opencastle 0.31.6 → 0.32.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 (210) hide show
  1. package/LICENSE +93 -21
  2. package/README.md +9 -3
  3. package/bin/cli.mjs +15 -0
  4. package/dist/cli/agents.d.ts.map +1 -1
  5. package/dist/cli/agents.js +19 -5
  6. package/dist/cli/agents.js.map +1 -1
  7. package/dist/cli/artifacts-cli.d.ts +3 -0
  8. package/dist/cli/artifacts-cli.d.ts.map +1 -0
  9. package/dist/cli/artifacts-cli.js +36 -0
  10. package/dist/cli/artifacts-cli.js.map +1 -0
  11. package/dist/cli/baselines.d.ts.map +1 -1
  12. package/dist/cli/baselines.js +11 -0
  13. package/dist/cli/baselines.js.map +1 -1
  14. package/dist/cli/convoy/artifacts.d.ts +25 -0
  15. package/dist/cli/convoy/artifacts.d.ts.map +1 -0
  16. package/dist/cli/convoy/artifacts.js +129 -0
  17. package/dist/cli/convoy/artifacts.js.map +1 -0
  18. package/dist/cli/convoy/artifacts.test.d.ts +2 -0
  19. package/dist/cli/convoy/artifacts.test.d.ts.map +1 -0
  20. package/dist/cli/convoy/artifacts.test.js +169 -0
  21. package/dist/cli/convoy/artifacts.test.js.map +1 -0
  22. package/dist/cli/convoy/compaction.d.ts +23 -0
  23. package/dist/cli/convoy/compaction.d.ts.map +1 -0
  24. package/dist/cli/convoy/compaction.js +117 -0
  25. package/dist/cli/convoy/compaction.js.map +1 -0
  26. package/dist/cli/convoy/compaction.test.d.ts +2 -0
  27. package/dist/cli/convoy/compaction.test.d.ts.map +1 -0
  28. package/dist/cli/convoy/compaction.test.js +205 -0
  29. package/dist/cli/convoy/compaction.test.js.map +1 -0
  30. package/dist/cli/convoy/contracts.d.ts +22 -0
  31. package/dist/cli/convoy/contracts.d.ts.map +1 -0
  32. package/dist/cli/convoy/contracts.js +254 -0
  33. package/dist/cli/convoy/contracts.js.map +1 -0
  34. package/dist/cli/convoy/contracts.test.d.ts +2 -0
  35. package/dist/cli/convoy/contracts.test.d.ts.map +1 -0
  36. package/dist/cli/convoy/contracts.test.js +239 -0
  37. package/dist/cli/convoy/contracts.test.js.map +1 -0
  38. package/dist/cli/convoy/dag-analysis.d.ts +40 -0
  39. package/dist/cli/convoy/dag-analysis.d.ts.map +1 -0
  40. package/dist/cli/convoy/dag-analysis.js +282 -0
  41. package/dist/cli/convoy/dag-analysis.js.map +1 -0
  42. package/dist/cli/convoy/dag-analysis.test.d.ts +2 -0
  43. package/dist/cli/convoy/dag-analysis.test.d.ts.map +1 -0
  44. package/dist/cli/convoy/dag-analysis.test.js +289 -0
  45. package/dist/cli/convoy/dag-analysis.test.js.map +1 -0
  46. package/dist/cli/convoy/effort-scaling.d.ts +20 -0
  47. package/dist/cli/convoy/effort-scaling.d.ts.map +1 -0
  48. package/dist/cli/convoy/effort-scaling.js +82 -0
  49. package/dist/cli/convoy/effort-scaling.js.map +1 -0
  50. package/dist/cli/convoy/effort-scaling.test.d.ts +2 -0
  51. package/dist/cli/convoy/effort-scaling.test.d.ts.map +1 -0
  52. package/dist/cli/convoy/effort-scaling.test.js +120 -0
  53. package/dist/cli/convoy/effort-scaling.test.js.map +1 -0
  54. package/dist/cli/convoy/engine.d.ts.map +1 -1
  55. package/dist/cli/convoy/engine.js +298 -11
  56. package/dist/cli/convoy/engine.js.map +1 -1
  57. package/dist/cli/convoy/engine.test.js +155 -18
  58. package/dist/cli/convoy/engine.test.js.map +1 -1
  59. package/dist/cli/convoy/event-schemas.d.ts.map +1 -1
  60. package/dist/cli/convoy/event-schemas.js +55 -0
  61. package/dist/cli/convoy/event-schemas.js.map +1 -1
  62. package/dist/cli/convoy/isolation.d.ts +27 -0
  63. package/dist/cli/convoy/isolation.d.ts.map +1 -0
  64. package/dist/cli/convoy/isolation.js +120 -0
  65. package/dist/cli/convoy/isolation.js.map +1 -0
  66. package/dist/cli/convoy/isolation.test.d.ts +2 -0
  67. package/dist/cli/convoy/isolation.test.d.ts.map +1 -0
  68. package/dist/cli/convoy/isolation.test.js +105 -0
  69. package/dist/cli/convoy/isolation.test.js.map +1 -0
  70. package/dist/cli/convoy/review-stages.d.ts +9 -0
  71. package/dist/cli/convoy/review-stages.d.ts.map +1 -0
  72. package/dist/cli/convoy/review-stages.js +134 -0
  73. package/dist/cli/convoy/review-stages.js.map +1 -0
  74. package/dist/cli/convoy/review-stages.test.d.ts +2 -0
  75. package/dist/cli/convoy/review-stages.test.d.ts.map +1 -0
  76. package/dist/cli/convoy/review-stages.test.js +197 -0
  77. package/dist/cli/convoy/review-stages.test.js.map +1 -0
  78. package/dist/cli/convoy/skill-refinement.d.ts +39 -0
  79. package/dist/cli/convoy/skill-refinement.d.ts.map +1 -0
  80. package/dist/cli/convoy/skill-refinement.js +239 -0
  81. package/dist/cli/convoy/skill-refinement.js.map +1 -0
  82. package/dist/cli/convoy/skill-refinement.test.d.ts +2 -0
  83. package/dist/cli/convoy/skill-refinement.test.d.ts.map +1 -0
  84. package/dist/cli/convoy/skill-refinement.test.js +230 -0
  85. package/dist/cli/convoy/skill-refinement.test.js.map +1 -0
  86. package/dist/cli/convoy/spec-builder.d.ts +1 -0
  87. package/dist/cli/convoy/spec-builder.d.ts.map +1 -1
  88. package/dist/cli/convoy/spec-builder.js +11 -0
  89. package/dist/cli/convoy/spec-builder.js.map +1 -1
  90. package/dist/cli/convoy/spec-builder.test.js +54 -0
  91. package/dist/cli/convoy/spec-builder.test.js.map +1 -1
  92. package/dist/cli/convoy/store.d.ts +3 -2
  93. package/dist/cli/convoy/store.d.ts.map +1 -1
  94. package/dist/cli/convoy/store.js +20 -2
  95. package/dist/cli/convoy/store.js.map +1 -1
  96. package/dist/cli/convoy/store.test.js +15 -15
  97. package/dist/cli/convoy/store.test.js.map +1 -1
  98. package/dist/cli/convoy/tdd-gate.d.ts +15 -0
  99. package/dist/cli/convoy/tdd-gate.d.ts.map +1 -0
  100. package/dist/cli/convoy/tdd-gate.js +119 -0
  101. package/dist/cli/convoy/tdd-gate.js.map +1 -0
  102. package/dist/cli/convoy/tdd-gate.test.d.ts +2 -0
  103. package/dist/cli/convoy/tdd-gate.test.d.ts.map +1 -0
  104. package/dist/cli/convoy/tdd-gate.test.js +227 -0
  105. package/dist/cli/convoy/tdd-gate.test.js.map +1 -0
  106. package/dist/cli/convoy/types.d.ts +91 -0
  107. package/dist/cli/convoy/types.d.ts.map +1 -1
  108. package/dist/cli/convoy/types.js +8 -0
  109. package/dist/cli/convoy/types.js.map +1 -1
  110. package/dist/cli/dashboard.d.ts.map +1 -1
  111. package/dist/cli/dashboard.js +54 -0
  112. package/dist/cli/dashboard.js.map +1 -1
  113. package/dist/cli/insights.d.ts +3 -0
  114. package/dist/cli/insights.d.ts.map +1 -0
  115. package/dist/cli/insights.js +94 -0
  116. package/dist/cli/insights.js.map +1 -0
  117. package/dist/cli/lesson.d.ts.map +1 -1
  118. package/dist/cli/lesson.js +7 -0
  119. package/dist/cli/lesson.js.map +1 -1
  120. package/dist/cli/log.d.ts.map +1 -1
  121. package/dist/cli/log.js +7 -0
  122. package/dist/cli/log.js.map +1 -1
  123. package/dist/cli/package-config.d.ts +12 -0
  124. package/dist/cli/package-config.d.ts.map +1 -0
  125. package/dist/cli/package-config.js +37 -0
  126. package/dist/cli/package-config.js.map +1 -0
  127. package/dist/cli/package.d.ts +23 -0
  128. package/dist/cli/package.d.ts.map +1 -0
  129. package/dist/cli/package.js +285 -0
  130. package/dist/cli/package.js.map +1 -0
  131. package/dist/cli/package.test.d.ts +2 -0
  132. package/dist/cli/package.test.d.ts.map +1 -0
  133. package/dist/cli/package.test.js +236 -0
  134. package/dist/cli/package.test.js.map +1 -0
  135. package/dist/cli/pipeline.d.ts +6 -0
  136. package/dist/cli/pipeline.d.ts.map +1 -1
  137. package/dist/cli/pipeline.js +15 -2
  138. package/dist/cli/pipeline.js.map +1 -1
  139. package/dist/cli/run/schema.d.ts.map +1 -1
  140. package/dist/cli/run/schema.js +32 -0
  141. package/dist/cli/run/schema.js.map +1 -1
  142. package/dist/cli/run/schema.test.js +51 -0
  143. package/dist/cli/run/schema.test.js.map +1 -1
  144. package/dist/cli/run.d.ts.map +1 -1
  145. package/dist/cli/run.js +10 -1
  146. package/dist/cli/run.js.map +1 -1
  147. package/dist/cli/skills.d.ts +3 -0
  148. package/dist/cli/skills.d.ts.map +1 -0
  149. package/dist/cli/skills.js +107 -0
  150. package/dist/cli/skills.js.map +1 -0
  151. package/dist/cli/types.d.ts +4 -1
  152. package/dist/cli/types.d.ts.map +1 -1
  153. package/dist/cli/update.js +2 -2
  154. package/package.json +3 -2
  155. package/src/cli/agents.ts +20 -5
  156. package/src/cli/artifacts-cli.ts +41 -0
  157. package/src/cli/baselines.ts +12 -0
  158. package/src/cli/convoy/artifacts.test.ts +201 -0
  159. package/src/cli/convoy/artifacts.ts +186 -0
  160. package/src/cli/convoy/compaction.test.ts +245 -0
  161. package/src/cli/convoy/compaction.ts +164 -0
  162. package/src/cli/convoy/contracts.test.ts +279 -0
  163. package/src/cli/convoy/contracts.ts +280 -0
  164. package/src/cli/convoy/dag-analysis.test.ts +349 -0
  165. package/src/cli/convoy/dag-analysis.ts +371 -0
  166. package/src/cli/convoy/effort-scaling.test.ts +140 -0
  167. package/src/cli/convoy/effort-scaling.ts +90 -0
  168. package/src/cli/convoy/engine.test.ts +175 -18
  169. package/src/cli/convoy/engine.ts +315 -12
  170. package/src/cli/convoy/event-schemas.ts +55 -0
  171. package/src/cli/convoy/isolation.test.ts +137 -0
  172. package/src/cli/convoy/isolation.ts +165 -0
  173. package/src/cli/convoy/review-stages.test.ts +235 -0
  174. package/src/cli/convoy/review-stages.ts +166 -0
  175. package/src/cli/convoy/skill-refinement.test.ts +277 -0
  176. package/src/cli/convoy/skill-refinement.ts +306 -0
  177. package/src/cli/convoy/spec-builder.test.ts +61 -0
  178. package/src/cli/convoy/spec-builder.ts +9 -0
  179. package/src/cli/convoy/store.test.ts +15 -15
  180. package/src/cli/convoy/store.ts +26 -4
  181. package/src/cli/convoy/tdd-gate.test.ts +281 -0
  182. package/src/cli/convoy/tdd-gate.ts +154 -0
  183. package/src/cli/convoy/types.ts +51 -0
  184. package/src/cli/dashboard.ts +55 -0
  185. package/src/cli/insights.ts +99 -0
  186. package/src/cli/lesson.ts +8 -0
  187. package/src/cli/log.ts +8 -0
  188. package/src/cli/package-config.ts +48 -0
  189. package/src/cli/package.test.ts +276 -0
  190. package/src/cli/package.ts +329 -0
  191. package/src/cli/pipeline.ts +21 -2
  192. package/src/cli/run/schema.test.ts +58 -0
  193. package/src/cli/run/schema.ts +33 -0
  194. package/src/cli/run.ts +14 -1
  195. package/src/cli/skills.ts +121 -0
  196. package/src/cli/types.ts +4 -1
  197. package/src/cli/update.ts +2 -2
  198. package/src/dashboard/dist/_astro/{index.Je1YjU_y.css → index.BRDFmNzR.css} +1 -1
  199. package/src/dashboard/dist/index.html +163 -2
  200. package/src/dashboard/node_modules/.vite/deps/_metadata.json +6 -6
  201. package/src/dashboard/src/pages/index.astro +162 -1
  202. package/src/dashboard/src/styles/dashboard.css +85 -0
  203. package/src/orchestrator/agents/developer.agent.md +8 -0
  204. package/src/orchestrator/agents/ui-ux-expert.agent.md +7 -0
  205. package/src/orchestrator/prompts/assess-complexity.prompt.md +13 -0
  206. package/src/orchestrator/prompts/brainstorm.prompt.md +18 -0
  207. package/src/orchestrator/prompts/generate-convoy.prompt.md +61 -0
  208. package/src/orchestrator/skills/decomposition/SKILL.md +35 -0
  209. package/src/orchestrator/skills/frontend-design/SKILL.md +27 -1
  210. package/src/orchestrator/skills/project-consistency/SKILL.md +350 -0
@@ -1 +1 @@
1
- :root{--bg-primary: #0a0a0f;--bg-secondary: #111118;--bg-tertiary: #1a1a24;--bg-card: rgba(255, 255, 255, .03);--bg-card-hover: rgba(255, 255, 255, .06);--text-primary: #f0f0f5;--text-secondary: #8a8a9a;--text-tertiary: #7a7a8e;--text-accent: #a78bfa;--gradient-accent: linear-gradient(135deg, #a78bfa 0%, #6366f1 50%, #3b82f6 100%);--gradient-glow: radial-gradient(ellipse 800px 400px at 50% 0%, rgba(99, 102, 241, .12) 0%, transparent 70%);--border-color: rgba(255, 255, 255, .06);--border-accent: rgba(167, 139, 250, .3);--color-success: #22c55e;--color-partial: #f59e0b;--color-failed: #ef4444;--color-redirected: #64748b;--color-premium: #f59e0b;--color-standard: #a78bfa;--color-utility: #3b82f6;--color-economy: #64748b;--accent-blue: #3b82f6;--accent-purple: #a78bfa;--accent-indigo: #6366f1;--max-width: 1280px;--transition-fast: .15s cubic-bezier(.4, 0, .2, 1);--transition-base: .3s cubic-bezier(.4, 0, .2, 1)}*,*:before,*:after{box-sizing:border-box;margin:0;padding:0}html{font-size:16px;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}body{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Inter,Roboto,Helvetica,Arial,sans-serif;background-color:var(--bg-primary);color:var(--text-primary);line-height:1.6;overflow-x:hidden;min-height:100vh}.dash-header{position:sticky;top:0;z-index:50;background:#0a0a0fd9;backdrop-filter:blur(16px);-webkit-backdrop-filter:blur(16px);border-bottom:1px solid var(--border-color)}.dash-header__inner{max-width:var(--max-width);margin:0 auto;padding:0 24px;height:56px;display:flex;align-items:center;justify-content:space-between}.dash-header__brand{display:flex;align-items:center;gap:10px}.dash-header__icon{width:32px;height:32px;border-radius:8px;object-fit:contain}.dash-header__title{font-size:1rem;font-weight:600;color:var(--text-primary)}.dash-layout{display:flex;max-width:var(--max-width);margin:0 auto;position:relative}.dash-sidebar{position:sticky;top:56px;height:calc(100vh - 56px);width:180px;flex-shrink:0;padding:24px 0 24px 24px;overflow-y:auto;display:none}@media(min-width:1024px){.dash-sidebar{display:block}}.dash-sidebar__list{list-style:none;display:flex;flex-direction:column;gap:2px}.dash-sidebar__link{display:block;padding:8px 16px;font-size:.8125rem;font-weight:500;color:var(--text-tertiary);text-decoration:none;border-radius:8px;transition:color var(--transition-fast),background var(--transition-fast)}.dash-sidebar__link:hover{color:var(--text-secondary);background:#ffffff0a}.dash-sidebar__link--active{color:var(--text-accent);background:#a78bfa14;font-weight:600}.dash-main{flex:1;min-width:0;max-width:var(--max-width);margin:0 auto;padding:24px;display:flex;flex-direction:column;gap:20px;position:relative}.dash-main:before{content:"";position:fixed;top:0;left:50%;transform:translate(-50%);width:100%;height:600px;background:var(--gradient-glow);pointer-events:none;z-index:0}.dash-main>*{position:relative;z-index:1}[data-nav-section]{scroll-margin-top:72px}.kpi-row{display:grid;grid-template-columns:1fr;gap:12px}@media(min-width:480px){.kpi-row{grid-template-columns:repeat(2,1fr)}}@media(min-width:960px){.kpi-row{grid-template-columns:repeat(auto-fit,minmax(160px,1fr))}}.kpi-card{background:var(--bg-secondary);border:1px solid var(--border-color);border-radius:12px;padding:20px 24px;display:flex;flex-direction:column;gap:4px;transition:border-color var(--transition-fast)}.kpi-card:hover{border-color:#ffffff1a}.kpi-card__label{font-size:.75rem;font-weight:500;color:var(--text-tertiary);text-transform:uppercase;letter-spacing:.05em}.kpi-card__value{font-size:2rem;font-weight:700;color:var(--text-primary);line-height:1.2;letter-spacing:-.02em}.kpi-card__sub{font-size:.75rem;color:var(--text-secondary);display:flex;align-items:center;gap:4px}.kpi-trend{font-weight:600}.kpi-trend--up{color:var(--color-success)}.kpi-trend--down{color:var(--color-failed)}.kpi-trend--neutral{color:var(--text-tertiary)}.chart-card{background:var(--bg-secondary);border:1px solid var(--border-color);border-radius:12px;transition:border-color var(--transition-fast)}.chart-card:hover{border-color:#ffffff1a}.chart-card__header{padding:20px 24px 8px}.chart-card__title{font-size:.9375rem;font-weight:600;color:var(--text-primary)}.chart-card__desc{font-size:.75rem;color:var(--text-tertiary);margin-top:2px}.chart-card__body{padding:16px 24px 24px;min-height:120px}.chart-card__body--table{padding:0}.charts-row{display:grid;grid-template-columns:1fr;gap:20px}@media(min-width:768px){.charts-row{grid-template-columns:repeat(2,1fr)}}.bar-row{display:flex;align-items:center;gap:12px;padding:6px 0}.bar-row+.bar-row{border-top:1px solid rgba(255,255,255,.03)}.bar-label{font-size:.8125rem;color:var(--text-secondary);width:130px;flex-shrink:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.bar-track{flex:1;height:24px;background:var(--bg-tertiary);border-radius:6px;display:flex;overflow:hidden}.bar-segment{height:100%;transition:width .8s cubic-bezier(.4,0,.2,1);min-width:0}.bar--success{background:var(--color-success)}.bar--partial{background:var(--color-partial)}.bar--failed{background:var(--color-failed)}.bar--premium{background:var(--color-premium)}.bar--standard{background:var(--color-standard)}.bar--utility{background:var(--color-utility)}.bar--economy{background:var(--color-economy)}.bar--accent{background:var(--accent-blue)}.bar-value{font-size:.8125rem;font-weight:600;color:var(--text-primary);width:36px;text-align:right;flex-shrink:0;font-variant-numeric:tabular-nums}.donut-container{display:flex;align-items:center;justify-content:center;gap:32px;flex-wrap:wrap}.donut-wrap{position:relative;width:180px;height:180px;flex-shrink:0}.donut-svg{width:100%;height:100%}.donut-svg circle{transition:stroke-dasharray .8s cubic-bezier(.4,0,.2,1),stroke-dashoffset .8s cubic-bezier(.4,0,.2,1)}.donut-center{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);text-align:center}.donut-total{display:block;font-size:1.5rem;font-weight:700;color:var(--text-primary);line-height:1}.donut-total-label{display:block;font-size:.6875rem;color:var(--text-tertiary);text-transform:uppercase;letter-spacing:.08em;margin-top:2px}.donut-legend{display:flex;flex-direction:column;gap:10px}.legend-item{display:flex;align-items:center;gap:8px;font-size:.8125rem}.legend-dot{width:10px;height:10px;border-radius:3px;flex-shrink:0}.legend-name{color:var(--text-secondary);text-transform:capitalize}.legend-count{color:var(--text-tertiary);font-variant-numeric:tabular-nums;margin-left:auto}.timeline-svg{width:100%;height:auto;display:block}.timeline-svg text{font-family:inherit}.timeline-legend{display:flex;gap:16px;justify-content:center;margin-top:12px}.timeline-legend__item{display:flex;align-items:center;gap:6px;font-size:.75rem;color:var(--text-tertiary)}.timeline-legend__dot{width:8px;height:8px;border-radius:2px}.pipeline{display:flex;align-items:stretch;gap:0;overflow-x:auto;padding:8px 0}.pipeline-stage{flex:1;min-width:140px;display:flex;flex-direction:column;align-items:center;gap:8px;padding:16px 12px;position:relative}.pipeline-stage:not(:last-child):after{content:"";position:absolute;right:-1px;top:50%;transform:translateY(-50%);width:2px;height:40%;background:var(--border-color)}.pipeline-stage__icon{width:40px;height:40px;border-radius:10px;display:flex;align-items:center;justify-content:center;font-size:1rem}.pipeline-stage__icon--pending{background:#64748b26;color:#94a3b8;border:1px solid rgba(100,116,139,.2)}.pipeline-stage__icon--active{background:#3b82f626;color:#60a5fa;border:1px solid rgba(59,130,246,.3);animation:pulse-glow 2s ease-in-out infinite}.pipeline-stage__icon--review{background:#f59e0b26;color:#fbbf24;border:1px solid rgba(245,158,11,.3)}.pipeline-stage__icon--done{background:#22c55e26;color:#4ade80;border:1px solid rgba(34,197,94,.3)}@keyframes pulse-glow{0%,to{box-shadow:0 0 #3b82f633}50%{box-shadow:0 0 12px 4px #3b82f626}}.pipeline-stage__count{font-size:1.5rem;font-weight:700;color:var(--text-primary);line-height:1}.pipeline-stage__label{font-size:.75rem;color:var(--text-tertiary);text-transform:uppercase;letter-spacing:.04em;font-weight:500}.pipeline-arrow{display:flex;align-items:center;color:var(--text-tertiary);font-size:1.25rem;padding:0 4px;flex-shrink:0}.exec-log{display:flex;flex-direction:column}.exec-step{display:flex;gap:16px;padding:14px 0;position:relative}.exec-step+.exec-step{border-top:1px solid rgba(255,255,255,.03)}.exec-step__indicator{display:flex;flex-direction:column;align-items:center;flex-shrink:0;width:32px}.exec-step__dot{width:24px;height:24px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:.6875rem;font-weight:700;flex-shrink:0}.exec-step__dot--success{background:#22c55e26;color:var(--color-success);border:1.5px solid rgba(34,197,94,.3)}.exec-step__dot--partial{background:#f59e0b26;color:var(--color-partial);border:1.5px solid rgba(245,158,11,.3)}.exec-step__dot--failed{background:#ef444426;color:var(--color-failed);border:1.5px solid rgba(239,68,68,.3)}.exec-step__line{flex:1;width:1.5px;background:var(--border-color);margin-top:4px}.exec-step__content{flex:1;min-width:0}.exec-step__header{display:flex;align-items:center;gap:8px;flex-wrap:wrap}.exec-step__agent{font-size:.875rem;font-weight:600;color:var(--text-primary)}.exec-step__badge{display:inline-flex;align-items:center;padding:2px 8px;font-size:.6875rem;font-weight:600;border-radius:100px;text-transform:capitalize}.exec-step__badge--success{background:#22c55e1f;color:var(--color-success);border:1px solid rgba(34,197,94,.2)}.exec-step__badge--partial{background:#f59e0b1f;color:var(--color-partial);border:1px solid rgba(245,158,11,.2)}.exec-step__badge--failed{background:#ef44441f;color:var(--color-failed);border:1px solid rgba(239,68,68,.2)}.exec-step__task{font-size:.8125rem;color:var(--text-secondary);margin-top:4px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.exec-step__meta{display:flex;gap:16px;margin-top:6px;font-size:.6875rem;color:var(--text-tertiary)}.exec-step__meta-item{display:flex;align-items:center;gap:4px}.panel-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:12px}.panel-item{background:var(--bg-tertiary);border-radius:8px;padding:16px;display:flex;flex-direction:column;gap:8px;border:1px solid transparent;transition:border-color var(--transition-fast)}.panel-item:hover{border-color:var(--border-color)}.panel-item__header{display:flex;align-items:center;justify-content:space-between}.panel-item__key{font-size:.8125rem;font-weight:600;color:var(--text-primary);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.panel-item__verdict{font-size:.6875rem;font-weight:700;padding:2px 8px;border-radius:4px;text-transform:uppercase;letter-spacing:.04em}.panel-item__verdict--pass{background:#22c55e26;color:var(--color-success)}.panel-item__verdict--block{background:#ef444426;color:var(--color-failed)}.panel-item__votes{display:flex;gap:4px}.panel-item__vote{width:24px;height:24px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:.625rem;font-weight:700}.panel-item__vote--pass{background:#22c55e1f;color:var(--color-success);border:1px solid rgba(34,197,94,.2)}.panel-item__vote--block{background:#ef44441f;color:var(--color-failed);border:1px solid rgba(239,68,68,.2)}.panel-item__fixes{font-size:.6875rem;color:var(--text-tertiary)}.panel-item__meta{display:flex;flex-wrap:wrap;gap:8px;margin-top:8px;padding-top:8px;border-top:1px solid var(--border-color)}.panel-item__meta-item{font-size:.625rem;color:var(--text-tertiary);white-space:nowrap}.sessions-table{width:100%;border-collapse:collapse;font-size:.8125rem}.sessions-table thead{position:sticky;top:0}.sessions-table th{padding:12px 16px;font-size:.6875rem;font-weight:600;color:var(--text-tertiary);text-align:left;text-transform:uppercase;letter-spacing:.06em;background:var(--bg-tertiary);border-bottom:1px solid var(--border-color)}.sessions-table th:last-child,.sessions-table td:last-child{text-align:right}.sessions-table th:nth-child(5),.sessions-table td:nth-child(5){text-align:right}.sessions-table td{padding:10px 16px;color:var(--text-secondary);border-bottom:1px solid rgba(255,255,255,.03);white-space:nowrap}.sessions-table tr:hover td{background:#ffffff05}.sessions-table .td-agent{font-weight:500;color:var(--text-primary)}.sessions-table .td-task{max-width:260px;overflow:hidden;text-overflow:ellipsis}.outcome-badge{display:inline-flex;align-items:center;padding:3px 10px;font-size:.6875rem;font-weight:600;border-radius:100px;text-transform:capitalize}.outcome-badge--success{background:#22c55e1f;color:var(--color-success);border:1px solid rgba(34,197,94,.2)}.outcome-badge--partial{background:#f59e0b1f;color:var(--color-partial);border:1px solid rgba(245,158,11,.2)}.outcome-badge--failed{background:#ef44441f;color:var(--color-failed);border:1px solid rgba(239,68,68,.2)}.td-num{font-variant-numeric:tabular-nums;text-align:right}.td-issue{font-size:.75rem;color:var(--text-accent);font-weight:500;font-variant-numeric:tabular-nums}.loading-skeleton{display:flex;align-items:center;justify-content:center;min-height:200px;color:var(--text-tertiary);font-size:.8125rem}.loading-skeleton:after{content:"Loading data…";animation:fade-pulse 1.5s ease-in-out infinite}@keyframes fade-pulse{0%,to{opacity:.4}50%{opacity:1}}.empty-state{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:48px 24px;text-align:center;gap:12px}.empty-state__icon{font-size:2rem;opacity:.4}.empty-state__text{font-size:.875rem;color:var(--text-tertiary);max-width:320px}.empty-state--enhanced{padding:56px 32px;gap:16px;border:1px dashed rgba(167,139,250,.15);border-radius:12px;background:radial-gradient(ellipse 300px 200px at 50% 30%,rgba(99,102,241,.04) 0%,transparent 70%),var(--bg-tertiary);position:relative;overflow:hidden}.empty-state--enhanced:before{content:"";position:absolute;inset:0;background:repeating-linear-gradient(0deg,transparent,transparent 23px,rgba(255,255,255,.015) 23px,rgba(255,255,255,.015) 24px);pointer-events:none}.empty-state__icon-wrap{width:64px;height:64px;display:flex;align-items:center;justify-content:center;border-radius:16px;background:#a78bfa0f;border:1px solid rgba(167,139,250,.12);color:var(--text-accent);animation:empty-breathe 4s ease-in-out infinite}@keyframes empty-breathe{0%,to{box-shadow:0 0 #a78bfa14;transform:scale(1)}50%{box-shadow:0 0 20px 4px #a78bfa0f;transform:scale(1.03)}}.empty-state__title{font-size:.9375rem;font-weight:600;color:var(--text-secondary);letter-spacing:-.01em}.empty-state__desc{font-size:.8125rem;color:var(--text-tertiary);max-width:380px;line-height:1.55}.kpi-card__hint{color:var(--text-tertiary);font-style:italic;font-size:.6875rem}.kpi-row--empty .kpi-card{border-style:dashed;border-color:#ffffff0a}.kpi-row--empty .kpi-card__value{color:var(--text-tertiary);opacity:.5}.welcome-banner{position:relative;background:var(--bg-secondary);border:1px solid transparent;border-radius:16px;padding:48px 40px;overflow:hidden;z-index:1}.welcome-banner:before{content:"";position:absolute;inset:-1px;border-radius:16px;padding:1px;background:linear-gradient(135deg,#a78bfa4d,#6366f126,#3b82f61a 60%,#a78bfa33);-webkit-mask:linear-gradient(#fff 0 0) content-box,linear-gradient(#fff 0 0);mask:linear-gradient(#fff 0 0) content-box,linear-gradient(#fff 0 0);-webkit-mask-composite:xor;mask-composite:exclude;pointer-events:none;z-index:0}.welcome-banner__glow{position:absolute;top:-60px;left:50%;transform:translate(-50%);width:500px;height:300px;background:radial-gradient(ellipse at center,rgba(167,139,250,.08) 0%,rgba(99,102,241,.04) 40%,transparent 70%);pointer-events:none;z-index:0}.welcome-banner__content{position:relative;z-index:1;display:flex;flex-direction:column;align-items:center;text-align:center;gap:20px}.welcome-banner__icon{width:72px;height:72px;display:flex;align-items:center;justify-content:center;border-radius:20px;background:#a78bfa14;border:1px solid rgba(167,139,250,.15);color:var(--text-accent);animation:welcome-float 6s ease-in-out infinite}@keyframes welcome-float{0%,to{transform:translateY(0);box-shadow:0 8px 32px #a78bfa14}50%{transform:translateY(-6px);box-shadow:0 16px 48px #a78bfa1f}}.welcome-banner__title{font-size:1.375rem;font-weight:700;color:var(--text-primary);letter-spacing:-.02em;line-height:1.3}.welcome-banner__subtitle{font-size:.9375rem;color:var(--text-secondary);max-width:480px;line-height:1.6}.welcome-banner__steps{display:flex;gap:20px;margin-top:12px;flex-wrap:wrap;justify-content:center}.welcome-step{display:flex;align-items:flex-start;gap:12px;text-align:left;padding:16px 20px;background:#ffffff05;border:1px solid rgba(255,255,255,.05);border-radius:12px;min-width:200px;max-width:220px;transition:border-color var(--transition-fast),background var(--transition-fast)}.welcome-step:hover{border-color:#a78bfa26;background:#ffffff08}.welcome-step__num{width:28px;height:28px;border-radius:8px;display:flex;align-items:center;justify-content:center;font-size:.75rem;font-weight:700;color:var(--text-accent);background:#a78bfa1a;border:1px solid rgba(167,139,250,.2);flex-shrink:0}.welcome-step__text{display:flex;flex-direction:column;gap:3px}.welcome-step__text strong{font-size:.8125rem;font-weight:600;color:var(--text-primary)}.welcome-step__text span{font-size:.75rem;color:var(--text-tertiary);line-height:1.4}@media(max-width:640px){.welcome-banner{padding:32px 24px}.welcome-banner__steps{flex-direction:column;align-items:center}.welcome-step{max-width:100%;width:100%}}@keyframes slide-up{0%{opacity:0;transform:translateY(12px)}to{opacity:1;transform:translateY(0)}}.dash-main>*{animation:slide-up .5s ease-out backwards}.dash-main>*:nth-child(1){animation-delay:0ms}.dash-main>*:nth-child(2){animation-delay:60ms}.dash-main>*:nth-child(3){animation-delay:.12s}.dash-main>*:nth-child(4){animation-delay:.18s}.dash-main>*:nth-child(5){animation-delay:.24s}.dash-main>*:nth-child(6){animation-delay:.3s}.dash-main>*:nth-child(7){animation-delay:.36s}.dash-main>*:nth-child(8){animation-delay:.42s}.dash-main>*:nth-child(9){animation-delay:.48s}.dash-main>*:nth-child(10){animation-delay:.54s}.dash-main>*:nth-child(11){animation-delay:.6s}@media(max-width:640px){.bar-label{width:90px;font-size:.75rem}.donut-container{flex-direction:column;align-items:center}.donut-wrap{width:150px;height:150px}.pipeline{gap:0}.pipeline-stage{min-width:100px;padding:12px 8px}.panel-grid{grid-template-columns:1fr}.sessions-table th:nth-child(3),.sessions-table td:nth-child(3){display:none}}.filter-bar{display:flex;flex-wrap:wrap;gap:12px;align-items:flex-end;padding:16px 20px;background:var(--bg-secondary);border:1px solid var(--border-color);border-radius:12px}.filter-group{display:flex;flex-direction:column;gap:4px;min-width:0}.filter-label{font-size:.6875rem;font-weight:500;color:var(--text-tertiary);text-transform:uppercase;letter-spacing:.05em}.filter-input,.filter-select{height:34px;padding:0 10px;font-size:.8125rem;color:var(--text-primary);background:var(--bg-tertiary);border:1px solid var(--border-color);border-radius:8px;outline:none;transition:border-color var(--transition-fast);font-family:inherit}.filter-input:focus,.filter-select:focus{border-color:var(--border-accent)}.filter-input{width:140px;color-scheme:dark}.filter-select{min-width:140px;cursor:pointer;appearance:none;-webkit-appearance:none;background-image:url("data:image/svg+xml,%3Csvg width='10' height='6' viewBox='0 0 10 6' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%235a5a6e' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right 10px center;padding-right:28px}.filter-reset{height:34px;font-size:.75rem}.dash-btn{display:inline-flex;align-items:center;gap:6px;padding:6px 14px;font-size:.8125rem;font-weight:500;font-family:inherit;border:none;border-radius:8px;cursor:pointer;transition:background var(--transition-fast),color var(--transition-fast)}.dash-btn--ghost{color:var(--text-secondary);background:#ffffff0f}.dash-btn--ghost:hover{color:var(--text-primary);background:#ffffff1a}.dash-header__actions{display:flex;align-items:center;gap:8px}@media(max-width:480px){.dash-header__inner{padding:0 12px}.dash-main{padding:12px;gap:12px}.kpi-card,.chart-card__header{padding:14px 16px}.chart-card__body{padding:12px 16px 16px}.filter-bar{padding:12px;gap:8px}.filter-input,.filter-select{width:100%;min-width:unset}.filter-group{flex:1 1 calc(50% - 4px)}.filter-reset{width:100%}.dash-header__title{font-size:.875rem}.exec-step__meta{flex-direction:column;gap:2px}.sessions-table th:nth-child(5),.sessions-table td:nth-child(5),.sessions-table th:nth-child(6),.sessions-table td:nth-child(6),.sessions-table th:nth-child(7),.sessions-table td:nth-child(7),.sessions-table th:nth-child(8),.sessions-table td:nth-child(8){display:none}}@media(max-width:768px){.charts-row{grid-template-columns:1fr}.pipeline{flex-wrap:wrap;gap:8px}.pipeline-arrow{display:none}.pipeline-stage{flex:1 1 calc(50% - 4px);min-width:100px}.tier-chart .donut-container,.donut-container{flex-direction:column;align-items:center}.sessions-table{font-size:.75rem}.sessions-table th,.sessions-table td{padding:8px 6px}}.convoy-overview{display:flex;flex-wrap:wrap;gap:24px;margin-bottom:20px}.convoy-stat{display:flex;flex-direction:column;gap:4px}.convoy-stat__label{font-size:.75rem;color:var(--text-tertiary);text-transform:uppercase;letter-spacing:.05em}.convoy-stat__value{font-size:.95rem;color:var(--text-primary)}.convoy-stat__value--error{color:var(--color-failed)}.convoy-progress{display:flex;align-items:center;gap:12px;margin-bottom:20px}.convoy-progress__bar{flex:1;height:8px;background:var(--bg-tertiary);border-radius:4px;overflow:hidden}.convoy-progress__fill{height:100%;background:var(--gradient-accent);border-radius:4px;transition:width var(--transition-base)}.convoy-progress__label{font-size:.8rem;color:var(--text-secondary);white-space:nowrap}.convoy-tasks{margin-top:8px}.convoy-chain{display:flex;align-items:stretch;gap:0;overflow-x:auto;padding:1rem 0 1.5rem;scrollbar-width:thin;scrollbar-color:var(--border-color) transparent}.convoy-chain::-webkit-scrollbar{height:4px}.convoy-chain::-webkit-scrollbar-track{background:transparent}.convoy-chain::-webkit-scrollbar-thumb{background:var(--border-color);border-radius:2px}.convoy-chain__connector{display:flex;align-items:center;padding:0 .5rem;color:var(--text-tertiary);font-size:1.1rem;flex-shrink:0}.convoy-chain__node{display:flex;flex-direction:column;align-items:center;gap:6px;padding:12px 16px;background:var(--bg-tertiary);border:1px solid var(--border-color);border-radius:10px;min-width:140px;cursor:pointer;transition:background var(--transition-fast),border-color var(--transition-fast),transform var(--transition-fast),box-shadow var(--transition-fast);flex-shrink:0}.convoy-chain__node:hover{background:var(--bg-card-hover);transform:translateY(-2px);box-shadow:0 4px 12px #0000004d}.convoy-chain__node-name{font-size:.8rem;font-weight:600;color:var(--text-primary);text-align:center;word-break:break-word;max-width:120px}.convoy-chain__node-meta{font-size:.72rem;color:var(--text-tertiary);text-align:center}.convoy-chain__node--active{border-color:var(--accent-purple);box-shadow:0 0 0 1px var(--accent-purple),0 0 12px #a78bfa33;animation:convoy-pulse 2s ease-in-out infinite}.convoy-chain__node--done{border-color:#22c55e4d}.convoy-chain__node--failed{border-color:#ef44444d}.convoy-chain__node--pending{opacity:.6}@keyframes convoy-pulse{0%,to{box-shadow:0 0 0 1px var(--accent-purple),0 0 8px #a78bfa26}50%{box-shadow:0 0 0 1px var(--accent-purple),0 0 18px #a78bfa59}}@media(max-width:768px){.convoy-chain{flex-wrap:wrap;gap:8px}.convoy-chain__connector{display:none}.convoy-chain__node{flex:1 1 calc(50% - 4px);min-width:120px}}.convoy-selector{display:flex;align-items:center;gap:.5rem}.convoy-selector__label{font-size:.75rem;text-transform:uppercase;letter-spacing:.05em;color:var(--text-secondary)}.convoy-selector__select{appearance:none;background:var(--bg-tertiary);border:1px solid rgba(255,255,255,.08);border-radius:6px;color:var(--text-primary);font-size:.8125rem;padding:.375rem 2rem .375rem .75rem;cursor:pointer;max-width:320px;background-image:url("data:image/svg+xml,%3Csvg width='10' height='6' viewBox='0 0 10 6' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%238a8a9a' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right .75rem center;transition:border-color .15s}.convoy-selector__select:hover{border-color:#ffffff26}.convoy-selector__select:focus{outline:2px solid var(--accent-purple);outline-offset:2px}.overall-stats{margin-bottom:0;padding:1.25rem;background:var(--bg-secondary);border-radius:12px;border:1px solid rgba(255,255,255,.06)}.overall-stats__header{display:flex;align-items:center;gap:.5rem;margin-bottom:1rem}.overall-stats__title{font-size:1rem;font-weight:600;color:var(--text-primary);margin:0}.overall-stats__grid{display:grid;grid-template-columns:repeat(6,1fr);gap:.75rem}.overall-kpi{display:flex;flex-direction:column;gap:.25rem;padding:.75rem;background:var(--bg-tertiary);border-radius:8px;border:1px solid rgba(255,255,255,.04);transition:border-color .15s}.overall-kpi:hover{border-color:#ffffff1a}.overall-kpi__label{font-size:.6875rem;text-transform:uppercase;letter-spacing:.05em;color:var(--text-secondary);display:flex;align-items:center;gap:.25rem}.overall-kpi__value{font-size:1.375rem;font-weight:700;color:var(--text-primary);font-variant-numeric:tabular-nums}.convoy-detail-header{padding:1.25rem;background:var(--bg-secondary);border-radius:12px;border:1px solid rgba(255,255,255,.06)}.convoy-detail-header__top{display:flex;align-items:center;gap:.75rem;margin-bottom:.75rem}.convoy-detail-header__name{font-size:1.25rem;font-weight:700;color:var(--text-primary);margin:0}.convoy-detail-header__meta{display:flex;flex-wrap:wrap;gap:1rem}.convoy-meta__item{font-size:.8125rem;color:var(--text-secondary)}.status-badge{display:inline-flex;align-items:center;padding:.125rem .625rem;border-radius:999px;font-size:.6875rem;font-weight:600;text-transform:uppercase;letter-spacing:.05em}.status-badge--done{background:#22c55e26;color:var(--color-success)}.status-badge--running{background:#3b82f626;color:var(--accent-blue)}.status-badge--failed{background:#ef444426;color:var(--color-failed)}.status-badge--gate-failed,.status-badge--gate_failed{background:#f59e0b26;color:var(--color-partial)}.tooltip-trigger{position:relative;cursor:help;font-size:.75rem;opacity:.5;transition:opacity .15s}.tooltip-trigger:hover{opacity:1}.tooltip-trigger:hover:after{content:attr(data-tooltip);position:absolute;bottom:100%;left:50%;transform:translate(-50%);padding:.5rem .875rem;background:var(--bg-primary);border:1px solid rgba(255,255,255,.12);border-radius:6px;font-size:.8125rem;color:var(--text-primary);max-width:420px;min-width:180px;white-space:normal;text-align:left;line-height:1.5;word-break:break-word;z-index:100;pointer-events:none;box-shadow:0 4px 12px #0006}.tooltip-trigger:focus{opacity:1;outline:2px solid var(--accent-blue);outline-offset:2px;border-radius:2px}.tooltip-trigger:focus:after,.tooltip-trigger:focus-visible:after{content:attr(data-tooltip);position:absolute;bottom:100%;left:50%;transform:translate(-50%);padding:.5rem .875rem;background:var(--bg-primary);border:1px solid rgba(255,255,255,.12);border-radius:6px;font-size:.8125rem;color:var(--text-primary);max-width:420px;min-width:180px;white-space:normal;text-align:left;line-height:1.5;word-break:break-word;z-index:100;pointer-events:none;box-shadow:0 4px 12px #0006}.status-badge--pending{background:#64748b26;color:#94a3b8}.status-badge--assigned{background:#3b82f61a;color:#60a5fa}.status-badge--timed-out{background:#ef44441f;color:#f87171}.status-badge--review-blocked{background:#f59e0b1f;color:#fbbf24}.status-badge--skipped{background:#64748b1a;color:#64748b}.status-badge--hook-failed{background:#ef44441a;color:#f87171}.status-badge--disputed{background:#a78bfa26;color:var(--accent-purple)}.status-badge--wait-for-input{background:#f59e0b1a;color:var(--color-partial)}.task-summary-cards{display:flex;gap:12px;flex-wrap:wrap;margin-bottom:20px}.task-summary-card{flex:1 1 140px;display:flex;flex-direction:column;gap:8px;padding:14px 16px;background:var(--bg-card);border:1px solid var(--border-color);border-radius:10px;transition:border-color .15s}.task-summary-card:hover{border-color:#ffffff1f}.task-summary-card__label{font-size:.6875rem;font-weight:600;text-transform:uppercase;letter-spacing:.06em;color:var(--text-tertiary)}.task-summary-card__value{font-size:1.75rem;font-weight:700;line-height:1;color:var(--text-primary)}.task-summary-card--done{border-left:3px solid var(--color-success)}.task-summary-card--running{border-left:3px solid var(--accent-blue)}.task-summary-card--errors{border-left:3px solid var(--color-failed)}.task-summary-card--waiting{border-left:3px solid #94a3b8}.task-summary-card--input{border-left:3px solid var(--color-partial)}.task-table-wrap{overflow-x:auto}.task-table .td-num{text-align:right}.sortable-th{cursor:pointer;user-select:none}.sortable-th:hover{color:var(--text-secondary)}.sortable-th--active{color:var(--text-primary)}.sort-indicator{margin-left:4px;font-size:.5625rem;opacity:.5}.sortable-th--active .sort-indicator{opacity:1;color:var(--accent-blue)}.phase-breakdown{display:flex;flex-direction:column;gap:8px;margin-bottom:20px}.phase-breakdown__row{display:flex;align-items:center;gap:12px}.phase-breakdown__label{font-size:.75rem;font-weight:600;color:var(--text-tertiary);min-width:60px}.phase-breakdown__bar{flex:1;height:10px;background:#ffffff0a;border-radius:5px;overflow:hidden;display:flex}.phase-breakdown__seg{height:100%;transition:width .3s ease}.phase-breakdown__seg--done{background:var(--color-success)}.phase-breakdown__seg--running{background:var(--accent-blue)}.phase-breakdown__seg--waiting{background:#475569}.phase-breakdown__seg--failed{background:var(--color-failed)}.phase-breakdown__count{font-size:.6875rem;color:var(--text-tertiary);min-width:52px;text-align:right}@media(max-width:960px){.overall-stats__grid{grid-template-columns:repeat(3,1fr)}}@media(max-width:640px){.overall-stats__grid{grid-template-columns:repeat(2,1fr)}.convoy-detail-header__name{font-size:1rem}.convoy-selector__select{max-width:200px}}@media(max-width:480px){.overall-stats__grid{grid-template-columns:1fr}}.reliability-empty{font-size:.875rem;color:var(--text-tertiary);padding:12px 0;margin:0}.secret-leak-banner{display:flex;align-items:flex-start;gap:12px;padding:14px 16px;background:#f59e0b1a;border:1px solid rgba(245,158,11,.3);border-radius:8px;margin-top:16px}.secret-leak-banner__icon{font-size:1.25rem;flex-shrink:0;line-height:1.4}.secret-leak-banner__text{display:flex;flex-direction:column;gap:4px}.secret-leak-banner__text strong{font-size:.875rem;font-weight:600;color:var(--color-partial)}.secret-leak-banner__text span{font-size:.8125rem;color:var(--text-secondary)}.artifact-type-badge{display:inline-block;padding:2px 8px;border-radius:4px;font-size:.75rem;font-weight:600;color:#fff;text-transform:uppercase;letter-spacing:.03em}.timeline-filters{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:16px}.timeline-filter-chip{display:inline-flex;align-items:center;padding:6px 14px;border-radius:20px;border:1px solid var(--border);background:transparent;color:var(--text-secondary);font-size:.8125rem;font-weight:500;cursor:pointer;transition:all .15s ease}.timeline-filter-chip:hover{border-color:var(--accent);color:var(--text-primary)}.timeline-filter-chip--active{background:var(--accent);border-color:var(--accent);color:#fff}.event-timeline-row{padding:12px 16px;border-bottom:1px solid var(--border);cursor:pointer;transition:background .15s ease}.event-timeline-row:hover{background:#a78bfa0d}.event-timeline-row--expanded{background:#a78bfa14}.event-timeline-row__main{display:flex;align-items:center;gap:12px;flex-wrap:wrap}.event-timeline-ts{font-size:.8125rem;color:var(--text-secondary);min-width:140px;font-variant-numeric:tabular-nums}.event-type-badge{display:inline-block;padding:2px 8px;border-radius:4px;font-size:.6875rem;font-weight:600;color:#fff;text-transform:uppercase;letter-spacing:.03em}.event-timeline-context{font-size:.8125rem;color:var(--text-tertiary, #6b7280);font-family:var(--font-mono, "SF Mono", "Fira Code", monospace)}.event-timeline-detail{margin-top:8px;padding:12px;background:var(--bg-card, #111118);border-radius:6px;border:1px solid var(--border)}.event-timeline-json{font-size:.75rem;color:var(--text-secondary);white-space:pre-wrap;word-break:break-all;margin:0;font-family:var(--font-mono, "SF Mono", "Fira Code", monospace);max-height:300px;overflow-y:auto}@media(max-width:640px){.event-timeline-ts{min-width:auto;font-size:.75rem}.event-timeline-row__main{gap:8px}.timeline-filter-chip{padding:4px 10px;font-size:.75rem}}.dash-btn:focus-visible,.convoy-selector__select:focus-visible,.filter-select:focus-visible,.filter-input:focus-visible,.dash-sidebar__link:focus-visible,.timeline-filter-chip:focus-visible{outline:2px solid var(--accent-blue);outline-offset:2px}.convoy-status-explanation{font-size:.8125rem;color:var(--text-secondary);margin-top:.25rem;margin-bottom:.5rem;font-style:italic}.view-home,.view-convoy-detail{display:flex;flex-direction:column;gap:20px}[data-view-hidden]{display:none!important}.breadcrumbs{display:flex;align-items:center;gap:6px;font-size:.8125rem;color:var(--text-tertiary);flex-wrap:wrap;padding:0;margin-bottom:-8px}.breadcrumbs__link{color:var(--text-secondary);text-decoration:none;transition:color var(--transition-fast);border-bottom:1px solid transparent}.breadcrumbs__link:hover{color:var(--text-accent);border-bottom-color:#a78bfa66}.breadcrumbs__link:focus-visible{outline:2px solid var(--accent-blue);outline-offset:2px;border-radius:2px}.breadcrumbs__separator{color:var(--text-tertiary);opacity:.5;user-select:none;font-size:.75rem}.breadcrumbs__current{color:var(--text-accent);font-weight:500;max-width:320px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.convoy-list-section{background:var(--bg-secondary);border:1px solid var(--border-color);border-radius:12px;transition:border-color var(--transition-fast)}.convoy-list-section:hover{border-color:#ffffff1a}.convoy-list-section__header{padding:20px 24px 12px;border-bottom:1px solid var(--border-color)}.convoy-list-section__header h2,.convoy-list-section__header .convoy-list-section__title{font-size:.9375rem;font-weight:600;color:var(--text-primary);margin:0}.convoy-list-section__desc{font-size:.75rem;color:var(--text-tertiary);margin-top:2px}.convoy-list-filters{display:flex;flex-wrap:wrap;gap:10px;align-items:flex-end;padding:14px 24px;background:#ffffff03;border-bottom:1px solid var(--border-color)}.convoy-list-filters__group{display:flex;flex-direction:column;gap:4px}.convoy-list-filters__group label{font-size:.6875rem;font-weight:500;color:var(--text-tertiary);text-transform:uppercase;letter-spacing:.05em}.convoy-list-filters__input,.convoy-list-filters__select,.convoy-list-filters__date{height:34px;padding:0 10px;font-size:.8125rem;color:var(--text-primary);background:var(--bg-tertiary);border:1px solid var(--border-color);border-radius:8px;outline:none;font-family:inherit;transition:border-color var(--transition-fast);color-scheme:dark}.convoy-list-filters__input:focus,.convoy-list-filters__select:focus,.convoy-list-filters__date:focus{border-color:var(--border-accent)}.convoy-list-filters__input{width:180px}.convoy-list-filters__date{width:150px}.convoy-list-filters__select{min-width:140px;cursor:pointer;appearance:none;-webkit-appearance:none;background-image:url("data:image/svg+xml,%3Csvg width='10' height='6' viewBox='0 0 10 6' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%235a5a6e' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right 10px center;padding-right:28px}.convoy-list-filters__reset{height:34px;padding:0 14px;font-size:.75rem;font-weight:500;font-family:inherit;color:var(--text-secondary);background:#ffffff0f;border:none;border-radius:8px;cursor:pointer;transition:background var(--transition-fast),color var(--transition-fast);align-self:flex-end;white-space:nowrap}.convoy-list-filters__reset:hover{background:#ffffff1a;color:var(--text-primary)}.convoy-list-filters__reset:focus-visible{outline:2px solid var(--accent-blue);outline-offset:2px}.convoy-list-table{width:100%;border-collapse:collapse;font-size:.8125rem}.convoy-list-table thead{position:sticky;top:0}.convoy-list-table th{padding:10px 16px;font-size:.6875rem;font-weight:600;color:var(--text-tertiary);text-align:left;text-transform:uppercase;letter-spacing:.06em;background:var(--bg-tertiary);border-bottom:1px solid var(--border-color);white-space:nowrap}.convoy-list-table td{padding:10px 16px;color:var(--text-secondary);border-bottom:1px solid rgba(255,255,255,.03);white-space:nowrap}.convoy-list-table tr{cursor:pointer;transition:background var(--transition-fast)}.convoy-list-table tbody tr:hover td{background:#a78bfa0d;color:var(--text-primary)}.convoy-list-table tbody tr:hover td:first-child{color:var(--text-accent)}.convoy-list-table .td-convoy-name{font-weight:600;color:var(--text-primary);max-width:240px;overflow:hidden;text-overflow:ellipsis}.convoy-list-empty{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:10px;padding:48px 24px;text-align:center;color:var(--text-tertiary)}.convoy-list-empty__icon{font-size:2rem;opacity:.35}.convoy-list-empty__text{font-size:.875rem;color:var(--text-tertiary);max-width:300px;line-height:1.5}.convoy-detail-hero{display:flex;flex-direction:column;gap:12px;padding:24px;background:var(--bg-secondary);border:1px solid var(--border-color);border-radius:12px;position:relative}.convoy-detail-hero:before{content:"";position:absolute;top:0;left:0;right:0;height:2px;background:var(--gradient-accent);opacity:.6;pointer-events:none}.convoy-detail-hero__top{display:flex;align-items:center;gap:14px;flex-wrap:wrap}.convoy-detail-hero__title{font-size:1.5rem;font-weight:700;color:var(--text-primary);letter-spacing:-.02em;line-height:1.25;margin:0}.convoy-detail-hero__status{flex-shrink:0}.convoy-detail-hero__status .status-badge{padding:.25rem .875rem;font-size:.75rem;border-radius:8px}.convoy-detail-hero__meta{display:flex;flex-wrap:wrap;gap:20px;padding-top:4px;border-top:1px solid var(--border-color)}.convoy-detail-hero__meta-item{display:flex;flex-direction:column;gap:2px}.convoy-detail-hero__meta-label{font-size:.6875rem;font-weight:500;color:var(--text-tertiary);text-transform:uppercase;letter-spacing:.05em}.convoy-detail-hero__meta-value{font-size:.875rem;color:var(--text-secondary);font-variant-numeric:tabular-nums}.task-row--clickable{cursor:pointer;transition:background var(--transition-fast)}.task-row--clickable:hover td{background:#a78bfa0a}.task-row--clickable td:first-child{position:relative}.task-row--clickable td:first-child:before{content:"";position:absolute;left:0;top:0;bottom:0;width:2px;background:transparent;transition:background var(--transition-fast)}.task-row--clickable:hover td:first-child:before{background:var(--border-accent)}.task-detail-expand{background:var(--bg-tertiary);border-bottom:1px solid var(--border-color)}.task-detail-expand__inner{padding:16px 20px}.task-detail-expand__grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:12px 24px}.task-detail-expand__field{display:flex;flex-direction:column;gap:3px}.task-detail-expand__label{font-size:.6875rem;font-weight:600;text-transform:uppercase;letter-spacing:.05em;color:var(--text-tertiary)}.task-detail-expand__value{font-size:.8125rem;color:var(--text-secondary);word-break:break-word;font-variant-numeric:tabular-nums}.task-detail-expand__value code{font-family:SF Mono,Fira Code,Cascadia Code,monospace;font-size:.75rem;background:#ffffff0f;padding:1px 6px;border-radius:4px;color:var(--text-accent)}@media(max-width:768px){.convoy-list-filters{padding:12px 16px;gap:8px}.convoy-list-filters__input,.convoy-list-filters__select,.convoy-list-filters__date{width:100%;min-width:unset}.convoy-list-filters__group{flex:1 1 calc(50% - 4px)}.convoy-list-filters__reset{flex:1 1 100%;width:100%}.convoy-list-section__header{padding:16px 16px 12px}}@media(max-width:480px){.convoy-list-filters__group{flex:1 1 100%}.convoy-detail-hero__title{font-size:1.25rem}.convoy-detail-hero{padding:16px}.task-detail-expand__grid{grid-template-columns:1fr}.breadcrumbs__current{max-width:180px}}
1
+ :root{--bg-primary: #0a0a0f;--bg-secondary: #111118;--bg-tertiary: #1a1a24;--bg-card: rgba(255, 255, 255, .03);--bg-card-hover: rgba(255, 255, 255, .06);--text-primary: #f0f0f5;--text-secondary: #8a8a9a;--text-tertiary: #7a7a8e;--text-accent: #a78bfa;--gradient-accent: linear-gradient(135deg, #a78bfa 0%, #6366f1 50%, #3b82f6 100%);--gradient-glow: radial-gradient(ellipse 800px 400px at 50% 0%, rgba(99, 102, 241, .12) 0%, transparent 70%);--border-color: rgba(255, 255, 255, .06);--border-accent: rgba(167, 139, 250, .3);--color-success: #22c55e;--color-partial: #f59e0b;--color-failed: #ef4444;--color-redirected: #64748b;--color-premium: #f59e0b;--color-standard: #a78bfa;--color-utility: #3b82f6;--color-economy: #64748b;--accent-blue: #3b82f6;--accent-purple: #a78bfa;--accent-indigo: #6366f1;--max-width: 1280px;--transition-fast: .15s cubic-bezier(.4, 0, .2, 1);--transition-base: .3s cubic-bezier(.4, 0, .2, 1)}*,*:before,*:after{box-sizing:border-box;margin:0;padding:0}html{font-size:16px;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}body{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Inter,Roboto,Helvetica,Arial,sans-serif;background-color:var(--bg-primary);color:var(--text-primary);line-height:1.6;overflow-x:hidden;min-height:100vh}.dash-header{position:sticky;top:0;z-index:50;background:#0a0a0fd9;backdrop-filter:blur(16px);-webkit-backdrop-filter:blur(16px);border-bottom:1px solid var(--border-color)}.dash-header__inner{max-width:var(--max-width);margin:0 auto;padding:0 24px;height:56px;display:flex;align-items:center;justify-content:space-between}.dash-header__brand{display:flex;align-items:center;gap:10px}.dash-header__icon{width:32px;height:32px;border-radius:8px;object-fit:contain}.dash-header__title{font-size:1rem;font-weight:600;color:var(--text-primary)}.dash-layout{display:flex;max-width:var(--max-width);margin:0 auto;position:relative}.dash-sidebar{position:sticky;top:56px;height:calc(100vh - 56px);width:180px;flex-shrink:0;padding:24px 0 24px 24px;overflow-y:auto;display:none}@media(min-width:1024px){.dash-sidebar{display:block}}.dash-sidebar__list{list-style:none;display:flex;flex-direction:column;gap:2px}.dash-sidebar__link{display:block;padding:8px 16px;font-size:.8125rem;font-weight:500;color:var(--text-tertiary);text-decoration:none;border-radius:8px;transition:color var(--transition-fast),background var(--transition-fast)}.dash-sidebar__link:hover{color:var(--text-secondary);background:#ffffff0a}.dash-sidebar__link--active{color:var(--text-accent);background:#a78bfa14;font-weight:600}.dash-main{flex:1;min-width:0;max-width:var(--max-width);margin:0 auto;padding:24px;display:flex;flex-direction:column;gap:20px;position:relative}.dash-main:before{content:"";position:fixed;top:0;left:50%;transform:translate(-50%);width:100%;height:600px;background:var(--gradient-glow);pointer-events:none;z-index:0}.dash-main>*{position:relative;z-index:1}[data-nav-section]{scroll-margin-top:72px}.kpi-row{display:grid;grid-template-columns:1fr;gap:12px}@media(min-width:480px){.kpi-row{grid-template-columns:repeat(2,1fr)}}@media(min-width:960px){.kpi-row{grid-template-columns:repeat(auto-fit,minmax(160px,1fr))}}.kpi-card{background:var(--bg-secondary);border:1px solid var(--border-color);border-radius:12px;padding:20px 24px;display:flex;flex-direction:column;gap:4px;transition:border-color var(--transition-fast)}.kpi-card:hover{border-color:#ffffff1a}.kpi-card__label{font-size:.75rem;font-weight:500;color:var(--text-tertiary);text-transform:uppercase;letter-spacing:.05em}.kpi-card__value{font-size:2rem;font-weight:700;color:var(--text-primary);line-height:1.2;letter-spacing:-.02em}.kpi-card__sub{font-size:.75rem;color:var(--text-secondary);display:flex;align-items:center;gap:4px}.kpi-trend{font-weight:600}.kpi-trend--up{color:var(--color-success)}.kpi-trend--down{color:var(--color-failed)}.kpi-trend--neutral{color:var(--text-tertiary)}.chart-card{background:var(--bg-secondary);border:1px solid var(--border-color);border-radius:12px;transition:border-color var(--transition-fast)}.chart-card:hover{border-color:#ffffff1a}.chart-card__header{padding:20px 24px 8px}.chart-card__title{font-size:.9375rem;font-weight:600;color:var(--text-primary)}.chart-card__desc{font-size:.75rem;color:var(--text-tertiary);margin-top:2px}.chart-card__body{padding:16px 24px 24px;min-height:120px}.chart-card__body--table{padding:0}.charts-row{display:grid;grid-template-columns:1fr;gap:20px}@media(min-width:768px){.charts-row{grid-template-columns:repeat(2,1fr)}}.bar-row{display:flex;align-items:center;gap:12px;padding:6px 0}.bar-row+.bar-row{border-top:1px solid rgba(255,255,255,.03)}.bar-label{font-size:.8125rem;color:var(--text-secondary);width:130px;flex-shrink:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.bar-track{flex:1;height:24px;background:var(--bg-tertiary);border-radius:6px;display:flex;overflow:hidden}.bar-segment{height:100%;transition:width .8s cubic-bezier(.4,0,.2,1);min-width:0}.bar--success{background:var(--color-success)}.bar--partial{background:var(--color-partial)}.bar--failed{background:var(--color-failed)}.bar--premium{background:var(--color-premium)}.bar--standard{background:var(--color-standard)}.bar--utility{background:var(--color-utility)}.bar--economy{background:var(--color-economy)}.bar--accent{background:var(--accent-blue)}.bar-value{font-size:.8125rem;font-weight:600;color:var(--text-primary);width:36px;text-align:right;flex-shrink:0;font-variant-numeric:tabular-nums}.donut-container{display:flex;align-items:center;justify-content:center;gap:32px;flex-wrap:wrap}.donut-wrap{position:relative;width:180px;height:180px;flex-shrink:0}.donut-svg{width:100%;height:100%}.donut-svg circle{transition:stroke-dasharray .8s cubic-bezier(.4,0,.2,1),stroke-dashoffset .8s cubic-bezier(.4,0,.2,1)}.donut-center{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);text-align:center}.donut-total{display:block;font-size:1.5rem;font-weight:700;color:var(--text-primary);line-height:1}.donut-total-label{display:block;font-size:.6875rem;color:var(--text-tertiary);text-transform:uppercase;letter-spacing:.08em;margin-top:2px}.donut-legend{display:flex;flex-direction:column;gap:10px}.legend-item{display:flex;align-items:center;gap:8px;font-size:.8125rem}.legend-dot{width:10px;height:10px;border-radius:3px;flex-shrink:0}.legend-name{color:var(--text-secondary);text-transform:capitalize}.legend-count{color:var(--text-tertiary);font-variant-numeric:tabular-nums;margin-left:auto}.timeline-svg{width:100%;height:auto;display:block}.timeline-svg text{font-family:inherit}.timeline-legend{display:flex;gap:16px;justify-content:center;margin-top:12px}.timeline-legend__item{display:flex;align-items:center;gap:6px;font-size:.75rem;color:var(--text-tertiary)}.timeline-legend__dot{width:8px;height:8px;border-radius:2px}.pipeline{display:flex;align-items:stretch;gap:0;overflow-x:auto;padding:8px 0}.pipeline-stage{flex:1;min-width:140px;display:flex;flex-direction:column;align-items:center;gap:8px;padding:16px 12px;position:relative}.pipeline-stage:not(:last-child):after{content:"";position:absolute;right:-1px;top:50%;transform:translateY(-50%);width:2px;height:40%;background:var(--border-color)}.pipeline-stage__icon{width:40px;height:40px;border-radius:10px;display:flex;align-items:center;justify-content:center;font-size:1rem}.pipeline-stage__icon--pending{background:#64748b26;color:#94a3b8;border:1px solid rgba(100,116,139,.2)}.pipeline-stage__icon--active{background:#3b82f626;color:#60a5fa;border:1px solid rgba(59,130,246,.3);animation:pulse-glow 2s ease-in-out infinite}.pipeline-stage__icon--review{background:#f59e0b26;color:#fbbf24;border:1px solid rgba(245,158,11,.3)}.pipeline-stage__icon--done{background:#22c55e26;color:#4ade80;border:1px solid rgba(34,197,94,.3)}@keyframes pulse-glow{0%,to{box-shadow:0 0 #3b82f633}50%{box-shadow:0 0 12px 4px #3b82f626}}.pipeline-stage__count{font-size:1.5rem;font-weight:700;color:var(--text-primary);line-height:1}.pipeline-stage__label{font-size:.75rem;color:var(--text-tertiary);text-transform:uppercase;letter-spacing:.04em;font-weight:500}.pipeline-arrow{display:flex;align-items:center;color:var(--text-tertiary);font-size:1.25rem;padding:0 4px;flex-shrink:0}.exec-log{display:flex;flex-direction:column}.exec-step{display:flex;gap:16px;padding:14px 0;position:relative}.exec-step+.exec-step{border-top:1px solid rgba(255,255,255,.03)}.exec-step__indicator{display:flex;flex-direction:column;align-items:center;flex-shrink:0;width:32px}.exec-step__dot{width:24px;height:24px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:.6875rem;font-weight:700;flex-shrink:0}.exec-step__dot--success{background:#22c55e26;color:var(--color-success);border:1.5px solid rgba(34,197,94,.3)}.exec-step__dot--partial{background:#f59e0b26;color:var(--color-partial);border:1.5px solid rgba(245,158,11,.3)}.exec-step__dot--failed{background:#ef444426;color:var(--color-failed);border:1.5px solid rgba(239,68,68,.3)}.exec-step__line{flex:1;width:1.5px;background:var(--border-color);margin-top:4px}.exec-step__content{flex:1;min-width:0}.exec-step__header{display:flex;align-items:center;gap:8px;flex-wrap:wrap}.exec-step__agent{font-size:.875rem;font-weight:600;color:var(--text-primary)}.exec-step__badge{display:inline-flex;align-items:center;padding:2px 8px;font-size:.6875rem;font-weight:600;border-radius:100px;text-transform:capitalize}.exec-step__badge--success{background:#22c55e1f;color:var(--color-success);border:1px solid rgba(34,197,94,.2)}.exec-step__badge--partial{background:#f59e0b1f;color:var(--color-partial);border:1px solid rgba(245,158,11,.2)}.exec-step__badge--failed{background:#ef44441f;color:var(--color-failed);border:1px solid rgba(239,68,68,.2)}.exec-step__task{font-size:.8125rem;color:var(--text-secondary);margin-top:4px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.exec-step__meta{display:flex;gap:16px;margin-top:6px;font-size:.6875rem;color:var(--text-tertiary)}.exec-step__meta-item{display:flex;align-items:center;gap:4px}.panel-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:12px}.panel-item{background:var(--bg-tertiary);border-radius:8px;padding:16px;display:flex;flex-direction:column;gap:8px;border:1px solid transparent;transition:border-color var(--transition-fast)}.panel-item:hover{border-color:var(--border-color)}.panel-item__header{display:flex;align-items:center;justify-content:space-between}.panel-item__key{font-size:.8125rem;font-weight:600;color:var(--text-primary);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.panel-item__verdict{font-size:.6875rem;font-weight:700;padding:2px 8px;border-radius:4px;text-transform:uppercase;letter-spacing:.04em}.panel-item__verdict--pass{background:#22c55e26;color:var(--color-success)}.panel-item__verdict--block{background:#ef444426;color:var(--color-failed)}.panel-item__votes{display:flex;gap:4px}.panel-item__vote{width:24px;height:24px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:.625rem;font-weight:700}.panel-item__vote--pass{background:#22c55e1f;color:var(--color-success);border:1px solid rgba(34,197,94,.2)}.panel-item__vote--block{background:#ef44441f;color:var(--color-failed);border:1px solid rgba(239,68,68,.2)}.panel-item__fixes{font-size:.6875rem;color:var(--text-tertiary)}.panel-item__meta{display:flex;flex-wrap:wrap;gap:8px;margin-top:8px;padding-top:8px;border-top:1px solid var(--border-color)}.panel-item__meta-item{font-size:.625rem;color:var(--text-tertiary);white-space:nowrap}.sessions-table{width:100%;border-collapse:collapse;font-size:.8125rem}.sessions-table thead{position:sticky;top:0}.sessions-table th{padding:12px 16px;font-size:.6875rem;font-weight:600;color:var(--text-tertiary);text-align:left;text-transform:uppercase;letter-spacing:.06em;background:var(--bg-tertiary);border-bottom:1px solid var(--border-color)}.sessions-table th:last-child,.sessions-table td:last-child{text-align:right}.sessions-table th:nth-child(5),.sessions-table td:nth-child(5){text-align:right}.sessions-table td{padding:10px 16px;color:var(--text-secondary);border-bottom:1px solid rgba(255,255,255,.03);white-space:nowrap}.sessions-table tr:hover td{background:#ffffff05}.sessions-table .td-agent{font-weight:500;color:var(--text-primary)}.sessions-table .td-task{max-width:260px;overflow:hidden;text-overflow:ellipsis}.outcome-badge{display:inline-flex;align-items:center;padding:3px 10px;font-size:.6875rem;font-weight:600;border-radius:100px;text-transform:capitalize}.outcome-badge--success{background:#22c55e1f;color:var(--color-success);border:1px solid rgba(34,197,94,.2)}.outcome-badge--partial{background:#f59e0b1f;color:var(--color-partial);border:1px solid rgba(245,158,11,.2)}.outcome-badge--failed{background:#ef44441f;color:var(--color-failed);border:1px solid rgba(239,68,68,.2)}.td-num{font-variant-numeric:tabular-nums;text-align:right}.td-issue{font-size:.75rem;color:var(--text-accent);font-weight:500;font-variant-numeric:tabular-nums}.loading-skeleton{display:flex;align-items:center;justify-content:center;min-height:200px;color:var(--text-tertiary);font-size:.8125rem}.loading-skeleton:after{content:"Loading data…";animation:fade-pulse 1.5s ease-in-out infinite}@keyframes fade-pulse{0%,to{opacity:.4}50%{opacity:1}}.empty-state{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:48px 24px;text-align:center;gap:12px}.empty-state__icon{font-size:2rem;opacity:.4}.empty-state__text{font-size:.875rem;color:var(--text-tertiary);max-width:320px}.empty-state--enhanced{padding:56px 32px;gap:16px;border:1px dashed rgba(167,139,250,.15);border-radius:12px;background:radial-gradient(ellipse 300px 200px at 50% 30%,rgba(99,102,241,.04) 0%,transparent 70%),var(--bg-tertiary);position:relative;overflow:hidden}.empty-state--enhanced:before{content:"";position:absolute;inset:0;background:repeating-linear-gradient(0deg,transparent,transparent 23px,rgba(255,255,255,.015) 23px,rgba(255,255,255,.015) 24px);pointer-events:none}.empty-state__icon-wrap{width:64px;height:64px;display:flex;align-items:center;justify-content:center;border-radius:16px;background:#a78bfa0f;border:1px solid rgba(167,139,250,.12);color:var(--text-accent);animation:empty-breathe 4s ease-in-out infinite}@keyframes empty-breathe{0%,to{box-shadow:0 0 #a78bfa14;transform:scale(1)}50%{box-shadow:0 0 20px 4px #a78bfa0f;transform:scale(1.03)}}.empty-state__title{font-size:.9375rem;font-weight:600;color:var(--text-secondary);letter-spacing:-.01em}.empty-state__desc{font-size:.8125rem;color:var(--text-tertiary);max-width:380px;line-height:1.55}.kpi-card__hint{color:var(--text-tertiary);font-style:italic;font-size:.6875rem}.kpi-row--empty .kpi-card{border-style:dashed;border-color:#ffffff0a}.kpi-row--empty .kpi-card__value{color:var(--text-tertiary);opacity:.5}.welcome-banner{position:relative;background:var(--bg-secondary);border:1px solid transparent;border-radius:16px;padding:48px 40px;overflow:hidden;z-index:1}.welcome-banner:before{content:"";position:absolute;inset:-1px;border-radius:16px;padding:1px;background:linear-gradient(135deg,#a78bfa4d,#6366f126,#3b82f61a 60%,#a78bfa33);-webkit-mask:linear-gradient(#fff 0 0) content-box,linear-gradient(#fff 0 0);mask:linear-gradient(#fff 0 0) content-box,linear-gradient(#fff 0 0);-webkit-mask-composite:xor;mask-composite:exclude;pointer-events:none;z-index:0}.welcome-banner__glow{position:absolute;top:-60px;left:50%;transform:translate(-50%);width:500px;height:300px;background:radial-gradient(ellipse at center,rgba(167,139,250,.08) 0%,rgba(99,102,241,.04) 40%,transparent 70%);pointer-events:none;z-index:0}.welcome-banner__content{position:relative;z-index:1;display:flex;flex-direction:column;align-items:center;text-align:center;gap:20px}.welcome-banner__icon{width:72px;height:72px;display:flex;align-items:center;justify-content:center;border-radius:20px;background:#a78bfa14;border:1px solid rgba(167,139,250,.15);color:var(--text-accent);animation:welcome-float 6s ease-in-out infinite}@keyframes welcome-float{0%,to{transform:translateY(0);box-shadow:0 8px 32px #a78bfa14}50%{transform:translateY(-6px);box-shadow:0 16px 48px #a78bfa1f}}.welcome-banner__title{font-size:1.375rem;font-weight:700;color:var(--text-primary);letter-spacing:-.02em;line-height:1.3}.welcome-banner__subtitle{font-size:.9375rem;color:var(--text-secondary);max-width:480px;line-height:1.6}.welcome-banner__steps{display:flex;gap:20px;margin-top:12px;flex-wrap:wrap;justify-content:center}.welcome-step{display:flex;align-items:flex-start;gap:12px;text-align:left;padding:16px 20px;background:#ffffff05;border:1px solid rgba(255,255,255,.05);border-radius:12px;min-width:200px;max-width:220px;transition:border-color var(--transition-fast),background var(--transition-fast)}.welcome-step:hover{border-color:#a78bfa26;background:#ffffff08}.welcome-step__num{width:28px;height:28px;border-radius:8px;display:flex;align-items:center;justify-content:center;font-size:.75rem;font-weight:700;color:var(--text-accent);background:#a78bfa1a;border:1px solid rgba(167,139,250,.2);flex-shrink:0}.welcome-step__text{display:flex;flex-direction:column;gap:3px}.welcome-step__text strong{font-size:.8125rem;font-weight:600;color:var(--text-primary)}.welcome-step__text span{font-size:.75rem;color:var(--text-tertiary);line-height:1.4}@media(max-width:640px){.welcome-banner{padding:32px 24px}.welcome-banner__steps{flex-direction:column;align-items:center}.welcome-step{max-width:100%;width:100%}}@keyframes slide-up{0%{opacity:0;transform:translateY(12px)}to{opacity:1;transform:translateY(0)}}.dash-main>*{animation:slide-up .5s ease-out backwards}.dash-main>*:nth-child(1){animation-delay:0ms}.dash-main>*:nth-child(2){animation-delay:60ms}.dash-main>*:nth-child(3){animation-delay:.12s}.dash-main>*:nth-child(4){animation-delay:.18s}.dash-main>*:nth-child(5){animation-delay:.24s}.dash-main>*:nth-child(6){animation-delay:.3s}.dash-main>*:nth-child(7){animation-delay:.36s}.dash-main>*:nth-child(8){animation-delay:.42s}.dash-main>*:nth-child(9){animation-delay:.48s}.dash-main>*:nth-child(10){animation-delay:.54s}.dash-main>*:nth-child(11){animation-delay:.6s}@media(max-width:640px){.bar-label{width:90px;font-size:.75rem}.donut-container{flex-direction:column;align-items:center}.donut-wrap{width:150px;height:150px}.pipeline{gap:0}.pipeline-stage{min-width:100px;padding:12px 8px}.panel-grid{grid-template-columns:1fr}.sessions-table th:nth-child(3),.sessions-table td:nth-child(3){display:none}}.filter-bar{display:flex;flex-wrap:wrap;gap:12px;align-items:flex-end;padding:16px 20px;background:var(--bg-secondary);border:1px solid var(--border-color);border-radius:12px}.filter-group{display:flex;flex-direction:column;gap:4px;min-width:0}.filter-label{font-size:.6875rem;font-weight:500;color:var(--text-tertiary);text-transform:uppercase;letter-spacing:.05em}.filter-input,.filter-select{height:34px;padding:0 10px;font-size:.8125rem;color:var(--text-primary);background:var(--bg-tertiary);border:1px solid var(--border-color);border-radius:8px;outline:none;transition:border-color var(--transition-fast);font-family:inherit}.filter-input:focus,.filter-select:focus{border-color:var(--border-accent)}.filter-input{width:140px;color-scheme:dark}.filter-select{min-width:140px;cursor:pointer;appearance:none;-webkit-appearance:none;background-image:url("data:image/svg+xml,%3Csvg width='10' height='6' viewBox='0 0 10 6' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%235a5a6e' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right 10px center;padding-right:28px}.filter-reset{height:34px;font-size:.75rem}.dash-btn{display:inline-flex;align-items:center;gap:6px;padding:6px 14px;font-size:.8125rem;font-weight:500;font-family:inherit;border:none;border-radius:8px;cursor:pointer;transition:background var(--transition-fast),color var(--transition-fast)}.dash-btn--ghost{color:var(--text-secondary);background:#ffffff0f}.dash-btn--ghost:hover{color:var(--text-primary);background:#ffffff1a}.dash-header__actions{display:flex;align-items:center;gap:8px}@media(max-width:480px){.dash-header__inner{padding:0 12px}.dash-main{padding:12px;gap:12px}.kpi-card,.chart-card__header{padding:14px 16px}.chart-card__body{padding:12px 16px 16px}.filter-bar{padding:12px;gap:8px}.filter-input,.filter-select{width:100%;min-width:unset}.filter-group{flex:1 1 calc(50% - 4px)}.filter-reset{width:100%}.dash-header__title{font-size:.875rem}.exec-step__meta{flex-direction:column;gap:2px}.sessions-table th:nth-child(5),.sessions-table td:nth-child(5),.sessions-table th:nth-child(6),.sessions-table td:nth-child(6),.sessions-table th:nth-child(7),.sessions-table td:nth-child(7),.sessions-table th:nth-child(8),.sessions-table td:nth-child(8){display:none}}@media(max-width:768px){.charts-row{grid-template-columns:1fr}.pipeline{flex-wrap:wrap;gap:8px}.pipeline-arrow{display:none}.pipeline-stage{flex:1 1 calc(50% - 4px);min-width:100px}.tier-chart .donut-container,.donut-container{flex-direction:column;align-items:center}.sessions-table{font-size:.75rem}.sessions-table th,.sessions-table td{padding:8px 6px}}.convoy-overview{display:flex;flex-wrap:wrap;gap:24px;margin-bottom:20px}.convoy-stat{display:flex;flex-direction:column;gap:4px}.convoy-stat__label{font-size:.75rem;color:var(--text-tertiary);text-transform:uppercase;letter-spacing:.05em}.convoy-stat__value{font-size:.95rem;color:var(--text-primary)}.convoy-stat__value--error{color:var(--color-failed)}.convoy-progress{display:flex;align-items:center;gap:12px;margin-bottom:20px}.convoy-progress__bar{flex:1;height:8px;background:var(--bg-tertiary);border-radius:4px;overflow:hidden}.convoy-progress__fill{height:100%;background:var(--gradient-accent);border-radius:4px;transition:width var(--transition-base)}.convoy-progress__label{font-size:.8rem;color:var(--text-secondary);white-space:nowrap}.convoy-tasks{margin-top:8px}.convoy-chain{display:flex;align-items:stretch;gap:0;overflow-x:auto;padding:1rem 0 1.5rem;scrollbar-width:thin;scrollbar-color:var(--border-color) transparent}.convoy-chain::-webkit-scrollbar{height:4px}.convoy-chain::-webkit-scrollbar-track{background:transparent}.convoy-chain::-webkit-scrollbar-thumb{background:var(--border-color);border-radius:2px}.convoy-chain__connector{display:flex;align-items:center;padding:0 .5rem;color:var(--text-tertiary);font-size:1.1rem;flex-shrink:0}.convoy-chain__node{display:flex;flex-direction:column;align-items:center;gap:6px;padding:12px 16px;background:var(--bg-tertiary);border:1px solid var(--border-color);border-radius:10px;min-width:140px;cursor:pointer;transition:background var(--transition-fast),border-color var(--transition-fast),transform var(--transition-fast),box-shadow var(--transition-fast);flex-shrink:0}.convoy-chain__node:hover{background:var(--bg-card-hover);transform:translateY(-2px);box-shadow:0 4px 12px #0000004d}.convoy-chain__node-name{font-size:.8rem;font-weight:600;color:var(--text-primary);text-align:center;word-break:break-word;max-width:120px}.convoy-chain__node-meta{font-size:.72rem;color:var(--text-tertiary);text-align:center}.convoy-chain__node--active{border-color:var(--accent-purple);box-shadow:0 0 0 1px var(--accent-purple),0 0 12px #a78bfa33;animation:convoy-pulse 2s ease-in-out infinite}.convoy-chain__node--done{border-color:#22c55e4d}.convoy-chain__node--failed{border-color:#ef44444d}.convoy-chain__node--pending{opacity:.6}@keyframes convoy-pulse{0%,to{box-shadow:0 0 0 1px var(--accent-purple),0 0 8px #a78bfa26}50%{box-shadow:0 0 0 1px var(--accent-purple),0 0 18px #a78bfa59}}@media(max-width:768px){.convoy-chain{flex-wrap:wrap;gap:8px}.convoy-chain__connector{display:none}.convoy-chain__node{flex:1 1 calc(50% - 4px);min-width:120px}}.convoy-selector{display:flex;align-items:center;gap:.5rem}.convoy-selector__label{font-size:.75rem;text-transform:uppercase;letter-spacing:.05em;color:var(--text-secondary)}.convoy-selector__select{appearance:none;background:var(--bg-tertiary);border:1px solid rgba(255,255,255,.08);border-radius:6px;color:var(--text-primary);font-size:.8125rem;padding:.375rem 2rem .375rem .75rem;cursor:pointer;max-width:320px;background-image:url("data:image/svg+xml,%3Csvg width='10' height='6' viewBox='0 0 10 6' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%238a8a9a' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right .75rem center;transition:border-color .15s}.convoy-selector__select:hover{border-color:#ffffff26}.convoy-selector__select:focus{outline:2px solid var(--accent-purple);outline-offset:2px}.overall-stats{margin-bottom:0;padding:1.25rem;background:var(--bg-secondary);border-radius:12px;border:1px solid rgba(255,255,255,.06)}.overall-stats__header{display:flex;align-items:center;gap:.5rem;margin-bottom:1rem}.overall-stats__title{font-size:1rem;font-weight:600;color:var(--text-primary);margin:0}.overall-stats__grid{display:grid;grid-template-columns:repeat(6,1fr);gap:.75rem}.overall-kpi{display:flex;flex-direction:column;gap:.25rem;padding:.75rem;background:var(--bg-tertiary);border-radius:8px;border:1px solid rgba(255,255,255,.04);transition:border-color .15s}.overall-kpi:hover{border-color:#ffffff1a}.overall-kpi__label{font-size:.6875rem;text-transform:uppercase;letter-spacing:.05em;color:var(--text-secondary);display:flex;align-items:center;gap:.25rem}.overall-kpi__value{font-size:1.375rem;font-weight:700;color:var(--text-primary);font-variant-numeric:tabular-nums}.convoy-detail-header{padding:1.25rem;background:var(--bg-secondary);border-radius:12px;border:1px solid rgba(255,255,255,.06)}.convoy-detail-header__top{display:flex;align-items:center;gap:.75rem;margin-bottom:.75rem}.convoy-detail-header__name{font-size:1.25rem;font-weight:700;color:var(--text-primary);margin:0}.convoy-detail-header__meta{display:flex;flex-wrap:wrap;gap:1rem}.convoy-meta__item{font-size:.8125rem;color:var(--text-secondary)}.status-badge{display:inline-flex;align-items:center;padding:.125rem .625rem;border-radius:999px;font-size:.6875rem;font-weight:600;text-transform:uppercase;letter-spacing:.05em}.status-badge--done{background:#22c55e26;color:var(--color-success)}.status-badge--running{background:#3b82f626;color:var(--accent-blue)}.status-badge--failed{background:#ef444426;color:var(--color-failed)}.status-badge--gate-failed,.status-badge--gate_failed{background:#f59e0b26;color:var(--color-partial)}.tooltip-trigger{position:relative;cursor:help;font-size:.75rem;opacity:.5;transition:opacity .15s}.tooltip-trigger:hover{opacity:1}.tooltip-trigger:hover:after{content:attr(data-tooltip);position:absolute;bottom:100%;left:50%;transform:translate(-50%);padding:.5rem .875rem;background:var(--bg-primary);border:1px solid rgba(255,255,255,.12);border-radius:6px;font-size:.8125rem;color:var(--text-primary);max-width:420px;min-width:180px;white-space:normal;text-align:left;line-height:1.5;word-break:break-word;z-index:100;pointer-events:none;box-shadow:0 4px 12px #0006}.tooltip-trigger:focus{opacity:1;outline:2px solid var(--accent-blue);outline-offset:2px;border-radius:2px}.tooltip-trigger:focus:after,.tooltip-trigger:focus-visible:after{content:attr(data-tooltip);position:absolute;bottom:100%;left:50%;transform:translate(-50%);padding:.5rem .875rem;background:var(--bg-primary);border:1px solid rgba(255,255,255,.12);border-radius:6px;font-size:.8125rem;color:var(--text-primary);max-width:420px;min-width:180px;white-space:normal;text-align:left;line-height:1.5;word-break:break-word;z-index:100;pointer-events:none;box-shadow:0 4px 12px #0006}.status-badge--pending{background:#64748b26;color:#94a3b8}.status-badge--assigned{background:#3b82f61a;color:#60a5fa}.status-badge--timed-out{background:#ef44441f;color:#f87171}.status-badge--review-blocked{background:#f59e0b1f;color:#fbbf24}.status-badge--skipped{background:#64748b1a;color:#64748b}.status-badge--hook-failed{background:#ef44441a;color:#f87171}.status-badge--disputed{background:#a78bfa26;color:var(--accent-purple)}.status-badge--wait-for-input{background:#f59e0b1a;color:var(--color-partial)}.task-summary-cards{display:flex;gap:12px;flex-wrap:wrap;margin-bottom:20px}.task-summary-card{flex:1 1 140px;display:flex;flex-direction:column;gap:8px;padding:14px 16px;background:var(--bg-card);border:1px solid var(--border-color);border-radius:10px;transition:border-color .15s}.task-summary-card:hover{border-color:#ffffff1f}.task-summary-card__label{font-size:.6875rem;font-weight:600;text-transform:uppercase;letter-spacing:.06em;color:var(--text-tertiary)}.task-summary-card__value{font-size:1.75rem;font-weight:700;line-height:1;color:var(--text-primary)}.task-summary-card--done{border-left:3px solid var(--color-success)}.task-summary-card--running{border-left:3px solid var(--accent-blue)}.task-summary-card--errors{border-left:3px solid var(--color-failed)}.task-summary-card--waiting{border-left:3px solid #94a3b8}.task-summary-card--input{border-left:3px solid var(--color-partial)}.task-table-wrap{overflow-x:auto}.task-table .td-num{text-align:right}.sortable-th{cursor:pointer;user-select:none}.sortable-th:hover{color:var(--text-secondary)}.sortable-th--active{color:var(--text-primary)}.sort-indicator{margin-left:4px;font-size:.5625rem;opacity:.5}.sortable-th--active .sort-indicator{opacity:1;color:var(--accent-blue)}.phase-breakdown{display:flex;flex-direction:column;gap:8px;margin-bottom:20px}.phase-breakdown__row{display:flex;align-items:center;gap:12px}.phase-breakdown__label{font-size:.75rem;font-weight:600;color:var(--text-tertiary);min-width:60px}.phase-breakdown__bar{flex:1;height:10px;background:#ffffff0a;border-radius:5px;overflow:hidden;display:flex}.phase-breakdown__seg{height:100%;transition:width .3s ease}.phase-breakdown__seg--done{background:var(--color-success)}.phase-breakdown__seg--running{background:var(--accent-blue)}.phase-breakdown__seg--waiting{background:#475569}.phase-breakdown__seg--failed{background:var(--color-failed)}.phase-breakdown__count{font-size:.6875rem;color:var(--text-tertiary);min-width:52px;text-align:right}@media(max-width:960px){.overall-stats__grid{grid-template-columns:repeat(3,1fr)}}@media(max-width:640px){.overall-stats__grid{grid-template-columns:repeat(2,1fr)}.convoy-detail-header__name{font-size:1rem}.convoy-selector__select{max-width:200px}}@media(max-width:480px){.overall-stats__grid{grid-template-columns:1fr}}.reliability-empty{font-size:.875rem;color:var(--text-tertiary);padding:12px 0;margin:0}.secret-leak-banner{display:flex;align-items:flex-start;gap:12px;padding:14px 16px;background:#f59e0b1a;border:1px solid rgba(245,158,11,.3);border-radius:8px;margin-top:16px}.secret-leak-banner__icon{font-size:1.25rem;flex-shrink:0;line-height:1.4}.secret-leak-banner__text{display:flex;flex-direction:column;gap:4px}.secret-leak-banner__text strong{font-size:.875rem;font-weight:600;color:var(--color-partial)}.secret-leak-banner__text span{font-size:.8125rem;color:var(--text-secondary)}.artifact-type-badge{display:inline-block;padding:2px 8px;border-radius:4px;font-size:.75rem;font-weight:600;color:#fff;text-transform:uppercase;letter-spacing:.03em}.timeline-filters{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:16px}.timeline-filter-chip{display:inline-flex;align-items:center;padding:6px 14px;border-radius:20px;border:1px solid var(--border);background:transparent;color:var(--text-secondary);font-size:.8125rem;font-weight:500;cursor:pointer;transition:all .15s ease}.timeline-filter-chip:hover{border-color:var(--accent);color:var(--text-primary)}.timeline-filter-chip--active{background:var(--accent);border-color:var(--accent);color:#fff}.event-timeline-row{padding:12px 16px;border-bottom:1px solid var(--border);cursor:pointer;transition:background .15s ease}.event-timeline-row:hover{background:#a78bfa0d}.event-timeline-row--expanded{background:#a78bfa14}.event-timeline-row__main{display:flex;align-items:center;gap:12px;flex-wrap:wrap}.event-timeline-ts{font-size:.8125rem;color:var(--text-secondary);min-width:140px;font-variant-numeric:tabular-nums}.event-type-badge{display:inline-block;padding:2px 8px;border-radius:4px;font-size:.6875rem;font-weight:600;color:#fff;text-transform:uppercase;letter-spacing:.03em}.event-timeline-context{font-size:.8125rem;color:var(--text-tertiary, #6b7280);font-family:var(--font-mono, "SF Mono", "Fira Code", monospace)}.event-timeline-detail{margin-top:8px;padding:12px;background:var(--bg-card, #111118);border-radius:6px;border:1px solid var(--border)}.event-timeline-json{font-size:.75rem;color:var(--text-secondary);white-space:pre-wrap;word-break:break-all;margin:0;font-family:var(--font-mono, "SF Mono", "Fira Code", monospace);max-height:300px;overflow-y:auto}@media(max-width:640px){.event-timeline-ts{min-width:auto;font-size:.75rem}.event-timeline-row__main{gap:8px}.timeline-filter-chip{padding:4px 10px;font-size:.75rem}}.dash-btn:focus-visible,.convoy-selector__select:focus-visible,.filter-select:focus-visible,.filter-input:focus-visible,.dash-sidebar__link:focus-visible,.timeline-filter-chip:focus-visible{outline:2px solid var(--accent-blue);outline-offset:2px}.convoy-status-explanation{font-size:.8125rem;color:var(--text-secondary);margin-top:.25rem;margin-bottom:.5rem;font-style:italic}.view-home,.view-convoy-detail{display:flex;flex-direction:column;gap:20px}[data-view-hidden]{display:none!important}.breadcrumbs{display:flex;align-items:center;gap:6px;font-size:.8125rem;color:var(--text-tertiary);flex-wrap:wrap;padding:0;margin-bottom:-8px}.breadcrumbs__link{color:var(--text-secondary);text-decoration:none;transition:color var(--transition-fast);border-bottom:1px solid transparent}.breadcrumbs__link:hover{color:var(--text-accent);border-bottom-color:#a78bfa66}.breadcrumbs__link:focus-visible{outline:2px solid var(--accent-blue);outline-offset:2px;border-radius:2px}.breadcrumbs__separator{color:var(--text-tertiary);opacity:.5;user-select:none;font-size:.75rem}.breadcrumbs__current{color:var(--text-accent);font-weight:500;max-width:320px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.convoy-list-section{background:var(--bg-secondary);border:1px solid var(--border-color);border-radius:12px;transition:border-color var(--transition-fast)}.convoy-list-section:hover{border-color:#ffffff1a}.convoy-list-section__header{padding:20px 24px 12px;border-bottom:1px solid var(--border-color)}.convoy-list-section__header h2,.convoy-list-section__header .convoy-list-section__title{font-size:.9375rem;font-weight:600;color:var(--text-primary);margin:0}.convoy-list-section__desc{font-size:.75rem;color:var(--text-tertiary);margin-top:2px}.convoy-list-filters{display:flex;flex-wrap:wrap;gap:10px;align-items:flex-end;padding:14px 24px;background:#ffffff03;border-bottom:1px solid var(--border-color)}.convoy-list-filters__group{display:flex;flex-direction:column;gap:4px}.convoy-list-filters__group label{font-size:.6875rem;font-weight:500;color:var(--text-tertiary);text-transform:uppercase;letter-spacing:.05em}.convoy-list-filters__input,.convoy-list-filters__select,.convoy-list-filters__date{height:34px;padding:0 10px;font-size:.8125rem;color:var(--text-primary);background:var(--bg-tertiary);border:1px solid var(--border-color);border-radius:8px;outline:none;font-family:inherit;transition:border-color var(--transition-fast);color-scheme:dark}.convoy-list-filters__input:focus,.convoy-list-filters__select:focus,.convoy-list-filters__date:focus{border-color:var(--border-accent)}.convoy-list-filters__input{width:180px}.convoy-list-filters__date{width:150px}.convoy-list-filters__select{min-width:140px;cursor:pointer;appearance:none;-webkit-appearance:none;background-image:url("data:image/svg+xml,%3Csvg width='10' height='6' viewBox='0 0 10 6' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%235a5a6e' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right 10px center;padding-right:28px}.convoy-list-filters__reset{height:34px;padding:0 14px;font-size:.75rem;font-weight:500;font-family:inherit;color:var(--text-secondary);background:#ffffff0f;border:none;border-radius:8px;cursor:pointer;transition:background var(--transition-fast),color var(--transition-fast);align-self:flex-end;white-space:nowrap}.convoy-list-filters__reset:hover{background:#ffffff1a;color:var(--text-primary)}.convoy-list-filters__reset:focus-visible{outline:2px solid var(--accent-blue);outline-offset:2px}.convoy-list-table{width:100%;border-collapse:collapse;font-size:.8125rem}.convoy-list-table thead{position:sticky;top:0}.convoy-list-table th{padding:10px 16px;font-size:.6875rem;font-weight:600;color:var(--text-tertiary);text-align:left;text-transform:uppercase;letter-spacing:.06em;background:var(--bg-tertiary);border-bottom:1px solid var(--border-color);white-space:nowrap}.convoy-list-table td{padding:10px 16px;color:var(--text-secondary);border-bottom:1px solid rgba(255,255,255,.03);white-space:nowrap}.convoy-list-table tr{cursor:pointer;transition:background var(--transition-fast)}.convoy-list-table tbody tr:hover td{background:#a78bfa0d;color:var(--text-primary)}.convoy-list-table tbody tr:hover td:first-child{color:var(--text-accent)}.convoy-list-table .td-convoy-name{font-weight:600;color:var(--text-primary);max-width:240px;overflow:hidden;text-overflow:ellipsis}.convoy-list-empty{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:10px;padding:48px 24px;text-align:center;color:var(--text-tertiary)}.convoy-list-empty__icon{font-size:2rem;opacity:.35}.convoy-list-empty__text{font-size:.875rem;color:var(--text-tertiary);max-width:300px;line-height:1.5}.convoy-detail-hero{display:flex;flex-direction:column;gap:12px;padding:24px;background:var(--bg-secondary);border:1px solid var(--border-color);border-radius:12px;position:relative}.convoy-detail-hero:before{content:"";position:absolute;top:0;left:0;right:0;height:2px;background:var(--gradient-accent);opacity:.6;pointer-events:none}.convoy-detail-hero__top{display:flex;align-items:center;gap:14px;flex-wrap:wrap}.convoy-detail-hero__title{font-size:1.5rem;font-weight:700;color:var(--text-primary);letter-spacing:-.02em;line-height:1.25;margin:0}.convoy-detail-hero__status{flex-shrink:0}.convoy-detail-hero__status .status-badge{padding:.25rem .875rem;font-size:.75rem;border-radius:8px}.convoy-detail-hero__meta{display:flex;flex-wrap:wrap;gap:20px;padding-top:4px;border-top:1px solid var(--border-color)}.convoy-detail-hero__meta-item{display:flex;flex-direction:column;gap:2px}.convoy-detail-hero__meta-label{font-size:.6875rem;font-weight:500;color:var(--text-tertiary);text-transform:uppercase;letter-spacing:.05em}.convoy-detail-hero__meta-value{font-size:.875rem;color:var(--text-secondary);font-variant-numeric:tabular-nums}.task-row--clickable{cursor:pointer;transition:background var(--transition-fast)}.task-row--clickable:hover td{background:#a78bfa0a}.task-row--clickable td:first-child{position:relative}.task-row--clickable td:first-child:before{content:"";position:absolute;left:0;top:0;bottom:0;width:2px;background:transparent;transition:background var(--transition-fast)}.task-row--clickable:hover td:first-child:before{background:var(--border-accent)}.task-detail-expand{background:var(--bg-tertiary);border-bottom:1px solid var(--border-color)}.task-detail-expand__inner{padding:16px 20px}.task-detail-expand__grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:12px 24px}.task-detail-expand__field{display:flex;flex-direction:column;gap:3px}.task-detail-expand__label{font-size:.6875rem;font-weight:600;text-transform:uppercase;letter-spacing:.05em;color:var(--text-tertiary)}.task-detail-expand__value{font-size:.8125rem;color:var(--text-secondary);word-break:break-word;font-variant-numeric:tabular-nums}.task-detail-expand__value code{font-family:SF Mono,Fira Code,Cascadia Code,monospace;font-size:.75rem;background:#ffffff0f;padding:1px 6px;border-radius:4px;color:var(--text-accent)}@media(max-width:768px){.convoy-list-filters{padding:12px 16px;gap:8px}.convoy-list-filters__input,.convoy-list-filters__select,.convoy-list-filters__date{width:100%;min-width:unset}.convoy-list-filters__group{flex:1 1 calc(50% - 4px)}.convoy-list-filters__reset{flex:1 1 100%;width:100%}.convoy-list-section__header{padding:16px 16px 12px}}@media(max-width:480px){.convoy-list-filters__group{flex:1 1 100%}.convoy-detail-hero__title{font-size:1.25rem}.convoy-detail-hero{padding:16px}.task-detail-expand__grid{grid-template-columns:1fr}.breadcrumbs__current{max-width:180px}}.waiting-banner{text-align:center;padding:3rem 2rem;margin-bottom:2rem;border-radius:var(--radius-lg, 12px);background:var(--bg-surface, #1e1e2e);border:1px solid var(--border-subtle, rgba(255,255,255,.06))}.waiting-banner__content{display:flex;flex-direction:column;align-items:center;gap:.75rem}.waiting-banner__spinner{width:32px;height:32px;border:3px solid var(--border-subtle, rgba(255,255,255,.1));border-top-color:var(--accent, #60a5fa);border-radius:50%;animation:spin 1s linear infinite}@keyframes spin{to{transform:rotate(360deg)}}.waiting-banner__title{font-size:1.25rem;font-weight:600;margin:0;color:var(--text-primary, #e2e8f0)}.waiting-banner__subtitle{font-size:.875rem;color:var(--text-muted, #94a3b8);margin:0}.pipeline-chain-nav{display:flex;align-items:center;gap:.5rem;padding:.5rem 0;margin-bottom:.5rem;flex-wrap:wrap}.pipeline-chain__label{font-size:.75rem;font-weight:600;text-transform:uppercase;letter-spacing:.05em;color:var(--text-muted, #94a3b8);margin-right:.25rem}.pipeline-chain__item{display:inline-flex;align-items:center;gap:.375rem;padding:.25rem .625rem;font-size:.8125rem;border-radius:var(--radius-sm, 6px);border:1px solid var(--border-subtle, rgba(255,255,255,.06));background:var(--bg-surface, #1e1e2e);color:var(--text-secondary, #cbd5e1);cursor:pointer;transition:border-color .15s,background .15s}.pipeline-chain__item:hover{border-color:var(--border-hover, rgba(255,255,255,.15));background:var(--bg-hover, rgba(255,255,255,.04))}.pipeline-chain__item--active{border-color:var(--accent, #60a5fa);background:#60a5fa14;color:var(--text-primary, #e2e8f0)}.pipeline-chain__dot{display:inline-block;width:8px;height:8px;border-radius:50%;flex-shrink:0}
@@ -1,4 +1,4 @@
1
- <!DOCTYPE html><html lang="en"> <head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Observability Dashboard — OpenCastle</title><meta name="description" content="Real-time observability for OpenCastle multi-agent orchestration — sessions, delegations, model tiers, and quality gates."><meta name="theme-color" content="#0a0a0f"><link rel="icon" type="image/png" sizes="192x192" href="/icon-192.png"><link rel="stylesheet" href="/_astro/index.Je1YjU_y.css"></head> <body> <script>(function(){const overallStats = {"convoyCounts":{"total":7,"running":1,"done":5,"failed":0,"gate_failed":0},"durationStats":{"avg_sec":2950.0000052154064,"p95_sec":3720.000019669533,"max_sec":5879.9999713897705},"tokenCostTotals":{"total_tokens":226750,"total_cost_usd":22.67},"topAgents":[{"agent":"Developer","task_count":6,"total_tokens":70100},{"agent":"Reviewer","task_count":5,"total_tokens":16250},{"agent":"UI/UX Expert","task_count":3,"total_tokens":32300},{"agent":"Testing Expert","task_count":3,"total_tokens":28800},{"agent":"DevOps Expert","task_count":3,"total_tokens":6400}],"topModels":[{"model":"claude-sonnet-4-6","task_count":21,"total_tokens":177650},{"model":"claude-haiku-3-5","task_count":5,"total_tokens":17700},{"model":"claude-opus-4-6","task_count":4,"total_tokens":40700}],"dlqSummary":{"count":3,"top_failure_types":[{"type":"timeout","count":1},{"type":"review_blocked","count":1},{"type":"gate_failed","count":1}]}};
1
+ <!DOCTYPE html><html lang="en"> <head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Observability Dashboard — OpenCastle</title><meta name="description" content="Real-time observability for OpenCastle multi-agent orchestration — sessions, delegations, model tiers, and quality gates."><meta name="theme-color" content="#0a0a0f"><link rel="icon" type="image/png" sizes="192x192" href="/icon-192.png"><link rel="stylesheet" href="/_astro/index.BRDFmNzR.css"></head> <body> <script>(function(){const overallStats = {"convoyCounts":{"total":7,"running":1,"done":5,"failed":0,"gate_failed":0},"durationStats":{"avg_sec":2950.0000052154064,"p95_sec":3720.000019669533,"max_sec":5879.9999713897705},"tokenCostTotals":{"total_tokens":226750,"total_cost_usd":22.67},"topAgents":[{"agent":"Developer","task_count":6,"total_tokens":70100},{"agent":"Reviewer","task_count":5,"total_tokens":16250},{"agent":"UI/UX Expert","task_count":3,"total_tokens":32300},{"agent":"Testing Expert","task_count":3,"total_tokens":28800},{"agent":"DevOps Expert","task_count":3,"total_tokens":6400}],"topModels":[{"model":"claude-sonnet-4-6","task_count":21,"total_tokens":177650},{"model":"claude-haiku-3-5","task_count":5,"total_tokens":17700},{"model":"claude-opus-4-6","task_count":4,"total_tokens":40700}],"dlqSummary":{"count":3,"top_failure_types":[{"type":"timeout","count":1},{"type":"review_blocked","count":1},{"type":"gate_failed","count":1}]}};
2
2
  const convoyList = [{"id":"demo-deploy-ci","name":"CI/CD Pipeline Setup","status":"running","created_at":"2026-03-11T08:00:00.000Z","finished_at":null,"total_tokens":null,"total_cost_usd":null},{"id":"demo-docs-update","name":"Documentation Refresh","status":"done","created_at":"2026-02-28T15:00:00.000Z","finished_at":"2026-02-28T15:22:00.000Z","total_tokens":14800,"total_cost_usd":1.48},{"id":"demo-data-pipeline","name":"Analytics ETL Pipeline","status":"done","created_at":"2026-02-22T13:00:00.000Z","finished_at":"2026-02-22T13:38:00.000Z","total_tokens":28900,"total_cost_usd":2.89},{"id":"demo-perf-opt","name":"Frontend Performance Boost","status":"done","created_at":"2026-02-17T10:00:00.000Z","finished_at":"2026-02-17T11:02:00.000Z","total_tokens":37200,"total_cost_usd":3.72},{"id":"demo-api-v2","name":"REST API v2 Migration","status":"gate_failed","created_at":"2026-02-12T16:00:00.000Z","finished_at":"2026-02-12T16:28:00.000Z","total_tokens":24600,"total_cost_usd":2.46},{"id":"demo-dashboard-ui","name":"Observability Dashboard UI","status":"done","created_at":"2026-02-07T14:00:00.000Z","finished_at":"2026-02-07T15:38:00.000Z","total_tokens":78400,"total_cost_usd":7.84},{"id":"demo-auth-revamp","name":"Auth System Revamp","status":"done","created_at":"2026-02-03T09:00:00.000Z","finished_at":"2026-02-03T09:47:00.000Z","total_tokens":42850,"total_cost_usd":4.28}];
3
3
 
4
4
  window.__DASHBOARD_DATA__ = { overallStats, convoyList }
@@ -83,6 +83,156 @@ Export
83
83
  return div.innerHTML;
84
84
  }
85
85
 
86
+ // ── Active Convoy Polling ──────────────────────────────────
87
+ let _activePollingTimer = null;
88
+ let _activePollingConvoyId = null;
89
+
90
+ function startActiveConvoyPolling() {
91
+ if (_activePollingTimer) return; // already polling
92
+ _activePollingTimer = setInterval(pollActiveConvoy, 3000);
93
+ // Also poll immediately
94
+ pollActiveConvoy();
95
+ }
96
+
97
+ function stopActiveConvoyPolling() {
98
+ if (_activePollingTimer) {
99
+ clearInterval(_activePollingTimer);
100
+ _activePollingTimer = null;
101
+ }
102
+ }
103
+
104
+ async function pollActiveConvoy() {
105
+ try {
106
+ const resp = await fetch(base + 'data/active-convoy.json');
107
+ if (!resp.ok) return;
108
+ const data = await resp.json();
109
+
110
+ if (!data.convoy) return; // no convoy yet — keep polling
111
+
112
+ const convoy = data.convoy;
113
+ const isRunningOrPending = convoy.status === 'running' || convoy.status === 'pending';
114
+
115
+ // If we haven't navigated to any convoy yet, navigate now
116
+ if (!_activePollingConvoyId) {
117
+ _activePollingConvoyId = convoy.id;
118
+ // Refresh ETL data so convoy detail JSON exists
119
+ await fetch(base + 'data/refresh');
120
+ // Re-fetch the convoy list and stats
121
+ await refreshDashboardData();
122
+ showConvoyDetailView(convoy.id, convoy.name || convoy.id);
123
+ removeWaitingBanner();
124
+ }
125
+
126
+ // If we're on a convoy and a new one started (pipeline chain), follow it
127
+ if (_activePollingConvoyId !== convoy.id && isRunningOrPending) {
128
+ _activePollingConvoyId = convoy.id;
129
+ await fetch(base + 'data/refresh');
130
+ await refreshDashboardData();
131
+ showConvoyDetailView(convoy.id, convoy.name || convoy.id);
132
+ }
133
+
134
+ // If we're viewing the active convoy, refresh its detail data
135
+ if (_activePollingConvoyId === convoy.id) {
136
+ await fetch(base + 'data/refresh');
137
+ await refreshDashboardData();
138
+ // Reload convoy detail to show latest task progress
139
+ await loadConvoyDetail(convoy.id);
140
+
141
+ // Update pipeline chain breadcrumb if applicable
142
+ if (data.pipeline && data.pipeline.length > 1) {
143
+ renderPipelineChain(data.pipeline, convoy.id);
144
+ }
145
+ }
146
+
147
+ // Stop polling when the convoy (and any pipeline) is finished
148
+ if (!isRunningOrPending) {
149
+ // In pipeline mode, check if all convoys in the chain are done
150
+ if (data.pipeline) {
151
+ const anyActive = data.pipeline.some(c => c.status === 'running' || c.status === 'pending');
152
+ if (!anyActive) {
153
+ stopActiveConvoyPolling();
154
+ }
155
+ } else {
156
+ stopActiveConvoyPolling();
157
+ }
158
+ }
159
+ } catch {
160
+ // Polling errors are non-fatal — just retry next interval
161
+ }
162
+ }
163
+
164
+ async function refreshDashboardData() {
165
+ try {
166
+ const [statsResp, listResp] = await Promise.all([
167
+ fetch(base + 'data/overall-stats.json'),
168
+ fetch(base + 'data/convoy-list.json'),
169
+ ]);
170
+ if (statsResp.ok) {
171
+ window.__DASHBOARD_DATA__.overallStats = await statsResp.json();
172
+ }
173
+ if (listResp.ok) {
174
+ window.__DASHBOARD_DATA__.convoyList = await listResp.json();
175
+ }
176
+ renderOverallStats();
177
+ renderConvoyList();
178
+ } catch {
179
+ // Non-fatal
180
+ }
181
+ }
182
+
183
+ function renderPipelineChain(pipelineConvoys, activeConvoyId) {
184
+ let chainEl = document.getElementById('pipeline-chain-nav');
185
+ if (!chainEl) {
186
+ chainEl = document.createElement('div');
187
+ chainEl.id = 'pipeline-chain-nav';
188
+ chainEl.className = 'pipeline-chain-nav';
189
+ const breadcrumbs = document.getElementById('breadcrumbs');
190
+ if (breadcrumbs) breadcrumbs.after(chainEl);
191
+ }
192
+
193
+ const statusDot = (status) => {
194
+ const colors = { done: '#4ade80', running: '#60a5fa', pending: '#94a3b8', failed: '#f87171', 'gate-failed': '#fb923c' };
195
+ return '<span class="pipeline-chain__dot" style="background:' + (colors[status] || '#94a3b8') + '"></span>';
196
+ };
197
+
198
+ let html = '<div class="pipeline-chain__label">Pipeline:</div>';
199
+ for (const c of pipelineConvoys) {
200
+ const isActive = c.id === activeConvoyId;
201
+ html += '<button class="pipeline-chain__item' + (isActive ? ' pipeline-chain__item--active' : '') + '" data-convoy-id="' + escapeHtml(c.id) + '">' +
202
+ statusDot(c.status) + escapeHtml(c.name || c.id) + '</button>';
203
+ }
204
+ chainEl.innerHTML = html;
205
+
206
+ chainEl.querySelectorAll('button[data-convoy-id]').forEach(btn => {
207
+ btn.addEventListener('click', () => {
208
+ const id = btn.dataset.convoyId;
209
+ const name = btn.textContent.trim();
210
+ _activePollingConvoyId = id;
211
+ showConvoyDetailView(id, name);
212
+ });
213
+ });
214
+ }
215
+
216
+ function showWaitingBanner() {
217
+ if (document.getElementById('waiting-banner')) return;
218
+ const banner = document.createElement('section');
219
+ banner.id = 'waiting-banner';
220
+ banner.className = 'waiting-banner';
221
+ banner.innerHTML =
222
+ '<div class="waiting-banner__content">' +
223
+ '<div class="waiting-banner__spinner"></div>' +
224
+ '<h2 class="waiting-banner__title">Waiting for convoy to start…</h2>' +
225
+ '<p class="waiting-banner__subtitle">The dashboard will automatically show convoy progress once it begins.</p>' +
226
+ '</div>';
227
+ const main = document.querySelector('.dash-main');
228
+ if (main) main.prepend(banner);
229
+ }
230
+
231
+ function removeWaitingBanner() {
232
+ const el = document.getElementById('waiting-banner');
233
+ if (el) el.remove();
234
+ }
235
+
86
236
  function formatTokens(n) {
87
237
  if (n >= 1000000) return (n / 1000000).toFixed(1) + 'M';
88
238
  if (n >= 1000) return (n / 1000).toFixed(1) + 'K';
@@ -1337,7 +1487,18 @@ Export
1337
1487
  const running = convoys.find((c) => c.status === 'running');
1338
1488
  const latest = convoys.slice().sort((a, b) => b.created_at.localeCompare(a.created_at))[0];
1339
1489
  const target = running || latest;
1340
- if (target) showConvoyDetailView(target.id, target.name || target.id);
1490
+ if (target) {
1491
+ _activePollingConvoyId = target.id;
1492
+ showConvoyDetailView(target.id, target.name || target.id);
1493
+ // If still running, start polling for live updates
1494
+ if (target.status === 'running' || target.status === 'pending') {
1495
+ startActiveConvoyPolling();
1496
+ }
1497
+ } else {
1498
+ // No convoy exists yet — show waiting state and poll
1499
+ showWaitingBanner();
1500
+ startActiveConvoyPolling();
1501
+ }
1341
1502
  } else if (convoyParam) {
1342
1503
  showConvoyDetailView(convoyParam, convoyParam);
1343
1504
  }
@@ -1,25 +1,25 @@
1
1
  {
2
- "hash": "c3f7a8b0",
2
+ "hash": "33ffdd90",
3
3
  "configHash": "30f8ea04",
4
- "lockfileHash": "b8604a8c",
5
- "browserHash": "9b0604a1",
4
+ "lockfileHash": "be559e81",
5
+ "browserHash": "1510bc18",
6
6
  "optimized": {
7
7
  "astro > cssesc": {
8
8
  "src": "../../../../../node_modules/cssesc/cssesc.js",
9
9
  "file": "astro___cssesc.js",
10
- "fileHash": "ff503ba2",
10
+ "fileHash": "3d8a744f",
11
11
  "needsInterop": true
12
12
  },
13
13
  "astro > aria-query": {
14
14
  "src": "../../../../../node_modules/aria-query/lib/index.js",
15
15
  "file": "astro___aria-query.js",
16
- "fileHash": "7c5354f6",
16
+ "fileHash": "f08a022d",
17
17
  "needsInterop": true
18
18
  },
19
19
  "astro > axobject-query": {
20
20
  "src": "../../../../../node_modules/axobject-query/lib/index.js",
21
21
  "file": "astro___axobject-query.js",
22
- "fileHash": "3cb889de",
22
+ "fileHash": "d3a3cea1",
23
23
  "needsInterop": true
24
24
  }
25
25
  },
@@ -401,6 +401,156 @@ try {
401
401
  return div.innerHTML;
402
402
  }
403
403
 
404
+ // ── Active Convoy Polling ──────────────────────────────────
405
+ let _activePollingTimer = null;
406
+ let _activePollingConvoyId = null;
407
+
408
+ function startActiveConvoyPolling() {
409
+ if (_activePollingTimer) return; // already polling
410
+ _activePollingTimer = setInterval(pollActiveConvoy, 3000);
411
+ // Also poll immediately
412
+ pollActiveConvoy();
413
+ }
414
+
415
+ function stopActiveConvoyPolling() {
416
+ if (_activePollingTimer) {
417
+ clearInterval(_activePollingTimer);
418
+ _activePollingTimer = null;
419
+ }
420
+ }
421
+
422
+ async function pollActiveConvoy() {
423
+ try {
424
+ const resp = await fetch(base + 'data/active-convoy.json');
425
+ if (!resp.ok) return;
426
+ const data = await resp.json();
427
+
428
+ if (!data.convoy) return; // no convoy yet — keep polling
429
+
430
+ const convoy = data.convoy;
431
+ const isRunningOrPending = convoy.status === 'running' || convoy.status === 'pending';
432
+
433
+ // If we haven't navigated to any convoy yet, navigate now
434
+ if (!_activePollingConvoyId) {
435
+ _activePollingConvoyId = convoy.id;
436
+ // Refresh ETL data so convoy detail JSON exists
437
+ await fetch(base + 'data/refresh');
438
+ // Re-fetch the convoy list and stats
439
+ await refreshDashboardData();
440
+ showConvoyDetailView(convoy.id, convoy.name || convoy.id);
441
+ removeWaitingBanner();
442
+ }
443
+
444
+ // If we're on a convoy and a new one started (pipeline chain), follow it
445
+ if (_activePollingConvoyId !== convoy.id && isRunningOrPending) {
446
+ _activePollingConvoyId = convoy.id;
447
+ await fetch(base + 'data/refresh');
448
+ await refreshDashboardData();
449
+ showConvoyDetailView(convoy.id, convoy.name || convoy.id);
450
+ }
451
+
452
+ // If we're viewing the active convoy, refresh its detail data
453
+ if (_activePollingConvoyId === convoy.id) {
454
+ await fetch(base + 'data/refresh');
455
+ await refreshDashboardData();
456
+ // Reload convoy detail to show latest task progress
457
+ await loadConvoyDetail(convoy.id);
458
+
459
+ // Update pipeline chain breadcrumb if applicable
460
+ if (data.pipeline && data.pipeline.length > 1) {
461
+ renderPipelineChain(data.pipeline, convoy.id);
462
+ }
463
+ }
464
+
465
+ // Stop polling when the convoy (and any pipeline) is finished
466
+ if (!isRunningOrPending) {
467
+ // In pipeline mode, check if all convoys in the chain are done
468
+ if (data.pipeline) {
469
+ const anyActive = data.pipeline.some(c => c.status === 'running' || c.status === 'pending');
470
+ if (!anyActive) {
471
+ stopActiveConvoyPolling();
472
+ }
473
+ } else {
474
+ stopActiveConvoyPolling();
475
+ }
476
+ }
477
+ } catch {
478
+ // Polling errors are non-fatal — just retry next interval
479
+ }
480
+ }
481
+
482
+ async function refreshDashboardData() {
483
+ try {
484
+ const [statsResp, listResp] = await Promise.all([
485
+ fetch(base + 'data/overall-stats.json'),
486
+ fetch(base + 'data/convoy-list.json'),
487
+ ]);
488
+ if (statsResp.ok) {
489
+ window.__DASHBOARD_DATA__.overallStats = await statsResp.json();
490
+ }
491
+ if (listResp.ok) {
492
+ window.__DASHBOARD_DATA__.convoyList = await listResp.json();
493
+ }
494
+ renderOverallStats();
495
+ renderConvoyList();
496
+ } catch {
497
+ // Non-fatal
498
+ }
499
+ }
500
+
501
+ function renderPipelineChain(pipelineConvoys, activeConvoyId) {
502
+ let chainEl = document.getElementById('pipeline-chain-nav');
503
+ if (!chainEl) {
504
+ chainEl = document.createElement('div');
505
+ chainEl.id = 'pipeline-chain-nav';
506
+ chainEl.className = 'pipeline-chain-nav';
507
+ const breadcrumbs = document.getElementById('breadcrumbs');
508
+ if (breadcrumbs) breadcrumbs.after(chainEl);
509
+ }
510
+
511
+ const statusDot = (status) => {
512
+ const colors = { done: '#4ade80', running: '#60a5fa', pending: '#94a3b8', failed: '#f87171', 'gate-failed': '#fb923c' };
513
+ return '<span class="pipeline-chain__dot" style="background:' + (colors[status] || '#94a3b8') + '"></span>';
514
+ };
515
+
516
+ let html = '<div class="pipeline-chain__label">Pipeline:</div>';
517
+ for (const c of pipelineConvoys) {
518
+ const isActive = c.id === activeConvoyId;
519
+ html += '<button class="pipeline-chain__item' + (isActive ? ' pipeline-chain__item--active' : '') + '" data-convoy-id="' + escapeHtml(c.id) + '">' +
520
+ statusDot(c.status) + escapeHtml(c.name || c.id) + '</button>';
521
+ }
522
+ chainEl.innerHTML = html;
523
+
524
+ chainEl.querySelectorAll('button[data-convoy-id]').forEach(btn => {
525
+ btn.addEventListener('click', () => {
526
+ const id = btn.dataset.convoyId;
527
+ const name = btn.textContent.trim();
528
+ _activePollingConvoyId = id;
529
+ showConvoyDetailView(id, name);
530
+ });
531
+ });
532
+ }
533
+
534
+ function showWaitingBanner() {
535
+ if (document.getElementById('waiting-banner')) return;
536
+ const banner = document.createElement('section');
537
+ banner.id = 'waiting-banner';
538
+ banner.className = 'waiting-banner';
539
+ banner.innerHTML =
540
+ '<div class="waiting-banner__content">' +
541
+ '<div class="waiting-banner__spinner"></div>' +
542
+ '<h2 class="waiting-banner__title">Waiting for convoy to start…</h2>' +
543
+ '<p class="waiting-banner__subtitle">The dashboard will automatically show convoy progress once it begins.</p>' +
544
+ '</div>';
545
+ const main = document.querySelector('.dash-main');
546
+ if (main) main.prepend(banner);
547
+ }
548
+
549
+ function removeWaitingBanner() {
550
+ const el = document.getElementById('waiting-banner');
551
+ if (el) el.remove();
552
+ }
553
+
404
554
  function formatTokens(n) {
405
555
  if (n >= 1000000) return (n / 1000000).toFixed(1) + 'M';
406
556
  if (n >= 1000) return (n / 1000).toFixed(1) + 'K';
@@ -1655,7 +1805,18 @@ try {
1655
1805
  const running = convoys.find((c) => c.status === 'running');
1656
1806
  const latest = convoys.slice().sort((a, b) => b.created_at.localeCompare(a.created_at))[0];
1657
1807
  const target = running || latest;
1658
- if (target) showConvoyDetailView(target.id, target.name || target.id);
1808
+ if (target) {
1809
+ _activePollingConvoyId = target.id;
1810
+ showConvoyDetailView(target.id, target.name || target.id);
1811
+ // If still running, start polling for live updates
1812
+ if (target.status === 'running' || target.status === 'pending') {
1813
+ startActiveConvoyPolling();
1814
+ }
1815
+ } else {
1816
+ // No convoy exists yet — show waiting state and poll
1817
+ showWaitingBanner();
1818
+ startActiveConvoyPolling();
1819
+ }
1659
1820
  } else if (convoyParam) {
1660
1821
  showConvoyDetailView(convoyParam, convoyParam);
1661
1822
  }