@ashlr/hub 3.11.2 → 3.11.3

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 (262) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/build-identity.json +2 -2
  3. package/dist/core/web/public/next/assets/{ActionMenu-_DhtX2gO.js → ActionMenu-FxXeRbPx.js} +2 -2
  4. package/dist/core/web/public/next/assets/{ActionMenu-_DhtX2gO.js.map → ActionMenu-FxXeRbPx.js.map} +1 -1
  5. package/dist/core/web/public/next/assets/{Advanced-CAAfaBke.js → Advanced-D_eS4472.js} +2 -2
  6. package/dist/core/web/public/next/assets/{Advanced-CAAfaBke.js.map → Advanced-D_eS4472.js.map} +1 -1
  7. package/dist/core/web/public/next/assets/{App-BAywyjE8.js → App-Cj4zKbG3.js} +2 -2
  8. package/dist/core/web/public/next/assets/{App-BAywyjE8.js.map → App-Cj4zKbG3.js.map} +1 -1
  9. package/dist/core/web/public/next/assets/{AppsSection-CUypKeog.js → AppsSection-Ddu_RCQE.js} +2 -2
  10. package/dist/core/web/public/next/assets/{AppsSection-CUypKeog.js.map → AppsSection-Ddu_RCQE.js.map} +1 -1
  11. package/dist/core/web/public/next/assets/{AreaTrend-CblDqC8Q.js → AreaTrend-CDxrQU4b.js} +2 -2
  12. package/dist/core/web/public/next/assets/{AreaTrend-CblDqC8Q.js.map → AreaTrend-CDxrQU4b.js.map} +1 -1
  13. package/dist/core/web/public/next/assets/AutonomySection-DuQkHGD_.js +2 -0
  14. package/dist/core/web/public/next/assets/{AutonomySection-D3d8lYO3.js.map → AutonomySection-DuQkHGD_.js.map} +1 -1
  15. package/dist/core/web/public/next/assets/{BranchBar-DU0jAV1E.js → BranchBar-CLsvOcyK.js} +2 -2
  16. package/dist/core/web/public/next/assets/{BranchBar-DU0jAV1E.js.map → BranchBar-CLsvOcyK.js.map} +1 -1
  17. package/dist/core/web/public/next/assets/{BudgetControl-Mm1ZL4u6.js → BudgetControl-TL3FeZ1D.js} +2 -2
  18. package/dist/core/web/public/next/assets/{BudgetControl-Mm1ZL4u6.js.map → BudgetControl-TL3FeZ1D.js.map} +1 -1
  19. package/dist/core/web/public/next/assets/{BurnDown-C1fgcFqo.js → BurnDown-sFXkUGdB.js} +2 -2
  20. package/dist/core/web/public/next/assets/{BurnDown-C1fgcFqo.js.map → BurnDown-sFXkUGdB.js.map} +1 -1
  21. package/dist/core/web/public/next/assets/{Button-DqgLUZvd.js → Button-HHXgoXGr.js} +2 -2
  22. package/dist/core/web/public/next/assets/{Button-DqgLUZvd.js.map → Button-HHXgoXGr.js.map} +1 -1
  23. package/dist/core/web/public/next/assets/{CapacityStrip-nWFHvqFB.js → CapacityStrip-qReu0RaF.js} +2 -2
  24. package/dist/core/web/public/next/assets/{CapacityStrip-nWFHvqFB.js.map → CapacityStrip-qReu0RaF.js.map} +1 -1
  25. package/dist/core/web/public/next/assets/{ChatSection-DUZNpiVr.js → ChatSection-DZuZfTaC.js} +3 -3
  26. package/dist/core/web/public/next/assets/{ChatSection-DUZNpiVr.js.map → ChatSection-DZuZfTaC.js.map} +1 -1
  27. package/dist/core/web/public/next/assets/{CloudBudgetForm-2OW38o_C.js → CloudBudgetForm-DJbiT1wi.js} +2 -2
  28. package/dist/core/web/public/next/assets/{CloudBudgetForm-2OW38o_C.js.map → CloudBudgetForm-DJbiT1wi.js.map} +1 -1
  29. package/dist/core/web/public/next/assets/{CommandPalette-C5w2o1-r.js → CommandPalette-zYLFZRnj.js} +2 -2
  30. package/dist/core/web/public/next/assets/{CommandPalette-C5w2o1-r.js.map → CommandPalette-zYLFZRnj.js.map} +1 -1
  31. package/dist/core/web/public/next/assets/{CommandSection-Bx2knNqY.js → CommandSection-rIeMK5Ch.js} +2 -2
  32. package/dist/core/web/public/next/assets/{CommandSection-Bx2knNqY.js.map → CommandSection-rIeMK5Ch.js.map} +1 -1
  33. package/dist/core/web/public/next/assets/{ConfirmDialog-B7ZwCQOX.js → ConfirmDialog-DLrLKM0c.js} +2 -2
  34. package/dist/core/web/public/next/assets/{ConfirmDialog-B7ZwCQOX.js.map → ConfirmDialog-DLrLKM0c.js.map} +1 -1
  35. package/dist/core/web/public/next/assets/{Dialog-BpgcEW6b.js → Dialog-BS9Dxi3G.js} +2 -2
  36. package/dist/core/web/public/next/assets/{Dialog-BpgcEW6b.js.map → Dialog-BS9Dxi3G.js.map} +1 -1
  37. package/dist/core/web/public/next/assets/{DiffPane-DpqRUtCx.js → DiffPane-TOmUf3b2.js} +2 -2
  38. package/dist/core/web/public/next/assets/{DiffPane-DpqRUtCx.js.map → DiffPane-TOmUf3b2.js.map} +1 -1
  39. package/dist/core/web/public/next/assets/{DiffViewer-CoV5-nUf.js → DiffViewer-BpH56302.js} +2 -2
  40. package/dist/core/web/public/next/assets/{DiffViewer-CoV5-nUf.js.map → DiffViewer-BpH56302.js.map} +1 -1
  41. package/dist/core/web/public/next/assets/{DockHost-C0Pq7Jak.js → DockHost-DzkzR-HD.js} +2 -2
  42. package/dist/core/web/public/next/assets/{DockHost-C0Pq7Jak.js.map → DockHost-DzkzR-HD.js.map} +1 -1
  43. package/dist/core/web/public/next/assets/{EmptyState-DYW29ncw.js → EmptyState-BqR5YAmf.js} +2 -2
  44. package/dist/core/web/public/next/assets/{EmptyState-DYW29ncw.js.map → EmptyState-BqR5YAmf.js.map} +1 -1
  45. package/dist/core/web/public/next/assets/{Epistemic-DVx6oHzp.js → Epistemic-dhvDTwAZ.js} +2 -2
  46. package/dist/core/web/public/next/assets/{Epistemic-DVx6oHzp.js.map → Epistemic-dhvDTwAZ.js.map} +1 -1
  47. package/dist/core/web/public/next/assets/{FleetSection-DSETviPK.js → FleetSection-ViAb549H.js} +3 -3
  48. package/dist/core/web/public/next/assets/{FleetSection-DSETviPK.js.map → FleetSection-ViAb549H.js.map} +1 -1
  49. package/dist/core/web/public/next/assets/{Funnel-DxiGqJrt.js → Funnel-D2u7Wlzc.js} +2 -2
  50. package/dist/core/web/public/next/assets/{Funnel-DxiGqJrt.js.map → Funnel-D2u7Wlzc.js.map} +1 -1
  51. package/dist/core/web/public/next/assets/{GearTray-C3I89sIt.js → GearTray-Cb2npoxM.js} +2 -2
  52. package/dist/core/web/public/next/assets/{GearTray-C3I89sIt.js.map → GearTray-Cb2npoxM.js.map} +1 -1
  53. package/dist/core/web/public/next/assets/{GrowthSection-C3m2bPEz.js → GrowthSection-C5aDPs8B.js} +2 -2
  54. package/dist/core/web/public/next/assets/{GrowthSection-C3m2bPEz.js.map → GrowthSection-C5aDPs8B.js.map} +1 -1
  55. package/dist/core/web/public/next/assets/{HandoffDialog-Bjb96a0N.js → HandoffDialog-BF3AYg-X.js} +2 -2
  56. package/dist/core/web/public/next/assets/{HandoffDialog-Bjb96a0N.js.map → HandoffDialog-BF3AYg-X.js.map} +1 -1
  57. package/dist/core/web/public/next/assets/{Input-ekTehVaH.js → Input-B5dmGLZx.js} +2 -2
  58. package/dist/core/web/public/next/assets/{Input-ekTehVaH.js.map → Input-B5dmGLZx.js.map} +1 -1
  59. package/dist/core/web/public/next/assets/{LeaderCard-85VBbbaZ.js → LeaderCard-DZrmjDbI.js} +2 -2
  60. package/dist/core/web/public/next/assets/{LeaderCard-85VBbbaZ.js.map → LeaderCard-DZrmjDbI.js.map} +1 -1
  61. package/dist/core/web/public/next/assets/{MatrixHeatmap-Bo8j0QPC.js → MatrixHeatmap-BgEUs2Eu.js} +2 -2
  62. package/dist/core/web/public/next/assets/{MatrixHeatmap-Bo8j0QPC.js.map → MatrixHeatmap-BgEUs2Eu.js.map} +1 -1
  63. package/dist/core/web/public/next/assets/McpSection-DZkiOuoq.js +2 -0
  64. package/dist/core/web/public/next/assets/{McpSection-DvHFaVyp.js.map → McpSection-DZkiOuoq.js.map} +1 -1
  65. package/dist/core/web/public/next/assets/{MessageMarkdown-fsY_ltVa.js → MessageMarkdown-BauY8ZTY.js} +3 -3
  66. package/dist/core/web/public/next/assets/{MessageMarkdown-fsY_ltVa.js.map → MessageMarkdown-BauY8ZTY.js.map} +1 -1
  67. package/dist/core/web/public/next/assets/{MessageMarkdownRenderer-DDdtu82l.js → MessageMarkdownRenderer-DLBNLfsn.js} +2 -2
  68. package/dist/core/web/public/next/assets/{MessageMarkdownRenderer-DDdtu82l.js.map → MessageMarkdownRenderer-DLBNLfsn.js.map} +1 -1
  69. package/dist/core/web/public/next/assets/{Meter-CeGDXdDM.js → Meter-DNeocJnD.js} +2 -2
  70. package/dist/core/web/public/next/assets/{Meter-CeGDXdDM.js.map → Meter-DNeocJnD.js.map} +1 -1
  71. package/dist/core/web/public/next/assets/{MindSection-CDVhHvXl.js → MindSection-BvJXFjyX.js} +2 -2
  72. package/dist/core/web/public/next/assets/{MindSection-CDVhHvXl.js.map → MindSection-BvJXFjyX.js.map} +1 -1
  73. package/dist/core/web/public/next/assets/{MutationTokenDialog-DTQzEOHR.js → MutationTokenDialog-mxrw0Yvy.js} +2 -2
  74. package/dist/core/web/public/next/assets/{MutationTokenDialog-DTQzEOHR.js.map → MutationTokenDialog-mxrw0Yvy.js.map} +1 -1
  75. package/dist/core/web/public/next/assets/{NeedsYouDrawer-6AuN0BF3.js → NeedsYouDrawer-CO-Balfp.js} +2 -2
  76. package/dist/core/web/public/next/assets/{NeedsYouDrawer-6AuN0BF3.js.map → NeedsYouDrawer-CO-Balfp.js.map} +1 -1
  77. package/dist/core/web/public/next/assets/{NeedsYouList-ChnRmbSk.js → NeedsYouList-CzDZbzRD.js} +2 -2
  78. package/dist/core/web/public/next/assets/{NeedsYouList-ChnRmbSk.js.map → NeedsYouList-CzDZbzRD.js.map} +1 -1
  79. package/dist/core/web/public/next/assets/{NewChatDialog-B06E7sqg.js → NewChatDialog-B8eJjlFf.js} +2 -2
  80. package/dist/core/web/public/next/assets/{NewChatDialog-B06E7sqg.js.map → NewChatDialog-B8eJjlFf.js.map} +1 -1
  81. package/dist/core/web/public/next/assets/{OnboardingFlow-C2M3zov9.js → OnboardingFlow-Cij6KWat.js} +2 -2
  82. package/dist/core/web/public/next/assets/{OnboardingFlow-C2M3zov9.js.map → OnboardingFlow-Cij6KWat.js.map} +1 -1
  83. package/dist/core/web/public/next/assets/{PreviewPane-Bd6HsX1k.js → PreviewPane-BS-CleCd.js} +2 -2
  84. package/dist/core/web/public/next/assets/{PreviewPane-Bd6HsX1k.js.map → PreviewPane-BS-CleCd.js.map} +1 -1
  85. package/dist/core/web/public/next/assets/{ProviderLogo-Bz7KR5j3.js → ProviderLogo-C5mBg8i0.js} +2 -2
  86. package/dist/core/web/public/next/assets/{ProviderLogo-Bz7KR5j3.js.map → ProviderLogo-C5mBg8i0.js.map} +1 -1
  87. package/dist/core/web/public/next/assets/{RailStatus-CctCuuLy.js → RailStatus-cPRyOmrk.js} +2 -2
  88. package/dist/core/web/public/next/assets/{RailStatus-CctCuuLy.js.map → RailStatus-cPRyOmrk.js.map} +1 -1
  89. package/dist/core/web/public/next/assets/{RefreshIndicator-CKY5BGdD.js → RefreshIndicator-CMwSCiz5.js} +2 -2
  90. package/dist/core/web/public/next/assets/{RefreshIndicator-CKY5BGdD.js.map → RefreshIndicator-CMwSCiz5.js.map} +1 -1
  91. package/dist/core/web/public/next/assets/{ResourcePoolConsoleApp-CspIsW_G.js → ResourcePoolConsoleApp-BFi1opsC.js} +2 -2
  92. package/dist/core/web/public/next/assets/{ResourcePoolConsoleApp-CspIsW_G.js.map → ResourcePoolConsoleApp-BFi1opsC.js.map} +1 -1
  93. package/dist/core/web/public/next/assets/{ResourcesChrome-B7fHZ6zX.js → ResourcesChrome-BJCauW_t.js} +3 -3
  94. package/dist/core/web/public/next/assets/{ResourcesChrome-B7fHZ6zX.js.map → ResourcesChrome-BJCauW_t.js.map} +1 -1
  95. package/dist/core/web/public/next/assets/{ResourcesDrawer-B7-N9n7-.js → ResourcesDrawer-BDecg6nO.js} +2 -2
  96. package/dist/core/web/public/next/assets/{ResourcesDrawer-B7-N9n7-.js.map → ResourcesDrawer-BDecg6nO.js.map} +1 -1
  97. package/dist/core/web/public/next/assets/{RouteErrorBoundary-C_B11J0s.js → RouteErrorBoundary-DYtwc2ja.js} +2 -2
  98. package/dist/core/web/public/next/assets/{RouteErrorBoundary-C_B11J0s.js.map → RouteErrorBoundary-DYtwc2ja.js.map} +1 -1
  99. package/dist/core/web/public/next/assets/{RunInCloudAction-_juw4EXd.js → RunInCloudAction-BEGEEM8O.js} +2 -2
  100. package/dist/core/web/public/next/assets/{RunInCloudAction-_juw4EXd.js.map → RunInCloudAction-BEGEEM8O.js.map} +1 -1
  101. package/dist/core/web/public/next/assets/{SeatSelector-D_YXvkPy.js → SeatSelector-CYHRR7Wp.js} +2 -2
  102. package/dist/core/web/public/next/assets/{SeatSelector-D_YXvkPy.js.map → SeatSelector-CYHRR7Wp.js.map} +1 -1
  103. package/dist/core/web/public/next/assets/{Segmented-DnKP6rr7.js → Segmented-BE53BenI.js} +2 -2
  104. package/dist/core/web/public/next/assets/{Segmented-DnKP6rr7.js.map → Segmented-BE53BenI.js.map} +1 -1
  105. package/dist/core/web/public/next/assets/{Select-DlbUupTX.js → Select-BwSGkHCS.js} +2 -2
  106. package/dist/core/web/public/next/assets/{Select-DlbUupTX.js.map → Select-BwSGkHCS.js.map} +1 -1
  107. package/dist/core/web/public/next/assets/{SessionGate-DnuTZACL.js → SessionGate-e0dFJm9d.js} +2 -2
  108. package/dist/core/web/public/next/assets/{SessionGate-DnuTZACL.js.map → SessionGate-e0dFJm9d.js.map} +1 -1
  109. package/dist/core/web/public/next/assets/{SessionInsightChip-C33-k-Q5.js → SessionInsightChip-CxlSyueJ.js} +2 -2
  110. package/dist/core/web/public/next/assets/{SessionInsightChip-C33-k-Q5.js.map → SessionInsightChip-CxlSyueJ.js.map} +1 -1
  111. package/dist/core/web/public/next/assets/{SessionSearch-DhhR9Csg.js → SessionSearch-_yp7S2TP.js} +2 -2
  112. package/dist/core/web/public/next/assets/{SessionSearch-DhhR9Csg.js.map → SessionSearch-_yp7S2TP.js.map} +1 -1
  113. package/dist/core/web/public/next/assets/{SettingsSection-C0xQvCz3.js → SettingsSection-wGnpWeGW.js} +2 -2
  114. package/dist/core/web/public/next/assets/{SettingsSection-C0xQvCz3.js.map → SettingsSection-wGnpWeGW.js.map} +1 -1
  115. package/dist/core/web/public/next/assets/{Sheet-BvNYOYv5.js → Sheet-DVP2Mgy6.js} +2 -2
  116. package/dist/core/web/public/next/assets/{Sheet-BvNYOYv5.js.map → Sheet-DVP2Mgy6.js.map} +1 -1
  117. package/dist/core/web/public/next/assets/{ShortcutsOverlay-1nUBVO-Z.js → ShortcutsOverlay-BcIcoClX.js} +2 -2
  118. package/dist/core/web/public/next/assets/{ShortcutsOverlay-1nUBVO-Z.js.map → ShortcutsOverlay-BcIcoClX.js.map} +1 -1
  119. package/dist/core/web/public/next/assets/{Sidebar-YrVvvBNM.js → Sidebar-DjQOqPbm.js} +3 -3
  120. package/dist/core/web/public/next/assets/{Sidebar-YrVvvBNM.js.map → Sidebar-DjQOqPbm.js.map} +1 -1
  121. package/dist/core/web/public/next/assets/{Slider-B2c-dbQb.js → Slider-BypUWjpH.js} +2 -2
  122. package/dist/core/web/public/next/assets/{Slider-B2c-dbQb.js.map → Slider-BypUWjpH.js.map} +1 -1
  123. package/dist/core/web/public/next/assets/{StatusBadge-Q9YYkijx.js → StatusBadge-HCZp416_.js} +2 -2
  124. package/dist/core/web/public/next/assets/{StatusBadge-Q9YYkijx.js.map → StatusBadge-HCZp416_.js.map} +1 -1
  125. package/dist/core/web/public/next/assets/{StepBand-Ci-C0GUG.js → StepBand-Duz1PUes.js} +2 -2
  126. package/dist/core/web/public/next/assets/{StepBand-Ci-C0GUG.js.map → StepBand-Duz1PUes.js.map} +1 -1
  127. package/dist/core/web/public/next/assets/{Surface-DBovMq4P.js → Surface-B75lVfzm.js} +2 -2
  128. package/dist/core/web/public/next/assets/{Surface-DBovMq4P.js.map → Surface-B75lVfzm.js.map} +1 -1
  129. package/dist/core/web/public/next/assets/{Swimlane-Cdc4TqDe.js → Swimlane-DGcIcnNA.js} +2 -2
  130. package/dist/core/web/public/next/assets/{Swimlane-Cdc4TqDe.js.map → Swimlane-DGcIcnNA.js.map} +1 -1
  131. package/dist/core/web/public/next/assets/{Switch-CUrvzO2k.js → Switch-iveI-8NY.js} +2 -2
  132. package/dist/core/web/public/next/assets/{Switch-CUrvzO2k.js.map → Switch-iveI-8NY.js.map} +1 -1
  133. package/dist/core/web/public/next/assets/{Tag-Bv8u6APt.js → Tag-DH15CUJp.js} +2 -2
  134. package/dist/core/web/public/next/assets/{Tag-Bv8u6APt.js.map → Tag-DH15CUJp.js.map} +1 -1
  135. package/dist/core/web/public/next/assets/{TerminalPane-BE4Xlqi5.js → TerminalPane-MQT-veKZ.js} +2 -2
  136. package/dist/core/web/public/next/assets/{TerminalPane-BE4Xlqi5.js.map → TerminalPane-MQT-veKZ.js.map} +1 -1
  137. package/dist/core/web/public/next/assets/{UniverseConsoleApp-BGwejf0m.js → UniverseConsoleApp-C8yQ0AaR.js} +2 -2
  138. package/dist/core/web/public/next/assets/{UniverseConsoleApp-BGwejf0m.js.map → UniverseConsoleApp-C8yQ0AaR.js.map} +1 -1
  139. package/dist/core/web/public/next/assets/{UniverseView-CgKa-WXC.js → UniverseView-_nPURPqe.js} +2 -2
  140. package/dist/core/web/public/next/assets/{UniverseView-CgKa-WXC.js.map → UniverseView-_nPURPqe.js.map} +1 -1
  141. package/dist/core/web/public/next/assets/{UsageSection-CazsHm1f.js → UsageSection-CqxRGJ40.js} +2 -2
  142. package/dist/core/web/public/next/assets/{UsageSection-CazsHm1f.js.map → UsageSection-CqxRGJ40.js.map} +1 -1
  143. package/dist/core/web/public/next/assets/{VerseConsoleApp-CTF3Shs0.js → VerseConsoleApp-DTjDpGCd.js} +3 -3
  144. package/dist/core/web/public/next/assets/{VerseConsoleApp-CTF3Shs0.js.map → VerseConsoleApp-DTjDpGCd.js.map} +1 -1
  145. package/dist/core/web/public/next/assets/{Workspace-CgdyXiEV.js → Workspace-DfcFGzME.js} +5 -5
  146. package/dist/core/web/public/next/assets/{Workspace-CgdyXiEV.js.map → Workspace-DfcFGzME.js.map} +1 -1
  147. package/dist/core/web/public/next/assets/{actions-MtxBGS5B.js → actions-tWevL9HV.js} +2 -2
  148. package/dist/core/web/public/next/assets/{actions-MtxBGS5B.js.map → actions-tWevL9HV.js.map} +1 -1
  149. package/dist/core/web/public/next/assets/{budget-queries-CP7hgR-p.js → budget-queries-V3wcJVK_.js} +2 -2
  150. package/dist/core/web/public/next/assets/{budget-queries-CP7hgR-p.js.map → budget-queries-V3wcJVK_.js.map} +1 -1
  151. package/dist/core/web/public/next/assets/{capacity-strip-model-fHfu5cph.js → capacity-strip-model-BDbmQ3e3.js} +2 -2
  152. package/dist/core/web/public/next/assets/{capacity-strip-model-fHfu5cph.js.map → capacity-strip-model-BDbmQ3e3.js.map} +1 -1
  153. package/dist/core/web/public/next/assets/{charts-Bis9WSiS.js → charts-CfAjuKMv.js} +2 -2
  154. package/dist/core/web/public/next/assets/{charts-Bis9WSiS.js.map → charts-CfAjuKMv.js.map} +1 -1
  155. package/dist/core/web/public/next/assets/{cloud-queries-BsOepFz6.js → cloud-queries-Br_r0UAz.js} +2 -2
  156. package/dist/core/web/public/next/assets/{cloud-queries-BsOepFz6.js.map → cloud-queries-Br_r0UAz.js.map} +1 -1
  157. package/dist/core/web/public/next/assets/{cloud.module-DoFnr8ZH.js → cloud.module-ascz58c3.js} +2 -2
  158. package/dist/core/web/public/next/assets/{cloud.module-DoFnr8ZH.js.map → cloud.module-ascz58c3.js.map} +1 -1
  159. package/dist/core/web/public/next/assets/{command-bus-CMvbYP5K.js → command-bus-xYZoK9nQ.js} +2 -2
  160. package/dist/core/web/public/next/assets/{command-bus-CMvbYP5K.js.map → command-bus-xYZoK9nQ.js.map} +1 -1
  161. package/dist/core/web/public/next/assets/{context-model-Ci3Ch9t5.js → context-model-BC-HOmPo.js} +2 -2
  162. package/dist/core/web/public/next/assets/{context-model-Ci3Ch9t5.js.map → context-model-BC-HOmPo.js.map} +1 -1
  163. package/dist/core/web/public/next/assets/{context-model-CjiJTnf1.js → context-model-CIBmSugV.js} +2 -2
  164. package/dist/core/web/public/next/assets/{context-model-CjiJTnf1.js.map → context-model-CIBmSugV.js.map} +1 -1
  165. package/dist/core/web/public/next/assets/{context-queries-BDXT6LQ3.js → context-queries-CrPcHWTz.js} +2 -2
  166. package/dist/core/web/public/next/assets/{context-queries-BDXT6LQ3.js.map → context-queries-CrPcHWTz.js.map} +1 -1
  167. package/dist/core/web/public/next/assets/{control-queries-Dv-h1Clu.js → control-queries-CmgBgKV7.js} +2 -2
  168. package/dist/core/web/public/next/assets/{control-queries-Dv-h1Clu.js.map → control-queries-CmgBgKV7.js.map} +1 -1
  169. package/dist/core/web/public/next/assets/{dock-icons-t--Eugrd.js → dock-icons-CUh8dOxJ.js} +2 -2
  170. package/dist/core/web/public/next/assets/{dock-icons-t--Eugrd.js.map → dock-icons-CUh8dOxJ.js.map} +1 -1
  171. package/dist/core/web/public/next/assets/{dock-store-qIu7kSQE.js → dock-store-B2vlxqPu.js} +2 -2
  172. package/dist/core/web/public/next/assets/{dock-store-qIu7kSQE.js.map → dock-store-B2vlxqPu.js.map} +1 -1
  173. package/dist/core/web/public/next/assets/{fleet-model-IRbwfhkR.js → fleet-model-7i-FbzKI.js} +2 -2
  174. package/dist/core/web/public/next/assets/{fleet-model-IRbwfhkR.js.map → fleet-model-7i-FbzKI.js.map} +1 -1
  175. package/dist/core/web/public/next/assets/{fleet-queries-7FVNByX1.js → fleet-queries-DzGoqq8X.js} +2 -2
  176. package/dist/core/web/public/next/assets/{fleet-queries-7FVNByX1.js.map → fleet-queries-DzGoqq8X.js.map} +1 -1
  177. package/dist/core/web/public/next/assets/{focus-trap-QqQxQdvH.js → focus-trap-HtcoXeEq.js} +2 -2
  178. package/dist/core/web/public/next/assets/{focus-trap-QqQxQdvH.js.map → focus-trap-HtcoXeEq.js.map} +1 -1
  179. package/dist/core/web/public/next/assets/{format-CaMmVQCn.js → format-BkWdOQDL.js} +2 -2
  180. package/dist/core/web/public/next/assets/{format-CaMmVQCn.js.map → format-BkWdOQDL.js.map} +1 -1
  181. package/dist/core/web/public/next/assets/{git-model-B4S_GUNA.js → git-model-bk_RXh3y.js} +2 -2
  182. package/dist/core/web/public/next/assets/{git-model-B4S_GUNA.js.map → git-model-bk_RXh3y.js.map} +1 -1
  183. package/dist/core/web/public/next/assets/{global-BkNl4e6E.js → global-oEl9Qj8u.js} +2 -2
  184. package/dist/core/web/public/next/assets/{global-BkNl4e6E.js.map → global-oEl9Qj8u.js.map} +1 -1
  185. package/dist/core/web/public/next/assets/{guarded-action-DHiL8tY5.js → guarded-action-OzqcPjmh.js} +3 -3
  186. package/dist/core/web/public/next/assets/{guarded-action-DHiL8tY5.js.map → guarded-action-OzqcPjmh.js.map} +1 -1
  187. package/dist/core/web/public/next/assets/{guarded-runners-DmGEkM2P.js → guarded-runners-LHLXmXIk.js} +2 -2
  188. package/dist/core/web/public/next/assets/{guarded-runners-DmGEkM2P.js.map → guarded-runners-LHLXmXIk.js.map} +1 -1
  189. package/dist/core/web/public/next/assets/{icon-base-NtFmP2yB.js → icon-base-DvM1eI5V.js} +2 -2
  190. package/dist/core/web/public/next/assets/{icon-base-NtFmP2yB.js.map → icon-base-DvM1eI5V.js.map} +1 -1
  191. package/dist/core/web/public/next/assets/{icons-C5EFt_Ts.js → icons-DEQa2rTx.js} +2 -2
  192. package/dist/core/web/public/next/assets/{icons-C5EFt_Ts.js.map → icons-DEQa2rTx.js.map} +1 -1
  193. package/dist/core/web/public/next/assets/{index-DbDw9UAs.js → index-BVxOlseC.js} +3 -3
  194. package/dist/core/web/public/next/assets/{index-DbDw9UAs.js.map → index-BVxOlseC.js.map} +1 -1
  195. package/dist/core/web/public/next/assets/{live-model-DEwrl7_A.js → live-model-bmsJgnYD.js} +2 -2
  196. package/dist/core/web/public/next/assets/{live-model-DEwrl7_A.js.map → live-model-bmsJgnYD.js.map} +1 -1
  197. package/dist/core/web/public/next/assets/{mind.module-CLhqMQak.js → mind.module-gTGAuJt1.js} +2 -2
  198. package/dist/core/web/public/next/assets/{mind.module-CLhqMQak.js.map → mind.module-gTGAuJt1.js.map} +1 -1
  199. package/dist/core/web/public/next/assets/{mutations-Kvzsg-iK.js → mutations-C5S7okTW.js} +2 -2
  200. package/dist/core/web/public/next/assets/{mutations-Kvzsg-iK.js.map → mutations-C5S7okTW.js.map} +1 -1
  201. package/dist/core/web/public/next/assets/{nav-C0IunEYF.js → nav-NVtnuG7A.js} +2 -2
  202. package/dist/core/web/public/next/assets/{nav-C0IunEYF.js.map → nav-NVtnuG7A.js.map} +1 -1
  203. package/dist/core/web/public/next/assets/{overnight-queries-C_AfcL7q.js → overnight-queries-DGm3qL1b.js} +2 -2
  204. package/dist/core/web/public/next/assets/{overnight-queries-C_AfcL7q.js.map → overnight-queries-DGm3qL1b.js.map} +1 -1
  205. package/dist/core/web/public/next/assets/{preloaded-CctOitLu.js → preloaded-Cwf9rsnZ.js} +2 -2
  206. package/dist/core/web/public/next/assets/{preloaded-CctOitLu.js.map → preloaded-Cwf9rsnZ.js.map} +1 -1
  207. package/dist/core/web/public/next/assets/primitives-DyCKYSBG.js +1 -0
  208. package/dist/core/web/public/next/assets/{queries-THD05gHP.js → queries-CYisSAAB.js} +2 -2
  209. package/dist/core/web/public/next/assets/{queries-THD05gHP.js.map → queries-CYisSAAB.js.map} +1 -1
  210. package/dist/core/web/public/next/assets/{reasoning-pref-BVPu0SME.js → reasoning-pref-BUcFF_5G.js} +2 -2
  211. package/dist/core/web/public/next/assets/{reasoning-pref-BVPu0SME.js.map → reasoning-pref-BUcFF_5G.js.map} +1 -1
  212. package/dist/core/web/public/next/assets/{reveal-anchor-wCT5b4m3.js → reveal-anchor-D-tV8xau.js} +2 -2
  213. package/dist/core/web/public/next/assets/{reveal-anchor-wCT5b4m3.js.map → reveal-anchor-D-tV8xau.js.map} +1 -1
  214. package/dist/core/web/public/next/assets/{seat-subscription-CR_VylsK.js → seat-subscription-B-f9ViU2.js} +2 -2
  215. package/dist/core/web/public/next/assets/{seat-subscription-CR_VylsK.js.map → seat-subscription-B-f9ViU2.js.map} +1 -1
  216. package/dist/core/web/public/next/assets/{section-visibility-B0xXUQJ0.js → section-visibility-Yctxu-if.js} +2 -2
  217. package/dist/core/web/public/next/assets/{section-visibility-B0xXUQJ0.js.map → section-visibility-Yctxu-if.js.map} +1 -1
  218. package/dist/core/web/public/next/assets/{sidebar-model-C5wVXGpb.js → sidebar-model-DQ-FyBHW.js} +2 -2
  219. package/dist/core/web/public/next/assets/{sidebar-model-C5wVXGpb.js.map → sidebar-model-DQ-FyBHW.js.map} +1 -1
  220. package/dist/core/web/public/next/assets/{slots-DDd8cEoh.js → slots-BhP8b8tf.js} +3 -3
  221. package/dist/core/web/public/next/assets/{slots-DDd8cEoh.js.map → slots-BhP8b8tf.js.map} +1 -1
  222. package/dist/core/web/public/next/assets/{surface-data-BFxAlefI.js → surface-data-DTI7LjvH.js} +2 -2
  223. package/dist/core/web/public/next/assets/{surface-data-BFxAlefI.js.map → surface-data-DTI7LjvH.js.map} +1 -1
  224. package/dist/core/web/public/next/assets/surface-prefetch-CdUEBFrl.js +2 -0
  225. package/dist/core/web/public/next/assets/{surface-prefetch-CHusyO9q.js.map → surface-prefetch-CdUEBFrl.js.map} +1 -1
  226. package/dist/core/web/public/next/assets/{tasks-model-DvkWveXs.js → tasks-model-BKDNqmmt.js} +2 -2
  227. package/dist/core/web/public/next/assets/{tasks-model-DvkWveXs.js.map → tasks-model-BKDNqmmt.js.map} +1 -1
  228. package/dist/core/web/public/next/assets/{terminal-icons-Dp6pJgV2.js → terminal-icons-D2xe-aM1.js} +2 -2
  229. package/dist/core/web/public/next/assets/{terminal-icons-Dp6pJgV2.js.map → terminal-icons-D2xe-aM1.js.map} +1 -1
  230. package/dist/core/web/public/next/assets/{usage-queries-CUTmnegA.js → usage-queries-BZuAANlI.js} +2 -2
  231. package/dist/core/web/public/next/assets/{usage-queries-CUTmnegA.js.map → usage-queries-BZuAANlI.js.map} +1 -1
  232. package/dist/core/web/public/next/assets/{use-guarded-action-UCX2u1t1.js → use-guarded-action-Cf4MeNBa.js} +2 -2
  233. package/dist/core/web/public/next/assets/{use-guarded-action-UCX2u1t1.js.map → use-guarded-action-Cf4MeNBa.js.map} +1 -1
  234. package/dist/core/web/public/next/assets/{use-ticker-OXAjob3y.js → use-ticker-D9yi49my.js} +2 -2
  235. package/dist/core/web/public/next/assets/{use-ticker-OXAjob3y.js.map → use-ticker-D9yi49my.js.map} +1 -1
  236. package/dist/core/web/public/next/assets/{use-token-gate-CDDRAoKH.js → use-token-gate-DqrSXdX6.js} +2 -2
  237. package/dist/core/web/public/next/assets/{use-token-gate-CDDRAoKH.js.map → use-token-gate-DqrSXdX6.js.map} +1 -1
  238. package/dist/core/web/public/next/assets/{useChartWidth-D9M7kUw7.js → useChartWidth-owwodNVz.js} +2 -2
  239. package/dist/core/web/public/next/assets/{useChartWidth-D9M7kUw7.js.map → useChartWidth-owwodNVz.js.map} +1 -1
  240. package/dist/core/web/public/next/assets/{useSeatsRefresh-B2dCVcj9.js → useSeatsRefresh-DgFy-Ph4.js} +2 -2
  241. package/dist/core/web/public/next/assets/{useSeatsRefresh-B2dCVcj9.js.map → useSeatsRefresh-DgFy-Ph4.js.map} +1 -1
  242. package/dist/core/web/public/next/assets/{useVerseTranscript-BL3CljSI.js → useVerseTranscript-CDYrrWOO.js} +2 -2
  243. package/dist/core/web/public/next/assets/{useVerseTranscript-BL3CljSI.js.map → useVerseTranscript-CDYrrWOO.js.map} +1 -1
  244. package/dist/core/web/public/next/assets/{verse-icons-DASWdYuE.js → verse-icons-F9VwX07_.js} +2 -2
  245. package/dist/core/web/public/next/assets/{verse-icons-DASWdYuE.js.map → verse-icons-F9VwX07_.js.map} +1 -1
  246. package/dist/core/web/public/next/assets/{verse-model-BQ0Y2CSr.js → verse-model-DyCwZF-M.js} +2 -2
  247. package/dist/core/web/public/next/assets/{verse-model-BQ0Y2CSr.js.map → verse-model-DyCwZF-M.js.map} +1 -1
  248. package/dist/core/web/public/next/assets/{verse-ui-store-D7YXi63q.js → verse-ui-store-62DxpVHS.js} +3 -3
  249. package/dist/core/web/public/next/assets/{verse-ui-store-D7YXi63q.js.map → verse-ui-store-62DxpVHS.js.map} +1 -1
  250. package/dist/core/web/public/next/assets/{viewport-BYGH5EgA.js → viewport-nTubFCwf.js} +2 -2
  251. package/dist/core/web/public/next/assets/{viewport-BYGH5EgA.js.map → viewport-nTubFCwf.js.map} +1 -1
  252. package/dist/core/web/public/next/assets/{warmup-AsqwWCUi.js → warmup-HG5vYbsN.js} +3 -3
  253. package/dist/core/web/public/next/assets/{warmup-AsqwWCUi.js.map → warmup-HG5vYbsN.js.map} +1 -1
  254. package/dist/core/web/public/next/assets/{workspace-model-CXorJr0G.js → workspace-model-CbhdPhei.js} +2 -2
  255. package/dist/core/web/public/next/assets/{workspace-model-CXorJr0G.js.map → workspace-model-CbhdPhei.js.map} +1 -1
  256. package/dist/core/web/public/next/index.html +1 -1
  257. package/dist/release-dependency-inventory.json +1 -1
  258. package/package.json +1 -1
  259. package/dist/core/web/public/next/assets/AutonomySection-D3d8lYO3.js +0 -2
  260. package/dist/core/web/public/next/assets/McpSection-DvHFaVyp.js +0 -2
  261. package/dist/core/web/public/next/assets/primitives-CbAGCNKt.js +0 -1
  262. package/dist/core/web/public/next/assets/surface-prefetch-CHusyO9q.js +0 -2
@@ -1 +1 @@
1
- {"version":3,"file":"BudgetControl-Mm1ZL4u6.js","names":[],"sources":["../../../../../../src/web-ui/routes/verse/budget/BudgetControl.module.css","../../../../../../src/web-ui/routes/verse/budget/BudgetControl.tsx"],"sourcesContent":["/* Budget panel. Hairlines and whitespace, no nested boxes (DESIGN-V2 §6).\n Every state is a WORD first; colour reinforces it. Status tokens are\n defined for both themes in tokens.css, so nothing here needs a dark rule. */\n\n.panel {\n display: flex;\n flex-direction: column;\n gap: var(--space-4);\n min-width: 0;\n color: var(--text-primary);\n font-family: var(--font-ui);\n}\n\n.header {\n display: flex;\n flex-wrap: wrap;\n align-items: baseline;\n gap: var(--space-2) var(--space-3);\n}\n.title {\n margin: 0;\n font-family: var(--font-display);\n font-size: var(--text-lg-size);\n font-weight: var(--font-weight-semibold);\n}\n.summary {\n margin: 0;\n flex: 1 1 16rem;\n font-size: var(--text-sm-size);\n color: var(--text-secondary);\n}\n.age {\n font-size: var(--text-2xs-size);\n color: var(--text-tertiary);\n font-variant-numeric: tabular-nums;\n}\n\n.mode {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-2) var(--space-3);\n}\n.modeText {\n margin: 0;\n flex: 1 1 14rem;\n font-size: var(--text-sm-size);\n color: var(--text-secondary);\n}\n\n.preview {\n margin: 0;\n display: flex;\n flex-wrap: wrap;\n align-items: baseline;\n gap: var(--space-1) var(--space-2);\n padding: var(--space-2) 0;\n border-top: 1px solid var(--border-subtle);\n border-bottom: 1px solid var(--border-subtle);\n font-size: var(--text-sm-size);\n}\n.previewLead { color: var(--text-secondary); }\n.previewWhy {\n flex-basis: 100%;\n font-size: var(--text-xs-size);\n color: var(--text-tertiary);\n}\n\n.error {\n margin: 0;\n font-size: var(--text-sm-size);\n color: var(--status-danger-fg);\n}\n.loading,\n.empty {\n margin: 0;\n font-size: var(--text-sm-size);\n color: var(--text-secondary);\n}\n\n.seats {\n list-style: none;\n margin: 0;\n padding: 0;\n display: flex;\n flex-direction: column;\n}\n.seat {\n display: flex;\n flex-direction: column;\n gap: var(--space-2);\n padding: var(--space-3) 0;\n border-bottom: 1px solid var(--border-subtle);\n min-width: 0;\n}\n.seat[aria-busy='true'] { opacity: 0.7; }\n\n.seatHead {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-2);\n min-width: 0;\n}\n.marker {\n width: 3px;\n height: 16px;\n border-radius: 2px;\n flex: none;\n}\n.seatName {\n font-weight: var(--font-weight-medium);\n font-size: var(--text-base-size);\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.status {\n font-family: var(--font-display);\n font-size: var(--text-2xs-size);\n font-weight: var(--font-weight-medium);\n letter-spacing: var(--tracking-label, 0.06em);\n text-transform: uppercase;\n color: var(--status-unknown-fg);\n}\n.status[data-status='eligible'] { color: var(--status-success-fg); }\n.status[data-status='held'] { color: var(--status-warning-fg); }\n.status[data-status='off'] { color: var(--status-neutral-fg); }\n.status[data-status='unknown'] { color: var(--status-unknown-fg); }\n.free {\n font-size: var(--text-2xs-size);\n color: var(--text-tertiary);\n}\n.toggle { margin-left: auto; }\n\n.bars {\n display: flex;\n flex-direction: column;\n gap: var(--space-1);\n}\n.bar {\n display: grid;\n grid-template-columns: 6.5rem minmax(0, 1fr) auto;\n align-items: center;\n gap: var(--space-2);\n font-size: var(--text-xs-size);\n}\n.barLabel {\n display: inline-flex;\n align-items: baseline;\n gap: var(--space-1);\n color: var(--text-secondary);\n white-space: nowrap;\n}\n.bar[data-binding] .barLabel { color: var(--text-primary); }\n.bindingMark {\n font-size: var(--text-2xs-size);\n color: var(--text-tertiary);\n}\n.barValue {\n font-variant-numeric: tabular-nums;\n color: var(--text-secondary);\n white-space: nowrap;\n}\n.unknown {\n font-style: italic;\n color: var(--status-unknown-fg);\n}\n\n/* The track: used (solid) · autonomy room (tint) · kept for you (hatched). */\n.track {\n position: relative;\n height: 8px;\n border-radius: var(--radius-full);\n background: var(--meter-track);\n overflow: hidden;\n}\n.used,\n.room,\n.reserveBand {\n position: absolute;\n top: 0;\n bottom: 0;\n}\n.used {\n left: 0;\n /* Quantity, not interaction: the fixed azure ramp, never the operator-chosen accent (DESIGN §13.2). */\n background: var(--data-seq-5);\n border-radius: var(--radius-full) 0 0 var(--radius-full);\n}\n.used[data-over] { background: var(--status-warning-solid); }\n.room {\n background: color-mix(in srgb, var(--data-seq-5) 28%, transparent);\n}\n.reserveBand {\n background: repeating-linear-gradient(\n 135deg,\n color-mix(in srgb, var(--text-tertiary) 30%, transparent) 0 3px,\n transparent 3px 6px\n );\n}\n.ceiling {\n position: absolute;\n top: -2px;\n bottom: -2px;\n width: 2px;\n margin-left: -1px;\n background: var(--text-primary);\n}\n.trackUnknown {\n height: 8px;\n border-radius: var(--radius-full);\n border: 1px dashed var(--border-strong);\n background: transparent;\n}\n\n.controls {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));\n gap: var(--space-2) var(--space-4);\n}\n\n.freeLine,\n.why {\n margin: 0;\n font-size: var(--text-xs-size);\n color: var(--text-secondary);\n}\n.more {\n font-size: var(--text-xs-size);\n color: var(--text-tertiary);\n}\n.more summary { cursor: pointer; }\n.more ul {\n margin: var(--space-1) 0 0;\n padding-left: var(--space-4);\n}\n\n.footnote {\n margin: 0;\n font-size: var(--text-2xs-size);\n color: var(--text-tertiary);\n}\n\n@media (max-width: 480px) {\n .bar {\n grid-template-columns: minmax(0, 1fr) auto;\n }\n .bar .track,\n .bar .trackUnknown {\n grid-column: 1 / -1;\n grid-row: 2;\n }\n .toggle { margin-left: 0; }\n}\n","/**\n * routes/verse/budget/BudgetControl.tsx — budget modes, per-seat reserves and\n * live headroom, in one panel.\n *\n * ┌ Budget ─────────────────────────── 3 of 7 seats can take autonomous work\n * │ [ Reserve | Balanced | All-in ] Autonomy stops at each seat's reserve…\n * │ Next medium task → Grok · why\n * │ ● Claude Code Eligible Autonomy [on]\n * │ Weekly ███████▒▒▒▒▒▒▒▒░░░░░░░░░ 20% used · stops at 60%\n * │ 5-hour ███▒▒▒▒▒▒▒▒▒▒▒▒░░░░░░░░░ 15% used · stops at 70%\n * │ Kept for you ──●──── 40% 5-hour ceiling ─────●── 70%\n * │ 40% of the weekly window is left for autonomy (40% kept for you).\n *\n * Each bar reads left to right: what is USED (solid), what autonomy may\n * still use (tinted), and the band KEPT FOR MASON (hatched) past the ceiling\n * tick. An unread window is a dashed track and the words \"no reading\" —\n * never an empty bar (which would claim headroom) or a full one.\n *\n * `BudgetControlView` is pure (props in, callbacks out) and is what the tests\n * render; `BudgetControl` wires it to the API, the mutation-token gate and a\n * 60 s refresh while the document is visible.\n *\n * Mount point: a Track B surface (Command home / Autonomy) owns placement —\n * this file only exports the panel.\n */\nimport { useCallback, useEffect, useId, useRef, useState } from 'react';\nimport type { BudgetView } from '../../../../core/routing/policy.js';\nimport type { BudgetMode, SeatDecision } from '../../../../core/routing/types.js';\nimport { MutationTokenDialog } from '../../../components/auth/MutationTokenDialog.js';\nimport { Segmented } from '../../../components/primitives/Segmented.js';\nimport { Slider } from '../../../components/primitives/Slider.js';\nimport { Switch } from '../../../components/primitives/Switch.js';\nimport { EngineMarker } from '../../../components/primitives/Tag.js';\nimport { useQuery, useRefetch } from '../../../data/hooks.js';\nimport { describeContextError, useTokenGate } from '../context/use-token-gate.js';\nimport { percentText, tidyProse } from '../autonomy/format.js';\nimport { readBudgetRows } from '../usage/capacity-strip-model.js';\nimport {\n BUDGET_MODE_OPTIONS,\n budgetSummary,\n clampPercent,\n modeAboveCeiling,\n readingAge,\n STATUS_WORDS,\n type BudgetBar,\n type BudgetSeatRow,\n} from './budget-model.js';\nimport { budgetPreviewQuery, budgetQuery, updateBudget, type BudgetSeatPatchWire } from './budget-queries.js';\nimport styles from './BudgetControl.module.css';\n\n/** Headroom moves with the collector (30 s cycle); a minute is plenty for a settings panel. */\nexport const BUDGET_POLL_MS = 60_000;\n/** Slider changes are committed this long after the last movement. */\nexport const BUDGET_COMMIT_DELAY_MS = 450;\n\n// ---------------------------------------------------------------------------\n// Headroom bar\n// ---------------------------------------------------------------------------\n\nfunction HeadroomBar({ bar }: { bar: BudgetBar }) {\n const used = bar.usedPercent;\n const ceiling = clampPercent(bar.ceilingPercent);\n if (used === null) {\n return (\n <div className={styles.bar} data-binding={bar.binding || undefined}>\n <span className={styles.barLabel}>{bar.label}</span>\n <div className={styles.trackUnknown} role=\"img\" aria-label={bar.description} />\n <span className={`${styles.barValue} ${styles.unknown}`}>no reading</span>\n </div>\n );\n }\n const usedPct = clampPercent(used);\n const over = usedPct >= ceiling;\n return (\n <div className={styles.bar} data-binding={bar.binding || undefined}>\n <span className={styles.barLabel}>\n {bar.label}\n {bar.binding ? <span className={styles.bindingMark} title=\"This window limits autonomy right now\">binding</span> : null}\n </span>\n <div className={styles.track} role=\"img\" aria-label={bar.description}>\n {ceiling < 100 ? (\n <div className={styles.reserveBand} style={{ left: `${ceiling}%`, width: `${100 - ceiling}%` }} />\n ) : null}\n {!over ? (\n <div className={styles.room} style={{ left: `${usedPct}%`, width: `${ceiling - usedPct}%` }} />\n ) : null}\n <div className={styles.used} data-over={over || undefined} style={{ width: `${usedPct}%` }} />\n {ceiling < 100 ? <div className={styles.ceiling} style={{ left: `${ceiling}%` }} /> : null}\n </div>\n <span className={styles.barValue}>\n {/* Words by the one percent rule; the bar geometry stays numeric. */}\n {percentText(used)} used{ceiling < 100 ? ` · stops at ${ceiling}%` : ''}\n </span>\n </div>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Draft slider — commits after the hand leaves it\n// ---------------------------------------------------------------------------\n\nfunction useCommittedDraft(serverValue: number, commit: (value: number) => void): [number, (v: number) => void] {\n const [draft, setDraft] = useState(serverValue);\n const dirty = useRef(false);\n const timer = useRef<ReturnType<typeof setTimeout> | null>(null);\n const commitRef = useRef(commit);\n commitRef.current = commit;\n\n // A new server value wins unless the operator is mid-drag.\n useEffect(() => {\n if (!dirty.current) setDraft(serverValue);\n }, [serverValue]);\n\n useEffect(() => () => {\n if (timer.current) clearTimeout(timer.current);\n }, []);\n\n const change = useCallback((value: number) => {\n setDraft(value);\n dirty.current = true;\n if (timer.current) clearTimeout(timer.current);\n timer.current = setTimeout(() => {\n dirty.current = false;\n timer.current = null;\n commitRef.current(value);\n }, BUDGET_COMMIT_DELAY_MS);\n }, []);\n\n return [draft, change];\n}\n\n// ---------------------------------------------------------------------------\n// One seat\n// ---------------------------------------------------------------------------\n\ninterface SeatRowProps {\n row: BudgetSeatRow;\n saving: boolean;\n readOnly: boolean;\n onSeat: (seatId: string, patch: BudgetSeatPatchWire) => void;\n}\n\nfunction SeatRow({ row, saving, readOnly, onSeat }: SeatRowProps) {\n const headingId = useId();\n const reserveServer = row.policy.reservePercent;\n const sessionServer = row.policy.maxSessionWindowPercent ?? 100;\n const [reserve, setReserve] = useCommittedDraft(reserveServer, (v) => {\n if (v !== reserveServer) onSeat(row.seatId, { reservePercent: v });\n });\n const [session, setSession] = useCommittedDraft(sessionServer, (v) => {\n if (v !== sessionServer) onSeat(row.seatId, { maxSessionWindowPercent: v >= 100 ? null : v });\n });\n const disabled = readOnly || saving;\n\n return (\n <li className={styles.seat} aria-labelledby={headingId} data-status={row.status} aria-busy={saving || undefined}>\n <div className={styles.seatHead}>\n <EngineMarker engine={row.engine} className={styles.marker} />\n {/* The name may truncate in a narrow sheet; the full name rides in the tooltip. */}\n <span id={headingId} className={styles.seatName} title={row.label}>{row.label}</span>\n <span className={styles.status} data-status={row.status}>{STATUS_WORDS[row.status]}</span>\n {row.free ? <span className={styles.free}>free</span> : null}\n <Switch\n className={styles.toggle}\n checked={row.policy.enabled}\n disabled={disabled}\n aria-label={`Autonomy on ${row.label}`}\n label=\"Autonomy\"\n onChange={(next) => onSeat(row.seatId, { enabled: next })}\n />\n </div>\n\n {row.bars.length > 0 ? (\n <div className={styles.bars}>\n {row.bars.map((bar) => <HeadroomBar key={bar.kind} bar={bar} />)}\n </div>\n ) : row.free ? (\n <p className={styles.freeLine}>No usage window — local models cost nothing and are never held back for you.</p>\n ) : null}\n\n {!row.free && row.policy.enabled ? (\n <div className={styles.controls}>\n <Slider\n label=\"Kept for you\"\n min={0}\n max={100}\n step={5}\n value={reserve}\n disabled={disabled}\n valueLabel={`${reserve}%`}\n valueText={`${reserve} percent of the ${row.engine === 'grok' ? 'billing period' : 'weekly window'} kept for you`}\n onChange={(e) => setReserve(clampPercent(Number(e.currentTarget.value)))}\n />\n {row.hasSessionCeiling ? (\n <Slider\n label=\"5-hour ceiling\"\n min={10}\n max={100}\n step={5}\n value={session}\n disabled={disabled}\n valueLabel={session >= 100 ? 'none' : `${session}%`}\n valueText={session >= 100 ? 'no 5-hour ceiling' : `autonomy stops at ${session} percent of the 5-hour window`}\n onChange={(e) => setSession(clampPercent(Number(e.currentTarget.value), 10, 100))}\n />\n ) : null}\n </div>\n ) : null}\n\n <p className={styles.why}>{row.why}</p>\n {row.more.length > 0 ? (\n <details className={styles.more}>\n <summary>{row.more.length === 1 ? '1 more note' : `${row.more.length} more notes`}</summary>\n <ul>\n {row.more.map((reason) => <li key={reason}>{reason}</li>)}\n </ul>\n </details>\n ) : null}\n </li>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Pure view\n// ---------------------------------------------------------------------------\n\nexport interface BudgetControlViewProps {\n view: BudgetView;\n preview: SeatDecision | null;\n nowMs: number;\n /** `'mode'` or a seat id while its change is in flight. */\n pending: string | null;\n error: string | null;\n readOnly?: boolean;\n /**\n * The standing grant's ceiling (`spend.maxMode`). Modes above it are shown\n * DISABLED with the reason — never hidden — because autonomy could not\n * spend them anyway. Moving toward Reserve is always allowed. Null/absent\n * = no grant ceiling applies (every mode selectable).\n */\n maxMode?: BudgetMode | null;\n onMode: (mode: BudgetMode) => void;\n onSeat: (seatId: string, patch: BudgetSeatPatchWire) => void;\n}\n\nexport function BudgetControlView({ view, preview, nowMs, pending, error, readOnly = false, maxMode = null, onMode, onSeat }: BudgetControlViewProps) {\n const titleId = useId();\n // The wire view is read defensively (the capacity strip's own guard): this\n // panel is opened from Apps, the composer's seat chip and the autonomy bar,\n // and a budget answer of `{}` or a garbled seat entry used to throw inside\n // buildBudgetRows and take the whole sheet down. A seat whose policy is\n // malformed is dropped, not shown as \"off\" — see readBudgetRows.\n const rows = [...readBudgetRows(view).values()];\n const summary = budgetSummary(rows);\n const knownMode = BUDGET_MODE_OPTIONS.find((o) => o.value === view.mode) ?? null;\n const mode = knownMode ?? BUDGET_MODE_OPTIONS[1]!;\n const maxAgeMs = typeof view.readingMaxAgeMs === 'number' && Number.isFinite(view.readingMaxAgeMs) ? view.readingMaxAgeMs : null;\n const ceilingLabel = maxMode ? BUDGET_MODE_OPTIONS.find((o) => o.value === maxMode)?.label ?? maxMode : null;\n const aboveNow = modeAboveCeiling(view.mode, maxMode);\n const chosen = preview?.seatId ? rows.find((r) => r.seatId === preview.seatId) : null;\n\n return (\n <section className={styles.panel} aria-labelledby={titleId}>\n <header className={styles.header}>\n <h2 id={titleId} className={styles.title}>Budget</h2>\n <p className={styles.summary}>{summary.sentence}</p>\n <span className={styles.age}>\n {Number.isFinite(Date.parse(view.sampledAt)) ? `Readings ${readingAge(view.sampledAt, nowMs)}` : 'Reading time not reported'}\n </span>\n </header>\n\n <div className={styles.mode}>\n <Segmented\n aria-label=\"Budget mode\"\n options={BUDGET_MODE_OPTIONS.map((o) => ({\n value: o.value,\n label: o.label,\n ...(modeAboveCeiling(o.value, maxMode) ? { ariaLabel: `${o.label} — above your grant` } : {}),\n disabled: readOnly || pending !== null || modeAboveCeiling(o.value, maxMode),\n }))}\n value={view.mode}\n onChange={(next) => { if (next !== view.mode && !modeAboveCeiling(next, maxMode)) onMode(next); }}\n />\n {/* No option is pressed when the server named no mode we know —\n showing Balanced there would claim a setting nobody read. */}\n <p className={styles.modeText}>{knownMode ? mode.description : 'The server did not say which mode is on.'}</p>\n {ceilingLabel ? (\n <p className={styles.modeText} data-ceiling=\"\">\n {aboveNow\n ? `Your grant allows up to ${ceilingLabel}, so autonomy spends as ${ceilingLabel} until this moves down.`\n : `Your grant allows up to ${ceilingLabel}; modes above it are off. Re-approve the grant to raise it.`}\n </p>\n ) : null}\n </div>\n\n {preview ? (\n <p className={styles.preview} aria-live=\"polite\">\n <span className={styles.previewLead}>Next medium task →</span>{' '}\n <strong>{chosen?.label ?? (preview.seatId ?? 'nowhere right now')}</strong>\n <span className={styles.previewWhy}>{/* A `{}` preview (an older server) has no why: say nothing rather than crash. */}\n {typeof preview.why === 'string' ? tidyProse(preview.why, nowMs) : null}</span>\n </p>\n ) : null}\n\n {error ? <p className={styles.error} role=\"alert\">{error}</p> : null}\n\n {rows.length === 0 ? (\n <p className={styles.empty}>No seats yet — connect an account or start Ollama, and they appear here.</p>\n ) : (\n <ul className={styles.seats}>\n {rows.map((row) => (\n <SeatRow key={row.seatId} row={row} saving={pending === row.seatId || pending === 'mode'} readOnly={readOnly} onSeat={onSeat} />\n ))}\n </ul>\n )}\n\n <p className={styles.footnote}>\n Reserves apply to autonomous work only — your own chats can always use a seat. Unknown usage is never treated as\n headroom: a seat with no reading, or one {maxAgeMs !== null ? `older than ${Math.round(maxAgeMs / 60_000)} minutes` : 'whose reading is stale'}, is held back.\n </p>\n </section>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Connected panel\n// ---------------------------------------------------------------------------\n\nexport function BudgetControl({ maxMode = null }: { maxMode?: BudgetMode | null } = {}) {\n const budget = useQuery(budgetQuery, { freshMs: 0 });\n const preview = useQuery(budgetPreviewQuery, { freshMs: 0 });\n const refetchBudget = useRefetch(budgetQuery);\n const refetchPreview = useRefetch(budgetPreviewQuery);\n const gate = useTokenGate();\n const [latest, setLatest] = useState<BudgetView | null>(null);\n const [pending, setPending] = useState<string | null>(null);\n const [error, setError] = useState<string | null>(null);\n const [nowMs, setNowMs] = useState(() => Date.now());\n\n // Poll while visible; read immediately on return (useSeatsRefresh's pattern).\n useEffect(() => {\n const tick = (): void => {\n if (typeof document !== 'undefined' && document.visibilityState === 'hidden') return;\n refetchBudget();\n refetchPreview();\n setNowMs(Date.now());\n };\n const timer = window.setInterval(tick, BUDGET_POLL_MS);\n document.addEventListener('visibilitychange', tick);\n return () => {\n window.clearInterval(timer);\n document.removeEventListener('visibilitychange', tick);\n };\n }, [refetchBudget, refetchPreview]);\n\n // The POST response is newer than the cached read until the refetch lands.\n // A cached read with no parseable sampledAt cannot be shown to be newer, so\n // the POST's answer wins (NaN comparisons are always false).\n const cached = budget.data;\n const view = latest && (!cached || !(Date.parse(latest.sampledAt) < Date.parse(cached.sampledAt))) ? latest : cached;\n\n const apply = useCallback(async (key: string, reason: string, update: Parameters<typeof updateBudget>[0]) => {\n setPending(key);\n setError(null);\n try {\n const next = await gate.run(reason, () => updateBudget(update));\n if (next) setLatest(next);\n } catch (err) {\n setError(describeContextError(err));\n } finally {\n setPending(null);\n setNowMs(Date.now());\n }\n }, [gate]);\n\n if (!view) {\n return (\n <section className={styles.panel} aria-label=\"Budget\">\n {budget.status === 'error' ? (\n <p className={styles.error} role=\"alert\">Budget unavailable: {budget.error?.message ?? 'the request failed.'}</p>\n ) : (\n <p className={styles.loading}>Reading seat usage…</p>\n )}\n </section>\n );\n }\n\n return (\n <>\n <BudgetControlView\n view={view}\n preview={preview.data ?? null}\n nowMs={nowMs}\n pending={pending}\n error={error}\n maxMode={maxMode}\n onMode={(mode) => void apply('mode', `Switch the budget to ${mode}`, { mode })}\n onSeat={(seatId, patch) => void apply(seatId, `Change the budget for ${seatId}`, { seatId, policy: patch })}\n />\n <MutationTokenDialog open={gate.dialog.open} reason={gate.dialog.reason} tokenLabel=\"Mutation token\"\n tokenHelp=\"the mutation token ashlr verse printed\" onClose={gate.dialog.onClose} onUnlocked={gate.dialog.onUnlocked} />\n </>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"BudgetControl-TL3FeZ1D.js","names":[],"sources":["../../../../../../src/web-ui/routes/verse/budget/BudgetControl.module.css","../../../../../../src/web-ui/routes/verse/budget/BudgetControl.tsx"],"sourcesContent":["/* Budget panel. Hairlines and whitespace, no nested boxes (DESIGN-V2 §6).\n Every state is a WORD first; colour reinforces it. Status tokens are\n defined for both themes in tokens.css, so nothing here needs a dark rule. */\n\n.panel {\n display: flex;\n flex-direction: column;\n gap: var(--space-4);\n min-width: 0;\n color: var(--text-primary);\n font-family: var(--font-ui);\n}\n\n.header {\n display: flex;\n flex-wrap: wrap;\n align-items: baseline;\n gap: var(--space-2) var(--space-3);\n}\n.title {\n margin: 0;\n font-family: var(--font-display);\n font-size: var(--text-lg-size);\n font-weight: var(--font-weight-semibold);\n}\n.summary {\n margin: 0;\n flex: 1 1 16rem;\n font-size: var(--text-sm-size);\n color: var(--text-secondary);\n}\n.age {\n font-size: var(--text-2xs-size);\n color: var(--text-tertiary);\n font-variant-numeric: tabular-nums;\n}\n\n.mode {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-2) var(--space-3);\n}\n.modeText {\n margin: 0;\n flex: 1 1 14rem;\n font-size: var(--text-sm-size);\n color: var(--text-secondary);\n}\n\n.preview {\n margin: 0;\n display: flex;\n flex-wrap: wrap;\n align-items: baseline;\n gap: var(--space-1) var(--space-2);\n padding: var(--space-2) 0;\n border-top: 1px solid var(--border-subtle);\n border-bottom: 1px solid var(--border-subtle);\n font-size: var(--text-sm-size);\n}\n.previewLead { color: var(--text-secondary); }\n.previewWhy {\n flex-basis: 100%;\n font-size: var(--text-xs-size);\n color: var(--text-tertiary);\n}\n\n.error {\n margin: 0;\n font-size: var(--text-sm-size);\n color: var(--status-danger-fg);\n}\n.loading,\n.empty {\n margin: 0;\n font-size: var(--text-sm-size);\n color: var(--text-secondary);\n}\n\n.seats {\n list-style: none;\n margin: 0;\n padding: 0;\n display: flex;\n flex-direction: column;\n}\n.seat {\n display: flex;\n flex-direction: column;\n gap: var(--space-2);\n padding: var(--space-3) 0;\n border-bottom: 1px solid var(--border-subtle);\n min-width: 0;\n}\n.seat[aria-busy='true'] { opacity: 0.7; }\n\n.seatHead {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-2);\n min-width: 0;\n}\n.marker {\n width: 3px;\n height: 16px;\n border-radius: 2px;\n flex: none;\n}\n.seatName {\n font-weight: var(--font-weight-medium);\n font-size: var(--text-base-size);\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.status {\n font-family: var(--font-display);\n font-size: var(--text-2xs-size);\n font-weight: var(--font-weight-medium);\n letter-spacing: var(--tracking-label, 0.06em);\n text-transform: uppercase;\n color: var(--status-unknown-fg);\n}\n.status[data-status='eligible'] { color: var(--status-success-fg); }\n.status[data-status='held'] { color: var(--status-warning-fg); }\n.status[data-status='off'] { color: var(--status-neutral-fg); }\n.status[data-status='unknown'] { color: var(--status-unknown-fg); }\n.free {\n font-size: var(--text-2xs-size);\n color: var(--text-tertiary);\n}\n.toggle { margin-left: auto; }\n\n.bars {\n display: flex;\n flex-direction: column;\n gap: var(--space-1);\n}\n.bar {\n display: grid;\n grid-template-columns: 6.5rem minmax(0, 1fr) auto;\n align-items: center;\n gap: var(--space-2);\n font-size: var(--text-xs-size);\n}\n.barLabel {\n display: inline-flex;\n align-items: baseline;\n gap: var(--space-1);\n color: var(--text-secondary);\n white-space: nowrap;\n}\n.bar[data-binding] .barLabel { color: var(--text-primary); }\n.bindingMark {\n font-size: var(--text-2xs-size);\n color: var(--text-tertiary);\n}\n.barValue {\n font-variant-numeric: tabular-nums;\n color: var(--text-secondary);\n white-space: nowrap;\n}\n.unknown {\n font-style: italic;\n color: var(--status-unknown-fg);\n}\n\n/* The track: used (solid) · autonomy room (tint) · kept for you (hatched). */\n.track {\n position: relative;\n height: 8px;\n border-radius: var(--radius-full);\n background: var(--meter-track);\n overflow: hidden;\n}\n.used,\n.room,\n.reserveBand {\n position: absolute;\n top: 0;\n bottom: 0;\n}\n.used {\n left: 0;\n /* Quantity, not interaction: the fixed azure ramp, never the operator-chosen accent (DESIGN §13.2). */\n background: var(--data-seq-5);\n border-radius: var(--radius-full) 0 0 var(--radius-full);\n}\n.used[data-over] { background: var(--status-warning-solid); }\n.room {\n background: color-mix(in srgb, var(--data-seq-5) 28%, transparent);\n}\n.reserveBand {\n background: repeating-linear-gradient(\n 135deg,\n color-mix(in srgb, var(--text-tertiary) 30%, transparent) 0 3px,\n transparent 3px 6px\n );\n}\n.ceiling {\n position: absolute;\n top: -2px;\n bottom: -2px;\n width: 2px;\n margin-left: -1px;\n background: var(--text-primary);\n}\n.trackUnknown {\n height: 8px;\n border-radius: var(--radius-full);\n border: 1px dashed var(--border-strong);\n background: transparent;\n}\n\n.controls {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));\n gap: var(--space-2) var(--space-4);\n}\n\n.freeLine,\n.why {\n margin: 0;\n font-size: var(--text-xs-size);\n color: var(--text-secondary);\n}\n.more {\n font-size: var(--text-xs-size);\n color: var(--text-tertiary);\n}\n.more summary { cursor: pointer; }\n.more ul {\n margin: var(--space-1) 0 0;\n padding-left: var(--space-4);\n}\n\n.footnote {\n margin: 0;\n font-size: var(--text-2xs-size);\n color: var(--text-tertiary);\n}\n\n@media (max-width: 480px) {\n .bar {\n grid-template-columns: minmax(0, 1fr) auto;\n }\n .bar .track,\n .bar .trackUnknown {\n grid-column: 1 / -1;\n grid-row: 2;\n }\n .toggle { margin-left: 0; }\n}\n","/**\n * routes/verse/budget/BudgetControl.tsx — budget modes, per-seat reserves and\n * live headroom, in one panel.\n *\n * ┌ Budget ─────────────────────────── 3 of 7 seats can take autonomous work\n * │ [ Reserve | Balanced | All-in ] Autonomy stops at each seat's reserve…\n * │ Next medium task → Grok · why\n * │ ● Claude Code Eligible Autonomy [on]\n * │ Weekly ███████▒▒▒▒▒▒▒▒░░░░░░░░░ 20% used · stops at 60%\n * │ 5-hour ███▒▒▒▒▒▒▒▒▒▒▒▒░░░░░░░░░ 15% used · stops at 70%\n * │ Kept for you ──●──── 40% 5-hour ceiling ─────●── 70%\n * │ 40% of the weekly window is left for autonomy (40% kept for you).\n *\n * Each bar reads left to right: what is USED (solid), what autonomy may\n * still use (tinted), and the band KEPT FOR MASON (hatched) past the ceiling\n * tick. An unread window is a dashed track and the words \"no reading\" —\n * never an empty bar (which would claim headroom) or a full one.\n *\n * `BudgetControlView` is pure (props in, callbacks out) and is what the tests\n * render; `BudgetControl` wires it to the API, the mutation-token gate and a\n * 60 s refresh while the document is visible.\n *\n * Mount point: a Track B surface (Command home / Autonomy) owns placement —\n * this file only exports the panel.\n */\nimport { useCallback, useEffect, useId, useRef, useState } from 'react';\nimport type { BudgetView } from '../../../../core/routing/policy.js';\nimport type { BudgetMode, SeatDecision } from '../../../../core/routing/types.js';\nimport { MutationTokenDialog } from '../../../components/auth/MutationTokenDialog.js';\nimport { Segmented } from '../../../components/primitives/Segmented.js';\nimport { Slider } from '../../../components/primitives/Slider.js';\nimport { Switch } from '../../../components/primitives/Switch.js';\nimport { EngineMarker } from '../../../components/primitives/Tag.js';\nimport { useQuery, useRefetch } from '../../../data/hooks.js';\nimport { describeContextError, useTokenGate } from '../context/use-token-gate.js';\nimport { percentText, tidyProse } from '../autonomy/format.js';\nimport { readBudgetRows } from '../usage/capacity-strip-model.js';\nimport {\n BUDGET_MODE_OPTIONS,\n budgetSummary,\n clampPercent,\n modeAboveCeiling,\n readingAge,\n STATUS_WORDS,\n type BudgetBar,\n type BudgetSeatRow,\n} from './budget-model.js';\nimport { budgetPreviewQuery, budgetQuery, updateBudget, type BudgetSeatPatchWire } from './budget-queries.js';\nimport styles from './BudgetControl.module.css';\n\n/** Headroom moves with the collector (30 s cycle); a minute is plenty for a settings panel. */\nexport const BUDGET_POLL_MS = 60_000;\n/** Slider changes are committed this long after the last movement. */\nexport const BUDGET_COMMIT_DELAY_MS = 450;\n\n// ---------------------------------------------------------------------------\n// Headroom bar\n// ---------------------------------------------------------------------------\n\nfunction HeadroomBar({ bar }: { bar: BudgetBar }) {\n const used = bar.usedPercent;\n const ceiling = clampPercent(bar.ceilingPercent);\n if (used === null) {\n return (\n <div className={styles.bar} data-binding={bar.binding || undefined}>\n <span className={styles.barLabel}>{bar.label}</span>\n <div className={styles.trackUnknown} role=\"img\" aria-label={bar.description} />\n <span className={`${styles.barValue} ${styles.unknown}`}>no reading</span>\n </div>\n );\n }\n const usedPct = clampPercent(used);\n const over = usedPct >= ceiling;\n return (\n <div className={styles.bar} data-binding={bar.binding || undefined}>\n <span className={styles.barLabel}>\n {bar.label}\n {bar.binding ? <span className={styles.bindingMark} title=\"This window limits autonomy right now\">binding</span> : null}\n </span>\n <div className={styles.track} role=\"img\" aria-label={bar.description}>\n {ceiling < 100 ? (\n <div className={styles.reserveBand} style={{ left: `${ceiling}%`, width: `${100 - ceiling}%` }} />\n ) : null}\n {!over ? (\n <div className={styles.room} style={{ left: `${usedPct}%`, width: `${ceiling - usedPct}%` }} />\n ) : null}\n <div className={styles.used} data-over={over || undefined} style={{ width: `${usedPct}%` }} />\n {ceiling < 100 ? <div className={styles.ceiling} style={{ left: `${ceiling}%` }} /> : null}\n </div>\n <span className={styles.barValue}>\n {/* Words by the one percent rule; the bar geometry stays numeric. */}\n {percentText(used)} used{ceiling < 100 ? ` · stops at ${ceiling}%` : ''}\n </span>\n </div>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Draft slider — commits after the hand leaves it\n// ---------------------------------------------------------------------------\n\nfunction useCommittedDraft(serverValue: number, commit: (value: number) => void): [number, (v: number) => void] {\n const [draft, setDraft] = useState(serverValue);\n const dirty = useRef(false);\n const timer = useRef<ReturnType<typeof setTimeout> | null>(null);\n const commitRef = useRef(commit);\n commitRef.current = commit;\n\n // A new server value wins unless the operator is mid-drag.\n useEffect(() => {\n if (!dirty.current) setDraft(serverValue);\n }, [serverValue]);\n\n useEffect(() => () => {\n if (timer.current) clearTimeout(timer.current);\n }, []);\n\n const change = useCallback((value: number) => {\n setDraft(value);\n dirty.current = true;\n if (timer.current) clearTimeout(timer.current);\n timer.current = setTimeout(() => {\n dirty.current = false;\n timer.current = null;\n commitRef.current(value);\n }, BUDGET_COMMIT_DELAY_MS);\n }, []);\n\n return [draft, change];\n}\n\n// ---------------------------------------------------------------------------\n// One seat\n// ---------------------------------------------------------------------------\n\ninterface SeatRowProps {\n row: BudgetSeatRow;\n saving: boolean;\n readOnly: boolean;\n onSeat: (seatId: string, patch: BudgetSeatPatchWire) => void;\n}\n\nfunction SeatRow({ row, saving, readOnly, onSeat }: SeatRowProps) {\n const headingId = useId();\n const reserveServer = row.policy.reservePercent;\n const sessionServer = row.policy.maxSessionWindowPercent ?? 100;\n const [reserve, setReserve] = useCommittedDraft(reserveServer, (v) => {\n if (v !== reserveServer) onSeat(row.seatId, { reservePercent: v });\n });\n const [session, setSession] = useCommittedDraft(sessionServer, (v) => {\n if (v !== sessionServer) onSeat(row.seatId, { maxSessionWindowPercent: v >= 100 ? null : v });\n });\n const disabled = readOnly || saving;\n\n return (\n <li className={styles.seat} aria-labelledby={headingId} data-status={row.status} aria-busy={saving || undefined}>\n <div className={styles.seatHead}>\n <EngineMarker engine={row.engine} className={styles.marker} />\n {/* The name may truncate in a narrow sheet; the full name rides in the tooltip. */}\n <span id={headingId} className={styles.seatName} title={row.label}>{row.label}</span>\n <span className={styles.status} data-status={row.status}>{STATUS_WORDS[row.status]}</span>\n {row.free ? <span className={styles.free}>free</span> : null}\n <Switch\n className={styles.toggle}\n checked={row.policy.enabled}\n disabled={disabled}\n aria-label={`Autonomy on ${row.label}`}\n label=\"Autonomy\"\n onChange={(next) => onSeat(row.seatId, { enabled: next })}\n />\n </div>\n\n {row.bars.length > 0 ? (\n <div className={styles.bars}>\n {row.bars.map((bar) => <HeadroomBar key={bar.kind} bar={bar} />)}\n </div>\n ) : row.free ? (\n <p className={styles.freeLine}>No usage window — local models cost nothing and are never held back for you.</p>\n ) : null}\n\n {!row.free && row.policy.enabled ? (\n <div className={styles.controls}>\n <Slider\n label=\"Kept for you\"\n min={0}\n max={100}\n step={5}\n value={reserve}\n disabled={disabled}\n valueLabel={`${reserve}%`}\n valueText={`${reserve} percent of the ${row.engine === 'grok' ? 'billing period' : 'weekly window'} kept for you`}\n onChange={(e) => setReserve(clampPercent(Number(e.currentTarget.value)))}\n />\n {row.hasSessionCeiling ? (\n <Slider\n label=\"5-hour ceiling\"\n min={10}\n max={100}\n step={5}\n value={session}\n disabled={disabled}\n valueLabel={session >= 100 ? 'none' : `${session}%`}\n valueText={session >= 100 ? 'no 5-hour ceiling' : `autonomy stops at ${session} percent of the 5-hour window`}\n onChange={(e) => setSession(clampPercent(Number(e.currentTarget.value), 10, 100))}\n />\n ) : null}\n </div>\n ) : null}\n\n <p className={styles.why}>{row.why}</p>\n {row.more.length > 0 ? (\n <details className={styles.more}>\n <summary>{row.more.length === 1 ? '1 more note' : `${row.more.length} more notes`}</summary>\n <ul>\n {row.more.map((reason) => <li key={reason}>{reason}</li>)}\n </ul>\n </details>\n ) : null}\n </li>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Pure view\n// ---------------------------------------------------------------------------\n\nexport interface BudgetControlViewProps {\n view: BudgetView;\n preview: SeatDecision | null;\n nowMs: number;\n /** `'mode'` or a seat id while its change is in flight. */\n pending: string | null;\n error: string | null;\n readOnly?: boolean;\n /**\n * The standing grant's ceiling (`spend.maxMode`). Modes above it are shown\n * DISABLED with the reason — never hidden — because autonomy could not\n * spend them anyway. Moving toward Reserve is always allowed. Null/absent\n * = no grant ceiling applies (every mode selectable).\n */\n maxMode?: BudgetMode | null;\n onMode: (mode: BudgetMode) => void;\n onSeat: (seatId: string, patch: BudgetSeatPatchWire) => void;\n}\n\nexport function BudgetControlView({ view, preview, nowMs, pending, error, readOnly = false, maxMode = null, onMode, onSeat }: BudgetControlViewProps) {\n const titleId = useId();\n // The wire view is read defensively (the capacity strip's own guard): this\n // panel is opened from Apps, the composer's seat chip and the autonomy bar,\n // and a budget answer of `{}` or a garbled seat entry used to throw inside\n // buildBudgetRows and take the whole sheet down. A seat whose policy is\n // malformed is dropped, not shown as \"off\" — see readBudgetRows.\n const rows = [...readBudgetRows(view).values()];\n const summary = budgetSummary(rows);\n const knownMode = BUDGET_MODE_OPTIONS.find((o) => o.value === view.mode) ?? null;\n const mode = knownMode ?? BUDGET_MODE_OPTIONS[1]!;\n const maxAgeMs = typeof view.readingMaxAgeMs === 'number' && Number.isFinite(view.readingMaxAgeMs) ? view.readingMaxAgeMs : null;\n const ceilingLabel = maxMode ? BUDGET_MODE_OPTIONS.find((o) => o.value === maxMode)?.label ?? maxMode : null;\n const aboveNow = modeAboveCeiling(view.mode, maxMode);\n const chosen = preview?.seatId ? rows.find((r) => r.seatId === preview.seatId) : null;\n\n return (\n <section className={styles.panel} aria-labelledby={titleId}>\n <header className={styles.header}>\n <h2 id={titleId} className={styles.title}>Budget</h2>\n <p className={styles.summary}>{summary.sentence}</p>\n <span className={styles.age}>\n {Number.isFinite(Date.parse(view.sampledAt)) ? `Readings ${readingAge(view.sampledAt, nowMs)}` : 'Reading time not reported'}\n </span>\n </header>\n\n <div className={styles.mode}>\n <Segmented\n aria-label=\"Budget mode\"\n options={BUDGET_MODE_OPTIONS.map((o) => ({\n value: o.value,\n label: o.label,\n ...(modeAboveCeiling(o.value, maxMode) ? { ariaLabel: `${o.label} — above your grant` } : {}),\n disabled: readOnly || pending !== null || modeAboveCeiling(o.value, maxMode),\n }))}\n value={view.mode}\n onChange={(next) => { if (next !== view.mode && !modeAboveCeiling(next, maxMode)) onMode(next); }}\n />\n {/* No option is pressed when the server named no mode we know —\n showing Balanced there would claim a setting nobody read. */}\n <p className={styles.modeText}>{knownMode ? mode.description : 'The server did not say which mode is on.'}</p>\n {ceilingLabel ? (\n <p className={styles.modeText} data-ceiling=\"\">\n {aboveNow\n ? `Your grant allows up to ${ceilingLabel}, so autonomy spends as ${ceilingLabel} until this moves down.`\n : `Your grant allows up to ${ceilingLabel}; modes above it are off. Re-approve the grant to raise it.`}\n </p>\n ) : null}\n </div>\n\n {preview ? (\n <p className={styles.preview} aria-live=\"polite\">\n <span className={styles.previewLead}>Next medium task →</span>{' '}\n <strong>{chosen?.label ?? (preview.seatId ?? 'nowhere right now')}</strong>\n <span className={styles.previewWhy}>{/* A `{}` preview (an older server) has no why: say nothing rather than crash. */}\n {typeof preview.why === 'string' ? tidyProse(preview.why, nowMs) : null}</span>\n </p>\n ) : null}\n\n {error ? <p className={styles.error} role=\"alert\">{error}</p> : null}\n\n {rows.length === 0 ? (\n <p className={styles.empty}>No seats yet — connect an account or start Ollama, and they appear here.</p>\n ) : (\n <ul className={styles.seats}>\n {rows.map((row) => (\n <SeatRow key={row.seatId} row={row} saving={pending === row.seatId || pending === 'mode'} readOnly={readOnly} onSeat={onSeat} />\n ))}\n </ul>\n )}\n\n <p className={styles.footnote}>\n Reserves apply to autonomous work only — your own chats can always use a seat. Unknown usage is never treated as\n headroom: a seat with no reading, or one {maxAgeMs !== null ? `older than ${Math.round(maxAgeMs / 60_000)} minutes` : 'whose reading is stale'}, is held back.\n </p>\n </section>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Connected panel\n// ---------------------------------------------------------------------------\n\nexport function BudgetControl({ maxMode = null }: { maxMode?: BudgetMode | null } = {}) {\n const budget = useQuery(budgetQuery, { freshMs: 0 });\n const preview = useQuery(budgetPreviewQuery, { freshMs: 0 });\n const refetchBudget = useRefetch(budgetQuery);\n const refetchPreview = useRefetch(budgetPreviewQuery);\n const gate = useTokenGate();\n const [latest, setLatest] = useState<BudgetView | null>(null);\n const [pending, setPending] = useState<string | null>(null);\n const [error, setError] = useState<string | null>(null);\n const [nowMs, setNowMs] = useState(() => Date.now());\n\n // Poll while visible; read immediately on return (useSeatsRefresh's pattern).\n useEffect(() => {\n const tick = (): void => {\n if (typeof document !== 'undefined' && document.visibilityState === 'hidden') return;\n refetchBudget();\n refetchPreview();\n setNowMs(Date.now());\n };\n const timer = window.setInterval(tick, BUDGET_POLL_MS);\n document.addEventListener('visibilitychange', tick);\n return () => {\n window.clearInterval(timer);\n document.removeEventListener('visibilitychange', tick);\n };\n }, [refetchBudget, refetchPreview]);\n\n // The POST response is newer than the cached read until the refetch lands.\n // A cached read with no parseable sampledAt cannot be shown to be newer, so\n // the POST's answer wins (NaN comparisons are always false).\n const cached = budget.data;\n const view = latest && (!cached || !(Date.parse(latest.sampledAt) < Date.parse(cached.sampledAt))) ? latest : cached;\n\n const apply = useCallback(async (key: string, reason: string, update: Parameters<typeof updateBudget>[0]) => {\n setPending(key);\n setError(null);\n try {\n const next = await gate.run(reason, () => updateBudget(update));\n if (next) setLatest(next);\n } catch (err) {\n setError(describeContextError(err));\n } finally {\n setPending(null);\n setNowMs(Date.now());\n }\n }, [gate]);\n\n if (!view) {\n return (\n <section className={styles.panel} aria-label=\"Budget\">\n {budget.status === 'error' ? (\n <p className={styles.error} role=\"alert\">Budget unavailable: {budget.error?.message ?? 'the request failed.'}</p>\n ) : (\n <p className={styles.loading}>Reading seat usage…</p>\n )}\n </section>\n );\n }\n\n return (\n <>\n <BudgetControlView\n view={view}\n preview={preview.data ?? null}\n nowMs={nowMs}\n pending={pending}\n error={error}\n maxMode={maxMode}\n onMode={(mode) => void apply('mode', `Switch the budget to ${mode}`, { mode })}\n onSeat={(seatId, patch) => void apply(seatId, `Change the budget for ${seatId}`, { seatId, policy: patch })}\n />\n <MutationTokenDialog open={gate.dialog.open} reason={gate.dialog.reason} tokenLabel=\"Mutation token\"\n tokenHelp=\"the mutation token ashlr verse printed\" onClose={gate.dialog.onClose} onUnlocked={gate.dialog.onUnlocked} />\n </>\n );\n}\n"],"mappings":"wtDCmDa,EAAiB,IAQ9B,SAAS,EAAY,CAAE,OAA2B,CAChD,IAAM,EAAO,EAAI,YACX,EAAU,EAAa,EAAI,cAAc,EAC/C,GAAI,IAAS,KACX,OACE,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAW,EAAO,IAAK,eAAc,EAAI,SAAW,IAAA,GAAzD,SAAA,EACE,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAO,SAAW,SAAA,EAAI,KAAY,CAAA,GACnD,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAW,EAAO,aAAc,KAAK,MAAM,aAAY,EAAI,WAAc,CAAA,GAC9E,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,GAAG,EAAO,SAAS,GAAG,EAAO,UAAW,SAAA,YAAgB,CAAA,CACtE,IAGT,IAAM,EAAU,EAAa,CAAI,EAC3B,EAAO,GAAW,EACxB,OACE,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAW,EAAO,IAAK,eAAc,EAAI,SAAW,IAAA,GAAzD,SAAA,EACE,EAAA,EAAA,KAAA,CAAC,OAAD,CAAM,UAAW,EAAO,SAAxB,SAAA,CACG,EAAI,MACJ,EAAI,SAAU,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAO,YAAa,MAAM,wCAAwC,SAAA,SAAa,CAAA,EAAI,IAC/G,KACN,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAW,EAAO,MAAO,KAAK,MAAM,aAAY,EAAI,YAAzD,SAAA,CACG,EAAU,KACT,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAW,EAAO,YAAa,MAAO,CAAE,KAAM,GAAG,EAAQ,GAAI,MAAO,GAAG,IAAM,EAAQ,EAAG,CAAI,CAAA,EAC/F,KACF,EAEE,MADF,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAW,EAAO,KAAM,MAAO,CAAE,KAAM,GAAG,EAAQ,GAAI,MAAO,GAAG,EAAU,EAAQ,EAAG,CAAI,CAAA,GAEhG,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAW,EAAO,KAAM,YAAW,GAAQ,IAAA,GAAW,MAAO,CAAE,MAAO,GAAG,EAAQ,EAAG,CAAI,CAAA,EAC5F,EAAU,KAAM,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAW,EAAO,QAAS,MAAO,CAAE,KAAM,GAAG,EAAQ,EAAG,CAAI,CAAA,EAAI,IACnF,KACL,EAAA,EAAA,KAAA,CAAC,OAAD,CAAM,UAAW,EAAO,SAAxB,SAAA,CAEG,EAAY,CAAI,EAAE,QAAM,EAAU,IAAM,eAAe,EAAQ,GAAK,EACjE,GACH,GAET,CAMA,SAAS,EAAkB,EAAqB,EAAgE,CAC9G,GAAM,CAAC,EAAO,IAAA,EAAY,EAAA,SAAA,CAAS,CAAW,EACxC,GAAA,EAAQ,EAAA,OAAA,CAAO,EAAK,EACpB,GAAA,EAAQ,EAAA,OAAA,CAA6C,IAAI,EACzD,GAAA,EAAY,EAAA,OAAA,CAAO,CAAM,EAuB/B,MAtBA,GAAU,QAAU,GAGpB,EAAA,EAAA,UAAA,KAAgB,CACT,EAAM,SAAS,EAAS,CAAW,CAC1C,EAAG,CAAC,CAAW,CAAC,GAEhB,EAAA,EAAA,UAAA,SAAsB,CAChB,EAAM,SAAS,aAAa,EAAM,OAAO,CAC/C,EAAG,CAAC,CAAC,EAaE,CAAC,GAAA,EAXO,EAAA,YAAA,CAAa,GAAkB,CAC5C,EAAS,CAAK,EACd,EAAM,QAAU,GACZ,EAAM,SAAS,aAAa,EAAM,OAAO,EAC7C,EAAM,QAAU,eAAiB,CAC/B,EAAM,QAAU,GAChB,EAAM,QAAU,KAChB,EAAU,QAAQ,CAAK,CACzB,EAAA,GAAyB,CAC3B,EAAG,CAAC,CAEW,CAAM,CACvB,CAaA,SAAS,EAAQ,CAAE,MAAK,SAAQ,WAAU,UAAwB,CAChE,IAAM,GAAA,EAAY,EAAA,MAAA,CAAM,EAClB,EAAgB,EAAI,OAAO,eAC3B,EAAgB,EAAI,OAAO,yBAA2B,IACtD,CAAC,EAAS,GAAc,EAAkB,EAAgB,GAAM,CAChE,IAAM,GAAe,EAAO,EAAI,OAAQ,CAAE,eAAgB,CAAE,CAAC,CACnE,CAAC,EACK,CAAC,EAAS,GAAc,EAAkB,EAAgB,GAAM,CAChE,IAAM,GAAe,EAAO,EAAI,OAAQ,CAAE,wBAAyB,GAAK,IAAM,KAAO,CAAE,CAAC,CAC9F,CAAC,EACK,EAAW,GAAY,EAE7B,OACE,EAAA,EAAA,KAAA,CAAC,KAAD,CAAI,UAAW,EAAO,KAAM,kBAAiB,EAAW,cAAa,EAAI,OAAQ,YAAW,GAAU,IAAA,GAAtG,SAAA,EACE,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAW,EAAO,SAAvB,SAAA,EACE,EAAA,EAAA,IAAA,CAAC,EAAD,CAAc,OAAQ,EAAI,OAAQ,UAAW,EAAO,MAAS,CAAA,GAE7D,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,GAAI,EAAW,UAAW,EAAO,SAAU,MAAO,EAAI,MAAQ,SAAA,EAAI,KAAY,CAAA,GACpF,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAO,OAAQ,cAAa,EAAI,OAAS,SAAA,EAAa,EAAI,OAAc,CAAA,EACxF,EAAI,MAAO,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAO,KAAM,SAAA,MAAU,CAAA,EAAI,MACxD,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,UAAW,EAAO,OAClB,QAAS,EAAI,OAAO,QACV,WACV,aAAY,eAAe,EAAI,QAC/B,MAAM,WACN,SAAW,GAAS,EAAO,EAAI,OAAQ,CAAE,QAAS,CAAK,CAAC,CACzD,CAAA,CACE,IAEJ,EAAI,KAAK,OAAS,GACjB,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAW,EAAO,KACpB,SAAA,EAAI,KAAK,IAAK,IAAQ,EAAA,EAAA,IAAA,CAAC,EAAD,CAAiC,KAAM,EAArB,EAAI,IAAiB,CAAC,CAC5D,CAAA,EACH,EAAI,MACN,EAAA,EAAA,IAAA,CAAC,IAAD,CAAG,UAAW,EAAO,SAAU,SAAA,8EAA+E,CAAA,EAC5G,KAEH,CAAC,EAAI,MAAQ,EAAI,OAAO,SACvB,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAW,EAAO,SAAvB,SAAA,EACE,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,MAAM,eACN,IAAK,EACL,IAAK,IACL,KAAM,EACN,MAAO,EACG,WACV,WAAY,GAAG,EAAQ,GACvB,UAAW,GAAG,EAAQ,kBAAkB,EAAI,SAAW,OAAS,iBAAmB,gBAAgB,eACnG,SAAW,GAAM,EAAW,EAAa,OAAO,EAAE,cAAc,KAAK,CAAC,CAAC,CACxE,CAAA,EACA,EAAI,mBACH,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,MAAM,iBACN,IAAK,GACL,IAAK,IACL,KAAM,EACN,MAAO,EACG,WACV,WAAY,GAAW,IAAM,OAAS,GAAG,EAAQ,GACjD,UAAW,GAAW,IAAM,oBAAsB,qBAAqB,EAAQ,+BAC/E,SAAW,GAAM,EAAW,EAAa,OAAO,EAAE,cAAc,KAAK,EAAG,GAAI,GAAG,CAAC,CACjF,CAAA,EACC,IACD,CACH,CAAA,EAAA,MAEJ,EAAA,EAAA,IAAA,CAAC,IAAD,CAAG,UAAW,EAAO,IAAM,SAAA,EAAI,GAAO,CAAA,EACrC,EAAI,KAAK,OAAS,GACjB,EAAA,EAAA,KAAA,CAAC,UAAD,CAAS,UAAW,EAAO,KAA3B,SAAA,EACE,EAAA,EAAA,IAAA,CAAC,UAAD,CAAA,SAAU,EAAI,KAAK,SAAW,EAAI,cAAgB,GAAG,EAAI,KAAK,OAAO,YAAsB,CAAA,GAC3F,EAAA,EAAA,IAAA,CAAC,KAAD,CAAA,SACG,EAAI,KAAK,IAAK,IAAW,EAAA,EAAA,IAAA,CAAC,KAAD,CAAA,SAAkB,CAAW,EAApB,CAAoB,CAAC,CACtD,CAAA,CACG,CACP,CAAA,EAAA,IACF,GAER,CAyBA,SAAgB,EAAkB,CAAE,OAAM,UAAS,QAAO,UAAS,QAAO,WAAW,GAAO,UAAU,KAAM,SAAQ,UAAkC,CACpJ,IAAM,GAAA,EAAU,EAAA,MAAA,CAAM,EAMhB,EAAO,CAAC,GAAG,EAAe,CAAI,CAAC,CAAC,OAAO,CAAC,EACxC,EAAU,EAAc,CAAI,EAC5B,EAAY,EAAoB,KAAM,GAAM,EAAE,QAAU,EAAK,IAAI,GAAK,KACtE,EAAO,GAAa,EAAoB,GACxC,EAAW,OAAO,EAAK,iBAAoB,UAAY,OAAO,SAAS,EAAK,eAAe,EAAI,EAAK,gBAAkB,KACtH,EAAe,EAAU,EAAoB,KAAM,GAAM,EAAE,QAAU,CAAO,CAAC,EAAE,OAAS,EAAU,KAClG,EAAW,EAAiB,EAAK,KAAM,CAAO,EAC9C,EAAS,GAAS,OAAS,EAAK,KAAM,GAAM,EAAE,SAAW,EAAQ,MAAM,EAAI,KAEjF,OACE,EAAA,EAAA,KAAA,CAAC,UAAD,CAAS,UAAW,EAAO,MAAO,kBAAiB,EAAnD,SAAA,EACE,EAAA,EAAA,KAAA,CAAC,SAAD,CAAQ,UAAW,EAAO,OAA1B,SAAA,EACE,EAAA,EAAA,IAAA,CAAC,KAAD,CAAI,GAAI,EAAS,UAAW,EAAO,MAAO,SAAA,QAAU,CAAA,GACpD,EAAA,EAAA,IAAA,CAAC,IAAD,CAAG,UAAW,EAAO,QAAU,SAAA,EAAQ,QAAY,CAAA,GACnD,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAO,IACrB,SAAA,OAAO,SAAS,KAAK,MAAM,EAAK,SAAS,CAAC,EAAI,YAAY,EAAW,EAAK,UAAW,CAAK,IAAM,2BAC7F,CAAA,CACA,KAER,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAW,EAAO,KAAvB,SAAA,EACE,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,aAAW,cACX,QAAS,EAAoB,IAAK,IAAO,CACvC,MAAO,EAAE,MACT,MAAO,EAAE,MACT,GAAI,EAAiB,EAAE,MAAO,CAAO,EAAI,CAAE,UAAW,GAAG,EAAE,MAAM,oBAAqB,EAAI,CAAC,EAC3F,SAAU,GAAY,IAAY,MAAQ,EAAiB,EAAE,MAAO,CAAO,CAC7E,EAAE,EACF,MAAO,EAAK,KACZ,SAAW,GAAS,CAAM,IAAS,EAAK,MAAQ,CAAC,EAAiB,EAAM,CAAO,GAAG,EAAO,CAAI,CAAG,CACjG,CAAA,GAGD,EAAA,EAAA,IAAA,CAAC,IAAD,CAAG,UAAW,EAAO,SAAW,SAAA,EAAY,EAAK,YAAc,0CAA8C,CAAA,EAC5G,GACC,EAAA,EAAA,IAAA,CAAC,IAAD,CAAG,UAAW,EAAO,SAAU,eAAa,GACzC,SAAA,EACG,2BAA2B,EAAa,0BAA0B,EAAa,yBAC/E,2BAA2B,EAAa,4DAC3C,CAAA,EACD,IACD,IAEJ,GACC,EAAA,EAAA,KAAA,CAAC,IAAD,CAAG,UAAW,EAAO,QAAS,YAAU,SAAxC,SAAA,EACE,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAO,YAAa,SAAA,oBAAwB,CAAA,EAAE,KAC/D,EAAA,EAAA,IAAA,CAAC,SAAD,CAAA,SAAS,GAAQ,OAAU,EAAQ,QAAU,mBAA6B,CAAA,GAC1E,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAO,WACvB,SAAA,OAAO,EAAQ,KAAQ,SAAW,EAAU,EAAQ,IAAK,CAAK,EAAI,IAAW,CAAA,CAC7E,CACD,CAAA,EAAA,KAEH,GAAQ,EAAA,EAAA,IAAA,CAAC,IAAD,CAAG,UAAW,EAAO,MAAO,KAAK,QAAS,SAAA,CAAS,CAAA,EAAI,KAE/D,EAAK,SAAW,GACf,EAAA,EAAA,IAAA,CAAC,IAAD,CAAG,UAAW,EAAO,MAAO,SAAA,0EAA2E,CAAA,GAEvG,EAAA,EAAA,IAAA,CAAC,KAAD,CAAI,UAAW,EAAO,MACnB,SAAA,EAAK,IAAK,IACT,EAAA,EAAA,IAAA,CAAC,EAAD,CAA+B,MAAK,OAAQ,IAAY,EAAI,QAAU,IAAY,OAAkB,WAAkB,QAAS,EAAjH,EAAI,MAA6G,CAChI,CACC,CAAA,GAGN,EAAA,EAAA,KAAA,CAAC,IAAD,CAAG,UAAW,EAAO,SAArB,SAAA,CAA+B,6JAEa,IAAa,KAA+D,yBAAxD,cAAc,KAAK,MAAM,EAAW,GAAM,EAAE,UAAqC,iBAC9I,GACI,GAEb,CAMA,SAAgB,EAAc,CAAE,UAAU,MAA0C,CAAC,EAAG,CACtF,IAAM,EAAS,EAAS,EAAa,CAAE,QAAS,CAAE,CAAC,EAC7C,EAAU,EAAS,EAAoB,CAAE,QAAS,CAAE,CAAC,EACrD,EAAgB,EAAW,CAAW,EACtC,EAAiB,EAAW,CAAkB,EAC9C,EAAO,EAAa,EACpB,CAAC,EAAQ,IAAA,EAAa,EAAA,SAAA,CAA4B,IAAI,EACtD,CAAC,EAAS,IAAA,EAAc,EAAA,SAAA,CAAwB,IAAI,EACpD,CAAC,EAAO,IAAA,EAAY,EAAA,SAAA,CAAwB,IAAI,EAChD,CAAC,EAAO,IAAA,EAAY,EAAA,SAAA,KAAe,KAAK,IAAI,CAAC,GAGnD,EAAA,EAAA,UAAA,KAAgB,CACd,IAAM,MAAmB,EACnB,OAAO,SAAa,KAAe,SAAS,kBAAoB,YACpE,EAAc,EACd,EAAe,EACf,EAAS,KAAK,IAAI,CAAC,EACrB,EACM,EAAQ,OAAO,YAAY,EAAM,CAAc,EAErD,OADA,SAAS,iBAAiB,mBAAoB,CAAI,MACrC,CACX,OAAO,cAAc,CAAK,EAC1B,SAAS,oBAAoB,mBAAoB,CAAI,CACvD,CACF,EAAG,CAAC,EAAe,CAAc,CAAC,EAKlC,IAAM,EAAS,EAAO,KAChB,EAAO,IAAW,CAAC,GAAU,EAAE,KAAK,MAAM,EAAO,SAAS,EAAI,KAAK,MAAM,EAAO,SAAS,IAAM,EAAS,EAExG,GAAA,EAAQ,EAAA,YAAA,CAAY,MAAO,EAAa,EAAgB,IAA+C,CAC3G,EAAW,CAAG,EACd,EAAS,IAAI,EACb,GAAI,CACF,IAAM,EAAO,MAAM,EAAK,IAAI,MAAc,EAAa,CAAM,CAAC,EAC1D,GAAM,EAAU,CAAI,CAC1B,OAAS,EAAK,CACZ,EAAS,EAAqB,CAAG,CAAC,CACpC,QAAU,CACR,EAAW,IAAI,EACf,EAAS,KAAK,IAAI,CAAC,CACrB,CACF,EAAG,CAAC,CAAI,CAAC,EAcT,OAZK,GAaH,EAAA,EAAA,KAAA,CAAA,EAAA,SAAA,CAAA,SAAA,EACE,EAAA,EAAA,IAAA,CAAC,EAAD,CACQ,OACN,QAAS,EAAQ,MAAQ,KAClB,QACE,UACF,QACE,UACT,OAAS,GAAS,KAAK,EAAM,OAAQ,wBAAwB,IAAQ,CAAE,MAAK,CAAC,EAC7E,QAAS,EAAQ,IAAU,KAAK,EAAM,EAAQ,yBAAyB,IAAU,CAAE,SAAQ,OAAQ,CAAM,CAAC,CAC3G,CAAA,GACD,EAAA,EAAA,IAAA,CAAC,EAAD,CAAqB,KAAM,EAAK,OAAO,KAAM,OAAQ,EAAK,OAAO,OAAQ,WAAW,iBAClF,UAAU,yCAAyC,QAAS,EAAK,OAAO,QAAS,WAAY,EAAK,OAAO,UAAa,CAAA,CACxH,CAAA,CAAA,GAxBA,EAAA,EAAA,IAAA,CAAC,UAAD,CAAS,UAAW,EAAO,MAAO,aAAW,SAC1C,SAAA,EAAO,SAAW,SACjB,EAAA,EAAA,KAAA,CAAC,IAAD,CAAG,UAAW,EAAO,MAAO,KAAK,QAAjC,SAAA,CAAyC,uBAAqB,EAAO,OAAO,SAAW,qBAAyB,CAEhH,CAAA,GAAA,EAAA,EAAA,IAAA,CAAC,IAAD,CAAG,UAAW,EAAO,QAAS,SAAA,qBAAsB,CAAA,CAE/C,CAAA,CAoBf"}
@@ -1,2 +1,2 @@
1
- import{a as e,n as t,s as n}from"./index-DbDw9UAs.js";import{D as r,E as i,L as a,P as o,S as s,T as ee,_ as c,c as l,d as te,j as ne,l as re,m as u,n as ie,p as ae,r as oe,t as se,u as d,w as ce}from"./useChartWidth-D9M7kUw7.js";import{c as f,v as p}from"./colors-BZ3a9wFf.js";import{i as m,l as le,t as h}from"./format-DKrNjdwD.js";import{n as g}from"./Swimlane-Cdc4TqDe.js";var _={tile:`_tile_lsnkj_1`,label:`_label_lsnkj_15`,value:`_value_lsnkj_25`,trend:`_trend_lsnkj_36`,meta:`_meta_lsnkj_41`,delta:`_delta_lsnkj_48`,deltaGood:`_deltaGood_lsnkj_54`,deltaBad:`_deltaBad_lsnkj_58`,deltaNeutral:`_deltaNeutral_lsnkj_62`,caption:`_caption_lsnkj_66`},v=t();function y(e){return[e.format?e.format(e.value):m(e.value),e.unit,e.versus].filter(e=>e!==void 0&&e!==``).join(` `)}function b({label:e,value:t,caption:n,delta:r,trend:i,trendLabel:a,describeTrend:o}){let s=r==null||r.goodWhenPositive===void 0||r.value===0?_.deltaNeutral:r.value>0===r.goodWhenPositive?_.deltaGood:_.deltaBad;return(0,v.jsxs)(`div`,{className:_.tile,"data-stat-tile":``,children:[(0,v.jsx)(`span`,{className:_.label,children:e}),(0,v.jsx)(`span`,{className:_.value,children:t}),i?(0,v.jsx)(`span`,{className:_.trend,children:(0,v.jsx)(g,{points:i,width:112,height:24,area:!0,ariaLabel:a??`${e} trend`,describe:o})}):null,r||n?(0,v.jsxs)(`div`,{className:_.meta,children:[r?(0,v.jsx)(`span`,{className:`${_.delta} ${s}`,children:y(r)}):null,n?(0,v.jsx)(`span`,{className:_.caption,children:n}):null]}):null]})}var ue=n(e(),1),x=16,de=26,fe=14;function S(e){let t=new Date(e);return Number.isNaN(t.getTime())?``:t.toLocaleString(`en-US`,{weekday:`short`,hour:`numeric`,minute:`2-digit`})}function C(e){let t=Math.max(0,Math.round(e/6e4));if(t<60)return`${t}m`;let n=Math.floor(t/60);return n<48?t%60?`${n}h ${t%60}m`:`${n}h`:`${Math.round(n/24)}d`}function pe(e,t,n,r,i){let a=t!==null&&Number.isFinite(t)?t:null;if(e.from&&e.from.remaining<=0)return{text:a===null?`Used up — reset time unknown.`:`Used up — resets ${r(a)}.`,severity:`danger`};if(e.from&&i!==void 0&&e.reserveAt!==null&&e.reserveAt<=e.from.t){let e=a===null?`until it resets (reset time unknown)`:`until ${r(a)}`;return{text:`Inside ${i.toLowerCase()} — autonomy has stopped using this window ${e}.`,severity:`warn`}}return a===null?{text:`Reset time unknown — not projecting this window.`,severity:`unknown`}:e.slopePerMs===null?{text:`Not enough readings to project this window yet.`,severity:`unknown`}:e.exhaustAt===null?e.reserveAt===null?{text:`At this pace: about ${n(e.remainingAtReset??0)} left at reset.`,severity:`ok`}:{text:`At this pace: ${i??`reserve`} reached ${r(e.reserveAt)}, ${C(a-e.reserveAt)} before reset.`,severity:`warn`}:{text:`At this pace: runs out ${r(e.exhaustAt)}, ${C(a-e.exhaustAt)} before reset.`,severity:`danger`}}function w({title:e,description:t,caveat:n,status:m,points:g,capacity:_,start:y,resetAt:b,now:C,reserve:w,height:T=200,width:me,formatValue:E,formatTime:D,ariaLabel:he}){let O=E??h,k=D??S,A=(0,ue.useRef)(null),j=se(A,me),M=d(),N=g.filter(e=>s(e.t)).sort((e,t)=>e.t-t.t),ge=N.some(e=>e.remaining!==null),P=m??(N.length===0?{kind:`empty`,message:`No readings in this window yet.`}:ge?{kind:`ready`}:{kind:`unknown`}),F=s(b),I=F?b:null,L=ne(N,I,{reserve:w?.value??null}),R=pe(L,I,O,k,w?.label),z=N.flatMap(e=>e.remaining!==null&&Number.isFinite(e.remaining)?[e.remaining]:[]),B=u(0,Math.max(_,...z,1),{count:4,integer:Number.isInteger(_)&&z.every(e=>Number.isInteger(e)),format:E}),V=B.ticks,_e=V[V.length-1],H=a(B.labels,28,56,M),U=Math.max(40,j-H-fe),W=T-x-de,ve=N.length?N[N.length-1].t:C,G=I??Math.max(C,ve),ye=s(y)?y:N[0]?.t??G,[K,q]=c(ye,G,te,`end`),J=r(K,q,H,H+U),Y=r(0,_e,x+W,x),X=e=>Math.min(q,Math.max(K,e)),Z=le(K,q,D??S,[K,q]),be=ee([{key:`start`,x:H,anchor:`start`,priority:2,variants:Z.map(e=>e(K))},F?{key:`reset`,x:H+U,anchor:`end`,priority:3,variants:Z.map(e=>`Resets ${e(q)}`)}:{key:`end`,x:H+U,anchor:`end`,priority:3,variants:Z.map(e=>e(q))}],{min:H,max:H+U,charPx:ce(M)}),xe=o(N.map(e=>({x:X(e.t),y:e.remaining}))).map(e=>e.map(e=>({x:J(e.x),y:Y(Math.max(0,e.y))}))),Q=``;if(I!==null&&L.from&&L.slopePerMs!==null){let e=L.exhaustAt??I,t=L.exhaustAt===null?L.remainingAtReset??L.from.remaining:0;e>L.from.t&&(Q=i([{x:J(X(L.from.t)),y:Y(L.from.remaining)},{x:J(X(e)),y:Y(Math.max(0,t))}]))}let $=R.severity===`danger`?p(`danger`):R.severity===`warn`?p(`warning`):`var(--text-tertiary)`,Se=he??`${e}: ${L.from?`${O(L.from.remaining)} of ${O(_)} left at ${k(L.from.t)}`:`no readings`}; ${I===null?`reset time unknown`:`resets ${k(I)}`}. ${R.text}`,Ce=[{key:`t`,label:`When`,render:e=>k(e.t)},{key:`r`,label:`Remaining`,numeric:!0,render:e=>e.remaining===null?`—`:O(e.remaining)}],we=[{label:`Remaining`,color:f,kind:`line`},...F?[{label:`Even pace`,color:`var(--text-tertiary)`,kind:`line`}]:[],...Q?[{label:`Projection`,color:$,kind:`line`}]:[]];return(0,v.jsx)(ie,{title:e,description:t,caveat:n,status:P,table:(0,v.jsx)(re,{caption:e,columns:Ce,rows:N,rowKey:e=>String(e.t)}),footer:(0,v.jsxs)(v.Fragment,{children:[(0,v.jsx)(`p`,{className:l.note,"data-severity":R.severity,role:`status`,children:R.text}),(0,v.jsx)(oe,{items:we})]}),children:(0,v.jsx)(`div`,{ref:A,className:l.plotWrap,children:(0,v.jsxs)(`svg`,{className:l.svg,width:j,height:T,viewBox:`0 0 ${j} ${T}`,role:`img`,"aria-label":Se,children:[V.map((e,t)=>(0,v.jsxs)(`g`,{children:[(0,v.jsx)(`line`,{className:l.grid,x1:H,x2:H+U,y1:Y(e),y2:Y(e)}),(0,v.jsx)(`text`,{className:l.tick,x:H-6,y:Y(e),dy:`0.32em`,textAnchor:`end`,children:B.labels[t]})]},e)),(0,v.jsx)(`line`,{className:l.axis,x1:H,x2:H+U,y1:Y(0),y2:Y(0)}),be.map(e=>(0,v.jsx)(`text`,{"data-axis-label":e.key,className:l.tick,x:e.x,y:T-8,textAnchor:e.anchor,children:e.text},e.key)),F?(0,v.jsx)(`path`,{"data-role":`pace`,className:l.reference,d:i([{x:J(K),y:Y(_)},{x:J(q),y:Y(0)}])}):null,w?(0,v.jsxs)(`g`,{"data-role":`reserve`,children:[(0,v.jsx)(`line`,{className:l.reference,x1:H,x2:H+U,y1:Y(w.value),y2:Y(w.value)}),(0,v.jsxs)(`text`,{"data-role":`reserve-label`,className:`${l.tick} ${l.halo}`,x:H+4,y:Y(w.value)-5,textAnchor:`start`,children:[w.label,` · `,O(w.value)]})]}):null,C>K&&C<q?(0,v.jsx)(`line`,{className:l.crosshair,x1:J(C),x2:J(C),y1:x,y2:x+W}):null,xe.map((e,t)=>(0,v.jsxs)(`g`,{"data-role":`remaining`,children:[(0,v.jsx)(`path`,{className:l.wash,fill:f,d:ae(e,e.map(e=>({x:e.x,y:Y(0)})))}),(0,v.jsx)(`path`,{className:l.line,stroke:f,d:i(e)})]},t)),Q?(0,v.jsx)(`path`,{"data-role":`projection`,className:l.projection,stroke:$,d:Q}):null,L.from?(0,v.jsx)(`circle`,{className:l.marker,cx:J(X(L.from.t)),cy:Y(L.from.remaining),r:4,fill:f}):null]})})})}export{b as n,w as t};
2
- //# sourceMappingURL=BurnDown-C1fgcFqo.js.map
1
+ import{a as e,n as t,s as n}from"./index-BVxOlseC.js";import{D as r,E as i,L as a,P as o,S as s,T as ee,_ as c,c as l,d as te,j as ne,l as re,m as u,n as ie,p as ae,r as oe,t as se,u as d,w as ce}from"./useChartWidth-owwodNVz.js";import{c as f,v as p}from"./colors-BZ3a9wFf.js";import{i as m,l as le,t as h}from"./format-DKrNjdwD.js";import{n as g}from"./Swimlane-DGcIcnNA.js";var _={tile:`_tile_lsnkj_1`,label:`_label_lsnkj_15`,value:`_value_lsnkj_25`,trend:`_trend_lsnkj_36`,meta:`_meta_lsnkj_41`,delta:`_delta_lsnkj_48`,deltaGood:`_deltaGood_lsnkj_54`,deltaBad:`_deltaBad_lsnkj_58`,deltaNeutral:`_deltaNeutral_lsnkj_62`,caption:`_caption_lsnkj_66`},v=t();function y(e){return[e.format?e.format(e.value):m(e.value),e.unit,e.versus].filter(e=>e!==void 0&&e!==``).join(` `)}function b({label:e,value:t,caption:n,delta:r,trend:i,trendLabel:a,describeTrend:o}){let s=r==null||r.goodWhenPositive===void 0||r.value===0?_.deltaNeutral:r.value>0===r.goodWhenPositive?_.deltaGood:_.deltaBad;return(0,v.jsxs)(`div`,{className:_.tile,"data-stat-tile":``,children:[(0,v.jsx)(`span`,{className:_.label,children:e}),(0,v.jsx)(`span`,{className:_.value,children:t}),i?(0,v.jsx)(`span`,{className:_.trend,children:(0,v.jsx)(g,{points:i,width:112,height:24,area:!0,ariaLabel:a??`${e} trend`,describe:o})}):null,r||n?(0,v.jsxs)(`div`,{className:_.meta,children:[r?(0,v.jsx)(`span`,{className:`${_.delta} ${s}`,children:y(r)}):null,n?(0,v.jsx)(`span`,{className:_.caption,children:n}):null]}):null]})}var ue=n(e(),1),x=16,de=26,fe=14;function S(e){let t=new Date(e);return Number.isNaN(t.getTime())?``:t.toLocaleString(`en-US`,{weekday:`short`,hour:`numeric`,minute:`2-digit`})}function C(e){let t=Math.max(0,Math.round(e/6e4));if(t<60)return`${t}m`;let n=Math.floor(t/60);return n<48?t%60?`${n}h ${t%60}m`:`${n}h`:`${Math.round(n/24)}d`}function pe(e,t,n,r,i){let a=t!==null&&Number.isFinite(t)?t:null;if(e.from&&e.from.remaining<=0)return{text:a===null?`Used up — reset time unknown.`:`Used up — resets ${r(a)}.`,severity:`danger`};if(e.from&&i!==void 0&&e.reserveAt!==null&&e.reserveAt<=e.from.t){let e=a===null?`until it resets (reset time unknown)`:`until ${r(a)}`;return{text:`Inside ${i.toLowerCase()} — autonomy has stopped using this window ${e}.`,severity:`warn`}}return a===null?{text:`Reset time unknown — not projecting this window.`,severity:`unknown`}:e.slopePerMs===null?{text:`Not enough readings to project this window yet.`,severity:`unknown`}:e.exhaustAt===null?e.reserveAt===null?{text:`At this pace: about ${n(e.remainingAtReset??0)} left at reset.`,severity:`ok`}:{text:`At this pace: ${i??`reserve`} reached ${r(e.reserveAt)}, ${C(a-e.reserveAt)} before reset.`,severity:`warn`}:{text:`At this pace: runs out ${r(e.exhaustAt)}, ${C(a-e.exhaustAt)} before reset.`,severity:`danger`}}function w({title:e,description:t,caveat:n,status:m,points:g,capacity:_,start:y,resetAt:b,now:C,reserve:w,height:T=200,width:me,formatValue:E,formatTime:D,ariaLabel:he}){let O=E??h,k=D??S,A=(0,ue.useRef)(null),j=se(A,me),M=d(),N=g.filter(e=>s(e.t)).sort((e,t)=>e.t-t.t),ge=N.some(e=>e.remaining!==null),P=m??(N.length===0?{kind:`empty`,message:`No readings in this window yet.`}:ge?{kind:`ready`}:{kind:`unknown`}),F=s(b),I=F?b:null,L=ne(N,I,{reserve:w?.value??null}),R=pe(L,I,O,k,w?.label),z=N.flatMap(e=>e.remaining!==null&&Number.isFinite(e.remaining)?[e.remaining]:[]),B=u(0,Math.max(_,...z,1),{count:4,integer:Number.isInteger(_)&&z.every(e=>Number.isInteger(e)),format:E}),V=B.ticks,_e=V[V.length-1],H=a(B.labels,28,56,M),U=Math.max(40,j-H-fe),W=T-x-de,ve=N.length?N[N.length-1].t:C,G=I??Math.max(C,ve),ye=s(y)?y:N[0]?.t??G,[K,q]=c(ye,G,te,`end`),J=r(K,q,H,H+U),Y=r(0,_e,x+W,x),X=e=>Math.min(q,Math.max(K,e)),Z=le(K,q,D??S,[K,q]),be=ee([{key:`start`,x:H,anchor:`start`,priority:2,variants:Z.map(e=>e(K))},F?{key:`reset`,x:H+U,anchor:`end`,priority:3,variants:Z.map(e=>`Resets ${e(q)}`)}:{key:`end`,x:H+U,anchor:`end`,priority:3,variants:Z.map(e=>e(q))}],{min:H,max:H+U,charPx:ce(M)}),xe=o(N.map(e=>({x:X(e.t),y:e.remaining}))).map(e=>e.map(e=>({x:J(e.x),y:Y(Math.max(0,e.y))}))),Q=``;if(I!==null&&L.from&&L.slopePerMs!==null){let e=L.exhaustAt??I,t=L.exhaustAt===null?L.remainingAtReset??L.from.remaining:0;e>L.from.t&&(Q=i([{x:J(X(L.from.t)),y:Y(L.from.remaining)},{x:J(X(e)),y:Y(Math.max(0,t))}]))}let $=R.severity===`danger`?p(`danger`):R.severity===`warn`?p(`warning`):`var(--text-tertiary)`,Se=he??`${e}: ${L.from?`${O(L.from.remaining)} of ${O(_)} left at ${k(L.from.t)}`:`no readings`}; ${I===null?`reset time unknown`:`resets ${k(I)}`}. ${R.text}`,Ce=[{key:`t`,label:`When`,render:e=>k(e.t)},{key:`r`,label:`Remaining`,numeric:!0,render:e=>e.remaining===null?`—`:O(e.remaining)}],we=[{label:`Remaining`,color:f,kind:`line`},...F?[{label:`Even pace`,color:`var(--text-tertiary)`,kind:`line`}]:[],...Q?[{label:`Projection`,color:$,kind:`line`}]:[]];return(0,v.jsx)(ie,{title:e,description:t,caveat:n,status:P,table:(0,v.jsx)(re,{caption:e,columns:Ce,rows:N,rowKey:e=>String(e.t)}),footer:(0,v.jsxs)(v.Fragment,{children:[(0,v.jsx)(`p`,{className:l.note,"data-severity":R.severity,role:`status`,children:R.text}),(0,v.jsx)(oe,{items:we})]}),children:(0,v.jsx)(`div`,{ref:A,className:l.plotWrap,children:(0,v.jsxs)(`svg`,{className:l.svg,width:j,height:T,viewBox:`0 0 ${j} ${T}`,role:`img`,"aria-label":Se,children:[V.map((e,t)=>(0,v.jsxs)(`g`,{children:[(0,v.jsx)(`line`,{className:l.grid,x1:H,x2:H+U,y1:Y(e),y2:Y(e)}),(0,v.jsx)(`text`,{className:l.tick,x:H-6,y:Y(e),dy:`0.32em`,textAnchor:`end`,children:B.labels[t]})]},e)),(0,v.jsx)(`line`,{className:l.axis,x1:H,x2:H+U,y1:Y(0),y2:Y(0)}),be.map(e=>(0,v.jsx)(`text`,{"data-axis-label":e.key,className:l.tick,x:e.x,y:T-8,textAnchor:e.anchor,children:e.text},e.key)),F?(0,v.jsx)(`path`,{"data-role":`pace`,className:l.reference,d:i([{x:J(K),y:Y(_)},{x:J(q),y:Y(0)}])}):null,w?(0,v.jsxs)(`g`,{"data-role":`reserve`,children:[(0,v.jsx)(`line`,{className:l.reference,x1:H,x2:H+U,y1:Y(w.value),y2:Y(w.value)}),(0,v.jsxs)(`text`,{"data-role":`reserve-label`,className:`${l.tick} ${l.halo}`,x:H+4,y:Y(w.value)-5,textAnchor:`start`,children:[w.label,` · `,O(w.value)]})]}):null,C>K&&C<q?(0,v.jsx)(`line`,{className:l.crosshair,x1:J(C),x2:J(C),y1:x,y2:x+W}):null,xe.map((e,t)=>(0,v.jsxs)(`g`,{"data-role":`remaining`,children:[(0,v.jsx)(`path`,{className:l.wash,fill:f,d:ae(e,e.map(e=>({x:e.x,y:Y(0)})))}),(0,v.jsx)(`path`,{className:l.line,stroke:f,d:i(e)})]},t)),Q?(0,v.jsx)(`path`,{"data-role":`projection`,className:l.projection,stroke:$,d:Q}):null,L.from?(0,v.jsx)(`circle`,{className:l.marker,cx:J(X(L.from.t)),cy:Y(L.from.remaining),r:4,fill:f}):null]})})})}export{b as n,w as t};
2
+ //# sourceMappingURL=BurnDown-sFXkUGdB.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"BurnDown-C1fgcFqo.js","names":[],"sources":["../../../../../../src/web-ui/components/charts/StatTile.module.css","../../../../../../src/web-ui/components/charts/StatTile.tsx","../../../../../../src/web-ui/components/charts/BurnDown.tsx"],"sourcesContent":[".tile {\n display: flex;\n flex-direction: column;\n gap: var(--space-1);\n min-width: 0;\n padding: var(--card-pad, var(--space-4));\n border-radius: var(--radius-lg);\n border: 1px solid var(--border-subtle);\n background: var(--bg-surface);\n /* Dark: a 4% white top hairline lifts the KPI row off the canvas; light:\n the token is transparent and this draws nothing. */\n box-shadow: inset 0 1px 0 var(--hairline-lift, transparent);\n}\n\n.label {\n font-family: var(--font-display);\n font-size: var(--text-2xs-size);\n line-height: var(--text-2xs-line);\n color: var(--text-tertiary);\n text-transform: uppercase;\n letter-spacing: var(--tracking-label);\n}\n\n/* KPI number: Plex 600, 24/32, tabular numerals (SPEC-310C §6). */\n.value {\n font-family: var(--font-ui);\n font-size: var(--text-2xl-size);\n line-height: var(--text-2xl-line);\n font-weight: var(--font-weight-semibold);\n font-variant-numeric: tabular-nums;\n color: var(--text-primary);\n overflow-wrap: anywhere;\n}\n\n/* The sparkline sits directly under the number it explains. */\n.trend {\n display: block;\n line-height: 0;\n}\n\n.meta {\n display: flex;\n flex-wrap: wrap;\n align-items: baseline;\n gap: var(--space-1) var(--space-2);\n}\n\n.delta {\n font-size: var(--text-xs-size);\n line-height: var(--text-xs-line);\n font-variant-numeric: tabular-nums;\n}\n\n.deltaGood {\n color: var(--status-success-fg);\n}\n\n.deltaBad {\n color: var(--status-danger-fg);\n}\n\n.deltaNeutral {\n color: var(--text-tertiary);\n}\n\n.caption {\n font-size: var(--text-xs-size);\n line-height: var(--text-xs-line);\n color: var(--text-tertiary);\n}\n","/**\n * components/charts/StatTile.tsx — value + delta + optional sparkline, the\n * figure contract from marks-and-anatomy.md. Use for a single current value\n * (a one-bar bar chart is never the answer — this is). `value` takes a\n * ReactNode (not just a string) so callers can wrap a sourceQuality-bearing\n * field in <Epistemic/> and pass that straight through.\n *\n * V3.10 (SPEC-310C §6 \"StatTile: sparkline goes under the number; deltas show\n * units\"): the 72×24 sparkline used to float top-right, disconnected from the\n * number it explains; it now sits directly under it. A delta reads as a\n * sentence fragment with its unit and its comparison — \"+5 merges vs prior\n * 7d\", never a bare \"-1\". In dark the tile gets the 4% top hairline\n * (`--hairline-lift`, transparent in light) so a KPI row lifts off the canvas.\n */\nimport type { ReactNode } from 'react';\nimport { formatSignedCompact } from './format.js';\nimport { Sparkline } from './Sparkline.js';\nimport styles from './StatTile.module.css';\n\nexport interface StatTileDelta {\n /** Signed raw value, e.g. +12 or -3. */\n value: number;\n /** Whether a positive delta reads as good (green) or bad (red). Omit for\n * a neutral, non-judgmental delta (e.g. \"goals in flight\" — more isn't\n * inherently good or bad). */\n goodWhenPositive?: boolean;\n /** vs which period, e.g. \"vs prior 7d\". */\n versus?: string;\n /** Unit after the number: \"merges\", \"pts\", \"min\". Plural is the caller's call. */\n unit?: string;\n /** Formats the SIGNED value (default: \"+12\" / \"-3\"). Use for percent points, durations, dollars. */\n format?: (signed: number) => string;\n}\n\n/** \"+5 merges vs prior 7d\" — the whole delta as one readable phrase. */\nexport function deltaText(delta: StatTileDelta): string {\n const n = delta.format ? delta.format(delta.value) : formatSignedCompact(delta.value);\n return [n, delta.unit, delta.versus].filter((part) => part !== undefined && part !== '').join(' ');\n}\n\nexport function StatTile({\n label,\n value,\n caption,\n delta,\n trend,\n trendLabel,\n describeTrend,\n}: {\n label: string;\n value: ReactNode;\n caption?: ReactNode;\n delta?: StatTileDelta | null;\n trend?: (number | null)[];\n trendLabel?: string;\n /** Spoken summary formatter for the sparkline (first → latest, range). */\n describeTrend?: (v: number) => string;\n}) {\n const deltaTone =\n delta == null || delta.goodWhenPositive === undefined\n ? styles.deltaNeutral\n : delta.value === 0\n ? styles.deltaNeutral\n : (delta.value > 0) === delta.goodWhenPositive\n ? styles.deltaGood\n : styles.deltaBad;\n\n return (\n <div className={styles.tile} data-stat-tile=\"\">\n <span className={styles.label}>{label}</span>\n <span className={styles.value}>{value}</span>\n {trend ? (\n <span className={styles.trend}>\n <Sparkline points={trend} width={112} height={24} area ariaLabel={trendLabel ?? `${label} trend`} describe={describeTrend} />\n </span>\n ) : null}\n {delta || caption ? (\n <div className={styles.meta}>\n {delta ? <span className={`${styles.delta} ${deltaTone}`}>{deltaText(delta)}</span> : null}\n {caption ? <span className={styles.caption}>{caption}</span> : null}\n </div>\n ) : null}\n </div>\n );\n}\n","/**\n * components/charts/BurnDown.tsx — a quota window burning down to its reset:\n * remaining capacity over time (solid line + wash), the even-pace reference\n * from full at window start to empty at reset (thin dashed), a projection\n * from the recent slope (dashed), an optional reserve line (the headroom kept\n * for interactive use) and the reset marker.\n *\n * The verdict is written in words under the plot — \"At this pace: reserve\n * reached 14:20, 3h 40m before reset\" — so the chart's point never depends on\n * reading slopes. With fewer than two readings it says it cannot project,\n * rather than drawing a guess — and with no plausible reset (0 / NaN /\n * pre-2000) it draws neither pace nor projection and says the reset is\n * unknown, rather than projecting to an invented one.\n */\nimport { useRef } from 'react';\nimport { CHART_SEQUENTIAL, toneColor } from './colors.js';\nimport { ChartFrame, type ChartStatus } from './ChartFrame.js';\nimport { ChartLegend } from './ChartParts.js';\nimport { TableView, type TableColumn } from './TableView.js';\nimport {\n MIN_TIME_SPAN_MS,\n areaPath,\n axisTicks,\n ensureSpan,\n isPlausibleTime,\n labelCharPx,\n layoutAxisLabels,\n linePath,\n linearScale,\n projectBurnDown,\n splitRuns,\n tickGutter,\n type BurnPoint,\n} from './chart-math.js';\nimport { formatCompact, timeLabelLadder } from './format.js';\nimport { useChartWidth } from './useChartWidth.js';\nimport { useTextScale } from './useTextScale.js';\nimport plot from './plot.module.css';\n\nexport interface BurnDownProps {\n title: string;\n description?: string;\n caveat?: string;\n status?: ChartStatus;\n points: BurnPoint[];\n /** Full capacity of the window (e.g. 100 for percent). */\n capacity: number;\n /** Window start and reset, epoch ms. */\n start: number;\n resetAt: number;\n now: number;\n /** Capacity to keep in reserve (same units as `remaining`). */\n reserve?: { value: number; label: string };\n height?: number;\n width?: number;\n formatValue?: (v: number) => string;\n formatTime?: (ms: number) => string;\n ariaLabel?: string;\n}\n\nconst PAD_T = 16;\nconst PAD_B = 26;\nconst PAD_R = 14;\n\nfunction defaultFormatTime(ms: number): string {\n const d = new Date(ms);\n return Number.isNaN(d.getTime()) ? '' : d.toLocaleString('en-US', { weekday: 'short', hour: 'numeric', minute: '2-digit' });\n}\n\nexport function formatLead(ms: number): string {\n const m = Math.max(0, Math.round(ms / 60_000));\n if (m < 60) return `${m}m`;\n const h = Math.floor(m / 60);\n if (h < 48) return m % 60 ? `${h}h ${m % 60}m` : `${h}h`;\n return `${Math.round(h / 24)}d`;\n}\n\n/**\n * The verdict in words. `resetAt` null (or non-finite) is an UNKNOWN reset:\n * what the window has already crossed is still said, but nothing is\n * projected — \"about 40% left at reset\" needs a reset (V3.10.1 review: an\n * epoch-0 reset printed a green verdict for a seat burning 10%/h, and a NaN\n * one printed \"about NaN% left at reset\").\n */\nexport function burnVerdict(\n projection: ReturnType<typeof projectBurnDown>,\n resetAt: number | null,\n formatValue: (v: number) => string,\n formatTime: (ms: number) => string,\n reserveLabel?: string,\n): { text: string; severity: 'ok' | 'warn' | 'danger' | 'unknown' } {\n const reset = resetAt !== null && Number.isFinite(resetAt) ? resetAt : null;\n // Already past a line: say where it IS, not a \"projection\" to a moment\n // that has passed (a used-up seat is not \"running out at 3:02\").\n if (projection.from && projection.from.remaining <= 0) {\n return { text: reset === null ? 'Used up — reset time unknown.' : `Used up — resets ${formatTime(reset)}.`, severity: 'danger' };\n }\n if (projection.from && reserveLabel !== undefined && projection.reserveAt !== null && projection.reserveAt <= projection.from.t) {\n const until = reset === null ? 'until it resets (reset time unknown)' : `until ${formatTime(reset)}`;\n return { text: `Inside ${reserveLabel.toLowerCase()} — autonomy has stopped using this window ${until}.`, severity: 'warn' };\n }\n if (reset === null) return { text: 'Reset time unknown — not projecting this window.', severity: 'unknown' };\n if (projection.slopePerMs === null) return { text: 'Not enough readings to project this window yet.', severity: 'unknown' };\n if (projection.exhaustAt !== null) {\n return {\n text: `At this pace: runs out ${formatTime(projection.exhaustAt)}, ${formatLead(reset - projection.exhaustAt)} before reset.`,\n severity: 'danger',\n };\n }\n if (projection.reserveAt !== null) {\n return {\n text: `At this pace: ${reserveLabel ?? 'reserve'} reached ${formatTime(projection.reserveAt)}, ${formatLead(reset - projection.reserveAt)} before reset.`,\n severity: 'warn',\n };\n }\n return {\n text: `At this pace: about ${formatValue(projection.remainingAtReset ?? 0)} left at reset.`,\n severity: 'ok',\n };\n}\n\nexport function BurnDown({\n title,\n description,\n caveat,\n status,\n points,\n capacity,\n start,\n resetAt,\n now,\n reserve,\n height = 200,\n width: fixedWidth,\n formatValue: formatValueProp,\n formatTime: formatTimeProp,\n ariaLabel,\n}: BurnDownProps) {\n const formatValue = formatValueProp ?? formatCompact;\n const formatTime = formatTimeProp ?? defaultFormatTime;\n const wrapRef = useRef<HTMLDivElement>(null);\n const width = useChartWidth(wrapRef, fixedWidth);\n const textScale = useTextScale();\n // A reading stamped 0 / NaN / pre-2000 is a null timestamp that leaked\n // through: it is not on this window's time axis, and it would drag both\n // the axis and the projection's slope back to 1970.\n const sorted = points.filter((p) => isPlausibleTime(p.t)).sort((a, b) => a.t - b.t);\n const anyKnown = sorted.some((p) => p.remaining !== null);\n const resolvedStatus: ChartStatus = status ?? (sorted.length === 0 ? { kind: 'empty', message: 'No readings in this window yet.' } : anyKnown ? { kind: 'ready' } : { kind: 'unknown' });\n\n // A reset of 0 / NaN / pre-2000 is a null that leaked through (an epoch-0\n // machine reset parses as a finite 0). It is UNKNOWN, not a moment: the\n // axis ends at the latest reading or now with no \"Resets\" on it, no even\n // pace or projection is drawn toward it, and the verdict says the reset is\n // unknown instead of inventing one (V3.10.1 review).\n const resetKnown = isPlausibleTime(resetAt);\n const reset = resetKnown ? resetAt : null;\n const projection = projectBurnDown(sorted, reset, { reserve: reserve?.value ?? null });\n const verdict = burnVerdict(projection, reset, formatValue, formatTime, reserve?.label);\n\n // Always 0 → capacity (100 for percent seats), so sibling cards share one\n // scale; widened only if a reading overshoots, never clipped.\n const known = sorted.flatMap((p) => (p.remaining !== null && Number.isFinite(p.remaining) ? [p.remaining] : []));\n const yAxis = axisTicks(0, Math.max(capacity, ...known, 1), {\n count: 4,\n integer: Number.isInteger(capacity) && known.every((v) => Number.isInteger(v)),\n format: formatValueProp,\n });\n const ticks = yAxis.ticks;\n const top = ticks[ticks.length - 1]!;\n const padL = tickGutter(yAxis.labels, 28, 56, textScale);\n const plotW = Math.max(40, width - padL - PAD_R);\n const plotH = height - PAD_T - PAD_B;\n // The window runs start → reset. An implausible bound (0 / NaN) falls back\n // to the readings; a degenerate one widens to MIN_TIME_SPAN_MS, keeping the\n // right edge where it is.\n const lastT = sorted.length ? sorted[sorted.length - 1]!.t : now;\n const rawEnd = reset ?? Math.max(now, lastT);\n const rawStart = isPlausibleTime(start) ? start : sorted[0]?.t ?? rawEnd;\n const [x0, xEnd] = ensureSpan(rawStart, rawEnd, MIN_TIME_SPAN_MS, 'end');\n const xs = linearScale(x0, xEnd, padL, padL + plotW);\n const ys = linearScale(0, top, PAD_T + plotH, PAD_T);\n const clampX = (t: number) => Math.min(xEnd, Math.max(x0, t));\n\n // x labels: the reset marker outranks the window start. Both walk the same\n // detail ladder (the caller's format → \"Fri 11:46 PM\" → \"Sep 18\"; clock\n // time only inside one day) until they fit side by side; if even the\n // shortest pair collides, the start is dropped rather than overprinted.\n // Widths are budgeted at the operator's Display size. With no known reset\n // the right edge is only the latest reading / now, and says just its time.\n const ladder = timeLabelLadder(x0, xEnd, formatTimeProp ?? defaultFormatTime, [x0, xEnd]);\n const xLabels = layoutAxisLabels(\n [\n { key: 'start', x: padL, anchor: 'start', priority: 2, variants: ladder.map((f) => f(x0)) },\n resetKnown\n ? { key: 'reset', x: padL + plotW, anchor: 'end', priority: 3, variants: ladder.map((f) => `Resets ${f(xEnd)}`) }\n : { key: 'end', x: padL + plotW, anchor: 'end', priority: 3, variants: ladder.map((f) => f(xEnd)) },\n ],\n { min: padL, max: padL + plotW, charPx: labelCharPx(textScale) },\n );\n\n const runs = splitRuns(sorted.map((p) => ({ x: clampX(p.t), y: p.remaining })))\n .map((run) => run.map((p) => ({ x: xs(p.x), y: ys(Math.max(0, p.y)) })));\n\n let projectionPath = '';\n if (reset !== null && projection.from && projection.slopePerMs !== null) {\n const endT = projection.exhaustAt ?? reset;\n const endR = projection.exhaustAt !== null ? 0 : projection.remainingAtReset ?? projection.from.remaining;\n if (endT > projection.from.t) {\n projectionPath = linePath([\n { x: xs(clampX(projection.from.t)), y: ys(projection.from.remaining) },\n { x: xs(clampX(endT)), y: ys(Math.max(0, endR)) },\n ]);\n }\n }\n const projectionColor = verdict.severity === 'danger' ? toneColor('danger') : verdict.severity === 'warn' ? toneColor('warning') : 'var(--text-tertiary)';\n\n const summary = ariaLabel ?? `${title}: ${projection.from ? `${formatValue(projection.from.remaining)} of ${formatValue(capacity)} left at ${formatTime(projection.from.t)}` : 'no readings'}; ${reset === null ? 'reset time unknown' : `resets ${formatTime(reset)}`}. ${verdict.text}`;\n\n const columns: TableColumn<BurnPoint>[] = [\n { key: 't', label: 'When', render: (p) => formatTime(p.t) },\n { key: 'r', label: 'Remaining', numeric: true, render: (p) => (p.remaining === null ? '—' : formatValue(p.remaining)) },\n ];\n\n const legendItems = [\n { label: 'Remaining', color: CHART_SEQUENTIAL, kind: 'line' as const },\n // Even pace runs from full at the window's start to empty AT RESET: with\n // no reset there is no pace to draw.\n ...(resetKnown ? [{ label: 'Even pace', color: 'var(--text-tertiary)', kind: 'line' as const }] : []),\n ...(projectionPath ? [{ label: 'Projection', color: projectionColor, kind: 'line' as const }] : []),\n ];\n\n return (\n <ChartFrame\n title={title}\n description={description}\n caveat={caveat}\n status={resolvedStatus}\n table={<TableView caption={title} columns={columns} rows={sorted} rowKey={(p) => String(p.t)} />}\n footer={\n <>\n <p className={plot.note} data-severity={verdict.severity} role=\"status\">{verdict.text}</p>\n <ChartLegend items={legendItems} />\n </>\n }\n >\n <div ref={wrapRef} className={plot.plotWrap}>\n <svg className={plot.svg} width={width} height={height} viewBox={`0 0 ${width} ${height}`} role=\"img\" aria-label={summary}>\n {ticks.map((t, i) => (\n <g key={t}>\n <line className={plot.grid} x1={padL} x2={padL + plotW} y1={ys(t)} y2={ys(t)} />\n <text className={plot.tick} x={padL - 6} y={ys(t)} dy=\"0.32em\" textAnchor=\"end\">{yAxis.labels[i]}</text>\n </g>\n ))}\n <line className={plot.axis} x1={padL} x2={padL + plotW} y1={ys(0)} y2={ys(0)} />\n {xLabels.map((l) => (\n <text key={l.key} data-axis-label={l.key} className={plot.tick} x={l.x} y={height - 8} textAnchor={l.anchor}>{l.text}</text>\n ))}\n\n {resetKnown ? (\n <path data-role=\"pace\" className={plot.reference} d={linePath([{ x: xs(x0), y: ys(capacity) }, { x: xs(xEnd), y: ys(0) }])} />\n ) : null}\n {reserve ? (\n <g data-role=\"reserve\">\n <line className={plot.reference} x1={padL} x2={padL + plotW} y1={ys(reserve.value)} y2={ys(reserve.value)} />\n {/* Above-left of the line, over a surface halo (SPEC-310C §6): the\n window's start is the one place the remaining line is always\n high, and the projection only ever runs to the right, so the\n label never sits on the data. */}\n <text data-role=\"reserve-label\" className={`${plot.tick} ${plot.halo}`} x={padL + 4} y={ys(reserve.value) - 5} textAnchor=\"start\">\n {reserve.label} · {formatValue(reserve.value)}\n </text>\n </g>\n ) : null}\n {now > x0 && now < xEnd ? (\n <line className={plot.crosshair} x1={xs(now)} x2={xs(now)} y1={PAD_T} y2={PAD_T + plotH} />\n ) : null}\n {runs.map((run, i) => (\n <g key={i} data-role=\"remaining\">\n <path className={plot.wash} fill={CHART_SEQUENTIAL} d={areaPath(run, run.map((p) => ({ x: p.x, y: ys(0) })))} />\n <path className={plot.line} stroke={CHART_SEQUENTIAL} d={linePath(run)} />\n </g>\n ))}\n {projectionPath ? (\n <path data-role=\"projection\" className={plot.projection} stroke={projectionColor} d={projectionPath} />\n ) : null}\n {projection.from ? (\n <circle className={plot.marker} cx={xs(clampX(projection.from.t))} cy={ys(projection.from.remaining)} r={4} fill={CHART_SEQUENTIAL} />\n ) : null}\n </svg>\n </div>\n </ChartFrame>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"BurnDown-sFXkUGdB.js","names":[],"sources":["../../../../../../src/web-ui/components/charts/StatTile.module.css","../../../../../../src/web-ui/components/charts/StatTile.tsx","../../../../../../src/web-ui/components/charts/BurnDown.tsx"],"sourcesContent":[".tile {\n display: flex;\n flex-direction: column;\n gap: var(--space-1);\n min-width: 0;\n padding: var(--card-pad, var(--space-4));\n border-radius: var(--radius-lg);\n border: 1px solid var(--border-subtle);\n background: var(--bg-surface);\n /* Dark: a 4% white top hairline lifts the KPI row off the canvas; light:\n the token is transparent and this draws nothing. */\n box-shadow: inset 0 1px 0 var(--hairline-lift, transparent);\n}\n\n.label {\n font-family: var(--font-display);\n font-size: var(--text-2xs-size);\n line-height: var(--text-2xs-line);\n color: var(--text-tertiary);\n text-transform: uppercase;\n letter-spacing: var(--tracking-label);\n}\n\n/* KPI number: Plex 600, 24/32, tabular numerals (SPEC-310C §6). */\n.value {\n font-family: var(--font-ui);\n font-size: var(--text-2xl-size);\n line-height: var(--text-2xl-line);\n font-weight: var(--font-weight-semibold);\n font-variant-numeric: tabular-nums;\n color: var(--text-primary);\n overflow-wrap: anywhere;\n}\n\n/* The sparkline sits directly under the number it explains. */\n.trend {\n display: block;\n line-height: 0;\n}\n\n.meta {\n display: flex;\n flex-wrap: wrap;\n align-items: baseline;\n gap: var(--space-1) var(--space-2);\n}\n\n.delta {\n font-size: var(--text-xs-size);\n line-height: var(--text-xs-line);\n font-variant-numeric: tabular-nums;\n}\n\n.deltaGood {\n color: var(--status-success-fg);\n}\n\n.deltaBad {\n color: var(--status-danger-fg);\n}\n\n.deltaNeutral {\n color: var(--text-tertiary);\n}\n\n.caption {\n font-size: var(--text-xs-size);\n line-height: var(--text-xs-line);\n color: var(--text-tertiary);\n}\n","/**\n * components/charts/StatTile.tsx — value + delta + optional sparkline, the\n * figure contract from marks-and-anatomy.md. Use for a single current value\n * (a one-bar bar chart is never the answer — this is). `value` takes a\n * ReactNode (not just a string) so callers can wrap a sourceQuality-bearing\n * field in <Epistemic/> and pass that straight through.\n *\n * V3.10 (SPEC-310C §6 \"StatTile: sparkline goes under the number; deltas show\n * units\"): the 72×24 sparkline used to float top-right, disconnected from the\n * number it explains; it now sits directly under it. A delta reads as a\n * sentence fragment with its unit and its comparison — \"+5 merges vs prior\n * 7d\", never a bare \"-1\". In dark the tile gets the 4% top hairline\n * (`--hairline-lift`, transparent in light) so a KPI row lifts off the canvas.\n */\nimport type { ReactNode } from 'react';\nimport { formatSignedCompact } from './format.js';\nimport { Sparkline } from './Sparkline.js';\nimport styles from './StatTile.module.css';\n\nexport interface StatTileDelta {\n /** Signed raw value, e.g. +12 or -3. */\n value: number;\n /** Whether a positive delta reads as good (green) or bad (red). Omit for\n * a neutral, non-judgmental delta (e.g. \"goals in flight\" — more isn't\n * inherently good or bad). */\n goodWhenPositive?: boolean;\n /** vs which period, e.g. \"vs prior 7d\". */\n versus?: string;\n /** Unit after the number: \"merges\", \"pts\", \"min\". Plural is the caller's call. */\n unit?: string;\n /** Formats the SIGNED value (default: \"+12\" / \"-3\"). Use for percent points, durations, dollars. */\n format?: (signed: number) => string;\n}\n\n/** \"+5 merges vs prior 7d\" — the whole delta as one readable phrase. */\nexport function deltaText(delta: StatTileDelta): string {\n const n = delta.format ? delta.format(delta.value) : formatSignedCompact(delta.value);\n return [n, delta.unit, delta.versus].filter((part) => part !== undefined && part !== '').join(' ');\n}\n\nexport function StatTile({\n label,\n value,\n caption,\n delta,\n trend,\n trendLabel,\n describeTrend,\n}: {\n label: string;\n value: ReactNode;\n caption?: ReactNode;\n delta?: StatTileDelta | null;\n trend?: (number | null)[];\n trendLabel?: string;\n /** Spoken summary formatter for the sparkline (first → latest, range). */\n describeTrend?: (v: number) => string;\n}) {\n const deltaTone =\n delta == null || delta.goodWhenPositive === undefined\n ? styles.deltaNeutral\n : delta.value === 0\n ? styles.deltaNeutral\n : (delta.value > 0) === delta.goodWhenPositive\n ? styles.deltaGood\n : styles.deltaBad;\n\n return (\n <div className={styles.tile} data-stat-tile=\"\">\n <span className={styles.label}>{label}</span>\n <span className={styles.value}>{value}</span>\n {trend ? (\n <span className={styles.trend}>\n <Sparkline points={trend} width={112} height={24} area ariaLabel={trendLabel ?? `${label} trend`} describe={describeTrend} />\n </span>\n ) : null}\n {delta || caption ? (\n <div className={styles.meta}>\n {delta ? <span className={`${styles.delta} ${deltaTone}`}>{deltaText(delta)}</span> : null}\n {caption ? <span className={styles.caption}>{caption}</span> : null}\n </div>\n ) : null}\n </div>\n );\n}\n","/**\n * components/charts/BurnDown.tsx — a quota window burning down to its reset:\n * remaining capacity over time (solid line + wash), the even-pace reference\n * from full at window start to empty at reset (thin dashed), a projection\n * from the recent slope (dashed), an optional reserve line (the headroom kept\n * for interactive use) and the reset marker.\n *\n * The verdict is written in words under the plot — \"At this pace: reserve\n * reached 14:20, 3h 40m before reset\" — so the chart's point never depends on\n * reading slopes. With fewer than two readings it says it cannot project,\n * rather than drawing a guess — and with no plausible reset (0 / NaN /\n * pre-2000) it draws neither pace nor projection and says the reset is\n * unknown, rather than projecting to an invented one.\n */\nimport { useRef } from 'react';\nimport { CHART_SEQUENTIAL, toneColor } from './colors.js';\nimport { ChartFrame, type ChartStatus } from './ChartFrame.js';\nimport { ChartLegend } from './ChartParts.js';\nimport { TableView, type TableColumn } from './TableView.js';\nimport {\n MIN_TIME_SPAN_MS,\n areaPath,\n axisTicks,\n ensureSpan,\n isPlausibleTime,\n labelCharPx,\n layoutAxisLabels,\n linePath,\n linearScale,\n projectBurnDown,\n splitRuns,\n tickGutter,\n type BurnPoint,\n} from './chart-math.js';\nimport { formatCompact, timeLabelLadder } from './format.js';\nimport { useChartWidth } from './useChartWidth.js';\nimport { useTextScale } from './useTextScale.js';\nimport plot from './plot.module.css';\n\nexport interface BurnDownProps {\n title: string;\n description?: string;\n caveat?: string;\n status?: ChartStatus;\n points: BurnPoint[];\n /** Full capacity of the window (e.g. 100 for percent). */\n capacity: number;\n /** Window start and reset, epoch ms. */\n start: number;\n resetAt: number;\n now: number;\n /** Capacity to keep in reserve (same units as `remaining`). */\n reserve?: { value: number; label: string };\n height?: number;\n width?: number;\n formatValue?: (v: number) => string;\n formatTime?: (ms: number) => string;\n ariaLabel?: string;\n}\n\nconst PAD_T = 16;\nconst PAD_B = 26;\nconst PAD_R = 14;\n\nfunction defaultFormatTime(ms: number): string {\n const d = new Date(ms);\n return Number.isNaN(d.getTime()) ? '' : d.toLocaleString('en-US', { weekday: 'short', hour: 'numeric', minute: '2-digit' });\n}\n\nexport function formatLead(ms: number): string {\n const m = Math.max(0, Math.round(ms / 60_000));\n if (m < 60) return `${m}m`;\n const h = Math.floor(m / 60);\n if (h < 48) return m % 60 ? `${h}h ${m % 60}m` : `${h}h`;\n return `${Math.round(h / 24)}d`;\n}\n\n/**\n * The verdict in words. `resetAt` null (or non-finite) is an UNKNOWN reset:\n * what the window has already crossed is still said, but nothing is\n * projected — \"about 40% left at reset\" needs a reset (V3.10.1 review: an\n * epoch-0 reset printed a green verdict for a seat burning 10%/h, and a NaN\n * one printed \"about NaN% left at reset\").\n */\nexport function burnVerdict(\n projection: ReturnType<typeof projectBurnDown>,\n resetAt: number | null,\n formatValue: (v: number) => string,\n formatTime: (ms: number) => string,\n reserveLabel?: string,\n): { text: string; severity: 'ok' | 'warn' | 'danger' | 'unknown' } {\n const reset = resetAt !== null && Number.isFinite(resetAt) ? resetAt : null;\n // Already past a line: say where it IS, not a \"projection\" to a moment\n // that has passed (a used-up seat is not \"running out at 3:02\").\n if (projection.from && projection.from.remaining <= 0) {\n return { text: reset === null ? 'Used up — reset time unknown.' : `Used up — resets ${formatTime(reset)}.`, severity: 'danger' };\n }\n if (projection.from && reserveLabel !== undefined && projection.reserveAt !== null && projection.reserveAt <= projection.from.t) {\n const until = reset === null ? 'until it resets (reset time unknown)' : `until ${formatTime(reset)}`;\n return { text: `Inside ${reserveLabel.toLowerCase()} — autonomy has stopped using this window ${until}.`, severity: 'warn' };\n }\n if (reset === null) return { text: 'Reset time unknown — not projecting this window.', severity: 'unknown' };\n if (projection.slopePerMs === null) return { text: 'Not enough readings to project this window yet.', severity: 'unknown' };\n if (projection.exhaustAt !== null) {\n return {\n text: `At this pace: runs out ${formatTime(projection.exhaustAt)}, ${formatLead(reset - projection.exhaustAt)} before reset.`,\n severity: 'danger',\n };\n }\n if (projection.reserveAt !== null) {\n return {\n text: `At this pace: ${reserveLabel ?? 'reserve'} reached ${formatTime(projection.reserveAt)}, ${formatLead(reset - projection.reserveAt)} before reset.`,\n severity: 'warn',\n };\n }\n return {\n text: `At this pace: about ${formatValue(projection.remainingAtReset ?? 0)} left at reset.`,\n severity: 'ok',\n };\n}\n\nexport function BurnDown({\n title,\n description,\n caveat,\n status,\n points,\n capacity,\n start,\n resetAt,\n now,\n reserve,\n height = 200,\n width: fixedWidth,\n formatValue: formatValueProp,\n formatTime: formatTimeProp,\n ariaLabel,\n}: BurnDownProps) {\n const formatValue = formatValueProp ?? formatCompact;\n const formatTime = formatTimeProp ?? defaultFormatTime;\n const wrapRef = useRef<HTMLDivElement>(null);\n const width = useChartWidth(wrapRef, fixedWidth);\n const textScale = useTextScale();\n // A reading stamped 0 / NaN / pre-2000 is a null timestamp that leaked\n // through: it is not on this window's time axis, and it would drag both\n // the axis and the projection's slope back to 1970.\n const sorted = points.filter((p) => isPlausibleTime(p.t)).sort((a, b) => a.t - b.t);\n const anyKnown = sorted.some((p) => p.remaining !== null);\n const resolvedStatus: ChartStatus = status ?? (sorted.length === 0 ? { kind: 'empty', message: 'No readings in this window yet.' } : anyKnown ? { kind: 'ready' } : { kind: 'unknown' });\n\n // A reset of 0 / NaN / pre-2000 is a null that leaked through (an epoch-0\n // machine reset parses as a finite 0). It is UNKNOWN, not a moment: the\n // axis ends at the latest reading or now with no \"Resets\" on it, no even\n // pace or projection is drawn toward it, and the verdict says the reset is\n // unknown instead of inventing one (V3.10.1 review).\n const resetKnown = isPlausibleTime(resetAt);\n const reset = resetKnown ? resetAt : null;\n const projection = projectBurnDown(sorted, reset, { reserve: reserve?.value ?? null });\n const verdict = burnVerdict(projection, reset, formatValue, formatTime, reserve?.label);\n\n // Always 0 → capacity (100 for percent seats), so sibling cards share one\n // scale; widened only if a reading overshoots, never clipped.\n const known = sorted.flatMap((p) => (p.remaining !== null && Number.isFinite(p.remaining) ? [p.remaining] : []));\n const yAxis = axisTicks(0, Math.max(capacity, ...known, 1), {\n count: 4,\n integer: Number.isInteger(capacity) && known.every((v) => Number.isInteger(v)),\n format: formatValueProp,\n });\n const ticks = yAxis.ticks;\n const top = ticks[ticks.length - 1]!;\n const padL = tickGutter(yAxis.labels, 28, 56, textScale);\n const plotW = Math.max(40, width - padL - PAD_R);\n const plotH = height - PAD_T - PAD_B;\n // The window runs start → reset. An implausible bound (0 / NaN) falls back\n // to the readings; a degenerate one widens to MIN_TIME_SPAN_MS, keeping the\n // right edge where it is.\n const lastT = sorted.length ? sorted[sorted.length - 1]!.t : now;\n const rawEnd = reset ?? Math.max(now, lastT);\n const rawStart = isPlausibleTime(start) ? start : sorted[0]?.t ?? rawEnd;\n const [x0, xEnd] = ensureSpan(rawStart, rawEnd, MIN_TIME_SPAN_MS, 'end');\n const xs = linearScale(x0, xEnd, padL, padL + plotW);\n const ys = linearScale(0, top, PAD_T + plotH, PAD_T);\n const clampX = (t: number) => Math.min(xEnd, Math.max(x0, t));\n\n // x labels: the reset marker outranks the window start. Both walk the same\n // detail ladder (the caller's format → \"Fri 11:46 PM\" → \"Sep 18\"; clock\n // time only inside one day) until they fit side by side; if even the\n // shortest pair collides, the start is dropped rather than overprinted.\n // Widths are budgeted at the operator's Display size. With no known reset\n // the right edge is only the latest reading / now, and says just its time.\n const ladder = timeLabelLadder(x0, xEnd, formatTimeProp ?? defaultFormatTime, [x0, xEnd]);\n const xLabels = layoutAxisLabels(\n [\n { key: 'start', x: padL, anchor: 'start', priority: 2, variants: ladder.map((f) => f(x0)) },\n resetKnown\n ? { key: 'reset', x: padL + plotW, anchor: 'end', priority: 3, variants: ladder.map((f) => `Resets ${f(xEnd)}`) }\n : { key: 'end', x: padL + plotW, anchor: 'end', priority: 3, variants: ladder.map((f) => f(xEnd)) },\n ],\n { min: padL, max: padL + plotW, charPx: labelCharPx(textScale) },\n );\n\n const runs = splitRuns(sorted.map((p) => ({ x: clampX(p.t), y: p.remaining })))\n .map((run) => run.map((p) => ({ x: xs(p.x), y: ys(Math.max(0, p.y)) })));\n\n let projectionPath = '';\n if (reset !== null && projection.from && projection.slopePerMs !== null) {\n const endT = projection.exhaustAt ?? reset;\n const endR = projection.exhaustAt !== null ? 0 : projection.remainingAtReset ?? projection.from.remaining;\n if (endT > projection.from.t) {\n projectionPath = linePath([\n { x: xs(clampX(projection.from.t)), y: ys(projection.from.remaining) },\n { x: xs(clampX(endT)), y: ys(Math.max(0, endR)) },\n ]);\n }\n }\n const projectionColor = verdict.severity === 'danger' ? toneColor('danger') : verdict.severity === 'warn' ? toneColor('warning') : 'var(--text-tertiary)';\n\n const summary = ariaLabel ?? `${title}: ${projection.from ? `${formatValue(projection.from.remaining)} of ${formatValue(capacity)} left at ${formatTime(projection.from.t)}` : 'no readings'}; ${reset === null ? 'reset time unknown' : `resets ${formatTime(reset)}`}. ${verdict.text}`;\n\n const columns: TableColumn<BurnPoint>[] = [\n { key: 't', label: 'When', render: (p) => formatTime(p.t) },\n { key: 'r', label: 'Remaining', numeric: true, render: (p) => (p.remaining === null ? '—' : formatValue(p.remaining)) },\n ];\n\n const legendItems = [\n { label: 'Remaining', color: CHART_SEQUENTIAL, kind: 'line' as const },\n // Even pace runs from full at the window's start to empty AT RESET: with\n // no reset there is no pace to draw.\n ...(resetKnown ? [{ label: 'Even pace', color: 'var(--text-tertiary)', kind: 'line' as const }] : []),\n ...(projectionPath ? [{ label: 'Projection', color: projectionColor, kind: 'line' as const }] : []),\n ];\n\n return (\n <ChartFrame\n title={title}\n description={description}\n caveat={caveat}\n status={resolvedStatus}\n table={<TableView caption={title} columns={columns} rows={sorted} rowKey={(p) => String(p.t)} />}\n footer={\n <>\n <p className={plot.note} data-severity={verdict.severity} role=\"status\">{verdict.text}</p>\n <ChartLegend items={legendItems} />\n </>\n }\n >\n <div ref={wrapRef} className={plot.plotWrap}>\n <svg className={plot.svg} width={width} height={height} viewBox={`0 0 ${width} ${height}`} role=\"img\" aria-label={summary}>\n {ticks.map((t, i) => (\n <g key={t}>\n <line className={plot.grid} x1={padL} x2={padL + plotW} y1={ys(t)} y2={ys(t)} />\n <text className={plot.tick} x={padL - 6} y={ys(t)} dy=\"0.32em\" textAnchor=\"end\">{yAxis.labels[i]}</text>\n </g>\n ))}\n <line className={plot.axis} x1={padL} x2={padL + plotW} y1={ys(0)} y2={ys(0)} />\n {xLabels.map((l) => (\n <text key={l.key} data-axis-label={l.key} className={plot.tick} x={l.x} y={height - 8} textAnchor={l.anchor}>{l.text}</text>\n ))}\n\n {resetKnown ? (\n <path data-role=\"pace\" className={plot.reference} d={linePath([{ x: xs(x0), y: ys(capacity) }, { x: xs(xEnd), y: ys(0) }])} />\n ) : null}\n {reserve ? (\n <g data-role=\"reserve\">\n <line className={plot.reference} x1={padL} x2={padL + plotW} y1={ys(reserve.value)} y2={ys(reserve.value)} />\n {/* Above-left of the line, over a surface halo (SPEC-310C §6): the\n window's start is the one place the remaining line is always\n high, and the projection only ever runs to the right, so the\n label never sits on the data. */}\n <text data-role=\"reserve-label\" className={`${plot.tick} ${plot.halo}`} x={padL + 4} y={ys(reserve.value) - 5} textAnchor=\"start\">\n {reserve.label} · {formatValue(reserve.value)}\n </text>\n </g>\n ) : null}\n {now > x0 && now < xEnd ? (\n <line className={plot.crosshair} x1={xs(now)} x2={xs(now)} y1={PAD_T} y2={PAD_T + plotH} />\n ) : null}\n {runs.map((run, i) => (\n <g key={i} data-role=\"remaining\">\n <path className={plot.wash} fill={CHART_SEQUENTIAL} d={areaPath(run, run.map((p) => ({ x: p.x, y: ys(0) })))} />\n <path className={plot.line} stroke={CHART_SEQUENTIAL} d={linePath(run)} />\n </g>\n ))}\n {projectionPath ? (\n <path data-role=\"projection\" className={plot.projection} stroke={projectionColor} d={projectionPath} />\n ) : null}\n {projection.from ? (\n <circle className={plot.marker} cx={xs(clampX(projection.from.t))} cy={ys(projection.from.remaining)} r={4} fill={CHART_SEQUENTIAL} />\n ) : null}\n </svg>\n </div>\n </ChartFrame>\n );\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{n as e}from"./index-DbDw9UAs.js";var t={button:`_button_12qr7_1`,glyph:`_glyph_12qr7_30`,sm:`_sm_12qr7_37`,block:`_block_12qr7_43`,iconOnly:`_iconOnly_12qr7_48`,ghost:`_ghost_12qr7_60`,subtle:`_subtle_12qr7_71`,primary:`_primary_12qr7_84`,danger:`_danger_12qr7_99`},n=e();function r({variant:e=`subtle`,size:r=`md`,icon:i,trailingIcon:a,block:o=!1,busy:s=!1,iconOnly:c=!1,className:l,children:u,disabled:d,type:f=`button`,...p}){let m=[t.button,t[e],t[r],c?t.iconOnly:``,o?t.block:``,l??``].filter(Boolean).join(` `);return(0,n.jsxs)(`button`,{type:f,className:m,disabled:d||s,"aria-busy":s||void 0,...p,children:[i?(0,n.jsx)(`span`,{className:t.glyph,children:i}):null,c?null:u,a?(0,n.jsx)(`span`,{className:t.glyph,children:a}):null]})}function i({icon:e,...t}){return(0,n.jsx)(r,{...t,iconOnly:!0,icon:e})}export{i as n,r as t};
2
- //# sourceMappingURL=Button-DqgLUZvd.js.map
1
+ import{n as e}from"./index-BVxOlseC.js";var t={button:`_button_12qr7_1`,glyph:`_glyph_12qr7_30`,sm:`_sm_12qr7_37`,block:`_block_12qr7_43`,iconOnly:`_iconOnly_12qr7_48`,ghost:`_ghost_12qr7_60`,subtle:`_subtle_12qr7_71`,primary:`_primary_12qr7_84`,danger:`_danger_12qr7_99`},n=e();function r({variant:e=`subtle`,size:r=`md`,icon:i,trailingIcon:a,block:o=!1,busy:s=!1,iconOnly:c=!1,className:l,children:u,disabled:d,type:f=`button`,...p}){let m=[t.button,t[e],t[r],c?t.iconOnly:``,o?t.block:``,l??``].filter(Boolean).join(` `);return(0,n.jsxs)(`button`,{type:f,className:m,disabled:d||s,"aria-busy":s||void 0,...p,children:[i?(0,n.jsx)(`span`,{className:t.glyph,children:i}):null,c?null:u,a?(0,n.jsx)(`span`,{className:t.glyph,children:a}):null]})}function i({icon:e,...t}){return(0,n.jsx)(r,{...t,iconOnly:!0,icon:e})}export{i as n,r as t};
2
+ //# sourceMappingURL=Button-HHXgoXGr.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Button-DqgLUZvd.js","names":[],"sources":["../../../../../../src/web-ui/components/primitives/Button.module.css","../../../../../../src/web-ui/components/primitives/Button.tsx"],"sourcesContent":[".button {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: var(--space-2);\n height: var(--density-row);\n padding: 0 var(--density-pad);\n border: 1px solid transparent;\n border-radius: var(--radius-sm);\n background: transparent;\n color: var(--text-primary);\n font-family: var(--font-ui);\n font-size: var(--text-sm-size);\n line-height: 1;\n font-weight: var(--font-weight-medium);\n white-space: nowrap;\n cursor: pointer;\n transition:\n background-color var(--duration-fast) var(--ease-standard),\n border-color var(--duration-fast) var(--ease-standard),\n color var(--duration-fast) var(--ease-standard),\n opacity var(--duration-fast) var(--ease-standard);\n}\n\n.button:disabled {\n cursor: not-allowed;\n opacity: 0.55;\n}\n\n.glyph {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n}\n\n.sm {\n height: var(--density-row-sm);\n padding: 0 var(--space-2);\n font-size: var(--text-xs-size);\n}\n\n.block {\n width: 100%;\n}\n\n/* Square: width tracks the same density token as the height. */\n.iconOnly {\n width: var(--density-row);\n padding: 0;\n}\n\n.sm.iconOnly {\n width: var(--density-row-sm);\n}\n\n/* --------------------------------------------------------------------------\n * Variants\n * ------------------------------------------------------------------------ */\n.ghost {\n color: var(--text-secondary);\n}\n.ghost:hover:not(:disabled) {\n background: var(--bg-hover);\n color: var(--text-primary);\n}\n.ghost:active:not(:disabled) {\n background: var(--bg-active);\n}\n\n.subtle {\n border-color: var(--border-default);\n background: var(--bg-surface);\n color: var(--text-primary);\n}\n.subtle:hover:not(:disabled) {\n background: var(--bg-hover);\n border-color: var(--border-strong);\n}\n.subtle:active:not(:disabled) {\n background: var(--bg-active);\n}\n\n.primary {\n background: var(--accent-600);\n border-color: var(--accent-600);\n color: var(--text-on-accent);\n}\n.primary:hover:not(:disabled) {\n background: var(--accent-700);\n border-color: var(--accent-700);\n}\n.primary:active:not(:disabled) {\n background: var(--accent-700);\n}\n\n/* Destructive: outlined, never filled — a red block reads as an error state,\n and the design language reserves fills for the one primary action. */\n.danger {\n border-color: var(--border-default);\n color: var(--status-danger-fg);\n}\n.danger:hover:not(:disabled) {\n background: var(--status-danger-bg);\n border-color: var(--status-danger-solid);\n}\n.danger:active:not(:disabled) {\n background: var(--status-danger-bg);\n}\n\n/* Pressed/selected state for toggle buttons built on this primitive. */\n.button[aria-pressed='true'],\n.button[aria-expanded='true'] {\n background: var(--bg-selected);\n color: var(--text-primary);\n}\n","/**\n * components/primitives/Button.tsx — every clickable action in the console.\n *\n * Four variants, and they are a hierarchy, not a palette (design doc §1):\n * ghost — the default in dense chrome. No border, no fill. Header strips\n * contain only these.\n * subtle — hairline border, no fill. The ordinary form button.\n * primary — the ONE accent-filled action on a surface. If a screen has two,\n * one of them is wrong.\n * danger — destructive. Outlined, never filled, and always paired with a\n * confirm step at the call site (approve/emergency-stop/delete).\n *\n * Heights come from the density tokens, never from a literal px, so compact\n * mode moves every control together.\n *\n * Icon-only buttons are a TYPE-LEVEL contract: `iconOnly` requires\n * `aria-label`, because an icon with no text has no accessible name and the\n * operator's screen reader would announce \"button\". Use <IconButton> for the\n * common case.\n */\nimport type { ButtonHTMLAttributes, ReactNode, Ref } from 'react';\nimport styles from './Button.module.css';\n\nexport type ButtonVariant = 'ghost' | 'subtle' | 'primary' | 'danger';\nexport type ButtonSize = 'sm' | 'md';\n\ninterface ButtonBase extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'className'> {\n variant?: ButtonVariant;\n size?: ButtonSize;\n /** Leading glyph (16px icon from ./icons.tsx). */\n icon?: ReactNode;\n /** Trailing glyph — chevrons, external-link marks. */\n trailingIcon?: ReactNode;\n /** Stretch to the container's width (forms, sheets). */\n block?: boolean;\n /** In-flight: disables the control and announces aria-busy. */\n busy?: boolean;\n /** Escape hatch for layout-only classes from a parent module. */\n className?: string;\n /** React 19 takes `ref` as an ordinary prop — no forwardRef wrapper needed. */\n ref?: Ref<HTMLButtonElement>;\n children?: ReactNode;\n}\n\nexport type ButtonProps = ButtonBase &\n (\n | {\n /** Square control with no visible label — an accessible name is mandatory. */\n iconOnly: true;\n 'aria-label': string;\n children?: never;\n }\n | { iconOnly?: false }\n );\n\nexport function Button({\n variant = 'subtle',\n size = 'md',\n icon,\n trailingIcon,\n block = false,\n busy = false,\n iconOnly = false,\n className,\n children,\n disabled,\n type = 'button',\n ...rest\n}: ButtonProps) {\n const classes = [\n styles.button,\n styles[variant],\n styles[size],\n iconOnly ? styles.iconOnly : '',\n block ? styles.block : '',\n className ?? '',\n ]\n .filter(Boolean)\n .join(' ');\n\n return (\n <button\n type={type}\n className={classes}\n disabled={disabled || busy}\n aria-busy={busy || undefined}\n {...rest}\n >\n {icon ? <span className={styles.glyph}>{icon}</span> : null}\n {iconOnly ? null : children}\n {trailingIcon ? <span className={styles.glyph}>{trailingIcon}</span> : null}\n </button>\n );\n}\n\nexport interface IconButtonProps extends Omit<ButtonBase, 'icon' | 'children' | 'trailingIcon'> {\n icon: ReactNode;\n /** Mandatory: the icon is the whole control. */\n 'aria-label': string;\n}\n\n/** Square, label-less button. Same variants and sizing as <Button>. */\nexport function IconButton({ icon, ...rest }: IconButtonProps) {\n return <Button {...rest} iconOnly icon={icon} />;\n}\n"],"mappings":"uRCuDA,SAAgB,EAAO,CACrB,UAAU,SACV,OAAO,KACP,OACA,eACA,QAAQ,GACR,OAAO,GACP,WAAW,GACX,YACA,WACA,WACA,OAAO,SACP,GAAG,GACW,CACd,IAAM,EAAU,CACd,EAAO,OACP,EAAO,GACP,EAAO,GACP,EAAW,EAAO,SAAW,GAC7B,EAAQ,EAAO,MAAQ,GACvB,GAAa,EACf,CAAC,CACE,OAAO,OAAO,CAAC,CACf,KAAK,GAAG,EAEX,OACE,EAAA,EAAA,KAAA,CAAC,SAAD,CACQ,OACN,UAAW,EACX,SAAU,GAAY,EACtB,YAAW,GAAQ,IAAA,GACnB,GAAI,EALN,SAAA,CAOG,GAAO,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAO,MAAQ,SAAA,CAAW,CAAA,EAAI,KACtD,EAAW,KAAO,EAClB,GAAe,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAO,MAAQ,SAAA,CAAmB,CAAA,EAAI,IACjE,GAEZ,CASA,SAAgB,EAAW,CAAE,OAAM,GAAG,GAAyB,CAC7D,OAAO,EAAA,EAAA,IAAA,CAAC,EAAD,CAAQ,GAAI,EAAM,SAAA,GAAe,MAAO,CAAA,CACjD"}
1
+ {"version":3,"file":"Button-HHXgoXGr.js","names":[],"sources":["../../../../../../src/web-ui/components/primitives/Button.module.css","../../../../../../src/web-ui/components/primitives/Button.tsx"],"sourcesContent":[".button {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: var(--space-2);\n height: var(--density-row);\n padding: 0 var(--density-pad);\n border: 1px solid transparent;\n border-radius: var(--radius-sm);\n background: transparent;\n color: var(--text-primary);\n font-family: var(--font-ui);\n font-size: var(--text-sm-size);\n line-height: 1;\n font-weight: var(--font-weight-medium);\n white-space: nowrap;\n cursor: pointer;\n transition:\n background-color var(--duration-fast) var(--ease-standard),\n border-color var(--duration-fast) var(--ease-standard),\n color var(--duration-fast) var(--ease-standard),\n opacity var(--duration-fast) var(--ease-standard);\n}\n\n.button:disabled {\n cursor: not-allowed;\n opacity: 0.55;\n}\n\n.glyph {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n}\n\n.sm {\n height: var(--density-row-sm);\n padding: 0 var(--space-2);\n font-size: var(--text-xs-size);\n}\n\n.block {\n width: 100%;\n}\n\n/* Square: width tracks the same density token as the height. */\n.iconOnly {\n width: var(--density-row);\n padding: 0;\n}\n\n.sm.iconOnly {\n width: var(--density-row-sm);\n}\n\n/* --------------------------------------------------------------------------\n * Variants\n * ------------------------------------------------------------------------ */\n.ghost {\n color: var(--text-secondary);\n}\n.ghost:hover:not(:disabled) {\n background: var(--bg-hover);\n color: var(--text-primary);\n}\n.ghost:active:not(:disabled) {\n background: var(--bg-active);\n}\n\n.subtle {\n border-color: var(--border-default);\n background: var(--bg-surface);\n color: var(--text-primary);\n}\n.subtle:hover:not(:disabled) {\n background: var(--bg-hover);\n border-color: var(--border-strong);\n}\n.subtle:active:not(:disabled) {\n background: var(--bg-active);\n}\n\n.primary {\n background: var(--accent-600);\n border-color: var(--accent-600);\n color: var(--text-on-accent);\n}\n.primary:hover:not(:disabled) {\n background: var(--accent-700);\n border-color: var(--accent-700);\n}\n.primary:active:not(:disabled) {\n background: var(--accent-700);\n}\n\n/* Destructive: outlined, never filled — a red block reads as an error state,\n and the design language reserves fills for the one primary action. */\n.danger {\n border-color: var(--border-default);\n color: var(--status-danger-fg);\n}\n.danger:hover:not(:disabled) {\n background: var(--status-danger-bg);\n border-color: var(--status-danger-solid);\n}\n.danger:active:not(:disabled) {\n background: var(--status-danger-bg);\n}\n\n/* Pressed/selected state for toggle buttons built on this primitive. */\n.button[aria-pressed='true'],\n.button[aria-expanded='true'] {\n background: var(--bg-selected);\n color: var(--text-primary);\n}\n","/**\n * components/primitives/Button.tsx — every clickable action in the console.\n *\n * Four variants, and they are a hierarchy, not a palette (design doc §1):\n * ghost — the default in dense chrome. No border, no fill. Header strips\n * contain only these.\n * subtle — hairline border, no fill. The ordinary form button.\n * primary — the ONE accent-filled action on a surface. If a screen has two,\n * one of them is wrong.\n * danger — destructive. Outlined, never filled, and always paired with a\n * confirm step at the call site (approve/emergency-stop/delete).\n *\n * Heights come from the density tokens, never from a literal px, so compact\n * mode moves every control together.\n *\n * Icon-only buttons are a TYPE-LEVEL contract: `iconOnly` requires\n * `aria-label`, because an icon with no text has no accessible name and the\n * operator's screen reader would announce \"button\". Use <IconButton> for the\n * common case.\n */\nimport type { ButtonHTMLAttributes, ReactNode, Ref } from 'react';\nimport styles from './Button.module.css';\n\nexport type ButtonVariant = 'ghost' | 'subtle' | 'primary' | 'danger';\nexport type ButtonSize = 'sm' | 'md';\n\ninterface ButtonBase extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'className'> {\n variant?: ButtonVariant;\n size?: ButtonSize;\n /** Leading glyph (16px icon from ./icons.tsx). */\n icon?: ReactNode;\n /** Trailing glyph — chevrons, external-link marks. */\n trailingIcon?: ReactNode;\n /** Stretch to the container's width (forms, sheets). */\n block?: boolean;\n /** In-flight: disables the control and announces aria-busy. */\n busy?: boolean;\n /** Escape hatch for layout-only classes from a parent module. */\n className?: string;\n /** React 19 takes `ref` as an ordinary prop — no forwardRef wrapper needed. */\n ref?: Ref<HTMLButtonElement>;\n children?: ReactNode;\n}\n\nexport type ButtonProps = ButtonBase &\n (\n | {\n /** Square control with no visible label — an accessible name is mandatory. */\n iconOnly: true;\n 'aria-label': string;\n children?: never;\n }\n | { iconOnly?: false }\n );\n\nexport function Button({\n variant = 'subtle',\n size = 'md',\n icon,\n trailingIcon,\n block = false,\n busy = false,\n iconOnly = false,\n className,\n children,\n disabled,\n type = 'button',\n ...rest\n}: ButtonProps) {\n const classes = [\n styles.button,\n styles[variant],\n styles[size],\n iconOnly ? styles.iconOnly : '',\n block ? styles.block : '',\n className ?? '',\n ]\n .filter(Boolean)\n .join(' ');\n\n return (\n <button\n type={type}\n className={classes}\n disabled={disabled || busy}\n aria-busy={busy || undefined}\n {...rest}\n >\n {icon ? <span className={styles.glyph}>{icon}</span> : null}\n {iconOnly ? null : children}\n {trailingIcon ? <span className={styles.glyph}>{trailingIcon}</span> : null}\n </button>\n );\n}\n\nexport interface IconButtonProps extends Omit<ButtonBase, 'icon' | 'children' | 'trailingIcon'> {\n icon: ReactNode;\n /** Mandatory: the icon is the whole control. */\n 'aria-label': string;\n}\n\n/** Square, label-less button. Same variants and sizing as <Button>. */\nexport function IconButton({ icon, ...rest }: IconButtonProps) {\n return <Button {...rest} iconOnly icon={icon} />;\n}\n"],"mappings":"uRCuDA,SAAgB,EAAO,CACrB,UAAU,SACV,OAAO,KACP,OACA,eACA,QAAQ,GACR,OAAO,GACP,WAAW,GACX,YACA,WACA,WACA,OAAO,SACP,GAAG,GACW,CACd,IAAM,EAAU,CACd,EAAO,OACP,EAAO,GACP,EAAO,GACP,EAAW,EAAO,SAAW,GAC7B,EAAQ,EAAO,MAAQ,GACvB,GAAa,EACf,CAAC,CACE,OAAO,OAAO,CAAC,CACf,KAAK,GAAG,EAEX,OACE,EAAA,EAAA,KAAA,CAAC,SAAD,CACQ,OACN,UAAW,EACX,SAAU,GAAY,EACtB,YAAW,GAAQ,IAAA,GACnB,GAAI,EALN,SAAA,CAOG,GAAO,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAO,MAAQ,SAAA,CAAW,CAAA,EAAI,KACtD,EAAW,KAAO,EAClB,GAAe,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAO,MAAQ,SAAA,CAAmB,CAAA,EAAI,IACjE,GAEZ,CASA,SAAgB,EAAW,CAAE,OAAM,GAAG,GAAyB,CAC7D,OAAO,EAAA,EAAA,IAAA,CAAC,EAAD,CAAQ,GAAI,EAAM,SAAA,GAAe,MAAO,CAAA,CACjD"}
@@ -1,2 +1,2 @@
1
- import{a as e,n as t,s as n}from"./index-DbDw9UAs.js";import{m as r,p as i}from"./global-BkNl4e6E.js";import{t as a}from"./ProviderLogo-Bz7KR5j3.js";import{i as o,r as s}from"./section-visibility-B0xXUQJ0.js";import{x as c}from"./VerseConsoleApp-CTF3Shs0.js";import{g as l}from"./format-CaMmVQCn.js";import{r as u}from"./Tag-Bv8u6APt.js";import{n as d}from"./budget-queries-CP7hgR-p.js";import{n as f,t as p}from"./useSeatsRefresh-B2dCVcj9.js";import{a as m,l as h,n as g,o as _,r as v,t as y}from"./capacity-strip-model-fHfu5cph.js";var b=n(e(),1),x={section:`_section_1vcn6_8`,scroll:`_scroll_1vcn6_16`,page:`_page_1vcn6_34`,header:`_header_1vcn6_43`,headerText:`_headerText_1vcn6_50`,title:`_title_1vcn6_56`,lede:`_lede_1vcn6_65`,headerMeta:`_headerMeta_1vcn6_71`,banner:`_banner_1vcn6_80`,accountsNote:`_accountsNote_1vcn6_96`,group:`_group_1vcn6_108`,groupHead:`_groupHead_1vcn6_114`,groupTitle:`_groupTitle_1vcn6_121`,caveat:`_caveat_1vcn6_138`,inlineCode:`_inlineCode_1vcn6_145`,card:`_card_1vcn6_154`,rows:`_rows_1vcn6_162`,row:`_row_1vcn6_162`,rowMain:`_rowMain_1vcn6_180`,rowHead:`_rowHead_1vcn6_187`,rowName:`_rowName_1vcn6_194`,rowVersion:`_rowVersion_1vcn6_200`,rowDesc:`_rowDesc_1vcn6_205`,rowDetail:`_rowDetail_1vcn6_206`,rowAside:`_rowAside_1vcn6_217`,health:`_health_1vcn6_228`,healthDot:`_healthDot_1vcn6_237`,loadingLine:`_loadingLine_1vcn6_263`,tile:`_tile_1vcn6_273`,pillWrap:`_pillWrap_1vcn6_314`,pill:`_pill_1vcn6_314`,pillText:`_pillText_1vcn6_348`,pillIcon:`_pillIcon_1vcn6_356`,visuallyHidden:`_visuallyHidden_1vcn6_367`,split:`_split_1vcn6_381`,disabledNote:`_disabledNote_1vcn6_394`,dialogBody:`_dialogBody_1vcn6_404`,commandBlock:`_commandBlock_1vcn6_415`,commandLabel:`_commandLabel_1vcn6_420`,dialogActions:`_dialogActions_1vcn6_428`,fieldset:`_fieldset_1vcn6_435`,legend:`_legend_1vcn6_443`,radio:`_radio_1vcn6_450`,error:`_error_1vcn6_460`,textarea:`_textarea_1vcn6_466`,fieldLabel:`_fieldLabel_1vcn6_483`,hint:`_hint_1vcn6_491`,warnings:`_warnings_1vcn6_495`,servers:`_servers_1vcn6_505`,reasonCode:`_reasonCode_1vcn6_511`,scopeLine:`_scopeLine_1vcn6_517`},S=t();function C({monogram:e,engine:t,size:n=`md`}){let r=t===null?void 0:{"--tile-hue":u(t)};return(0,S.jsx)(`span`,{className:x.tile,"data-size":n,"data-engine":t??void 0,style:r,"aria-hidden":`true`,children:t===null?e.slice(0,2):(0,S.jsx)(a,{engine:t,size:n===`sm`?14:18})})}var w={strip:`_strip_o9cqi_7`,visuallyHidden:`_visuallyHidden_o9cqi_15`,headline:`_headline_o9cqi_27`,empty:`_empty_o9cqi_35`,rows:`_rows_o9cqi_42`,row:`_row_o9cqi_42`,main:`_main_o9cqi_67`,head:`_head_o9cqi_27`,nameWrap:`_nameWrap_o9cqi_82`,nameButton:`_nameButton_o9cqi_83`,name:`_name_o9cqi_82`,plan:`_plan_o9cqi_121`,word:`_word_o9cqi_131`,dot:`_dot_o9cqi_140`,status:`_status_o9cqi_163`,statusLabel:`_statusLabel_o9cqi_176`,statusDetail:`_statusDetail_o9cqi_195`,stamp:`_stamp_o9cqi_199`,usableAgain:`_usableAgain_o9cqi_206`,summary:`_summary_o9cqi_211`,meta:`_meta_o9cqi_212`,autonomy:`_autonomy_o9cqi_222`,bars:`_bars_o9cqi_232`,bar:`_bar_o9cqi_232`,barLabel:`_barLabel_o9cqi_251`,track:`_track_o9cqi_262`,trackUnknown:`_trackUnknown_o9cqi_270`,used:`_used_o9cqi_276`,reserve:`_reserve_o9cqi_287`,ceiling:`_ceiling_o9cqi_297`,value:`_value_o9cqi_306`,reset:`_reset_o9cqi_319`,actions:`_actions_o9cqi_326`},T=90,E=3e4;function D(e){return Math.max(0,Math.min(100,Math.round(e)))}function O({row:e,w:t,reservePercent:n,compact:r}){let i=h(e,t,t.binding?n:null),a=t.binding&&n!==null&&n>0?100-D(n):null,o,s;if(t.limitReached)o=(0,S.jsx)(`span`,{className:w.track,role:`img`,"aria-label":i,children:(0,S.jsx)(`span`,{className:w.used,"data-level":`limit`,style:{width:`100%`}})}),s=(0,S.jsx)(`span`,{className:w.value,"data-level":`limit`,children:`limit reached`});else if(t.usedPercent===null)o=(0,S.jsx)(`span`,{className:w.trackUnknown,role:`img`,"aria-label":i}),s=(0,S.jsx)(`span`,{className:w.value,"data-level":`unknown`,children:`no reading`});else{let e=D(t.usedPercent),n=e>=T?`tight`:`ok`;o=(0,S.jsxs)(`span`,{className:w.track,role:`img`,"aria-label":i,children:[a===null?null:(0,S.jsx)(`span`,{className:w.reserve,style:{left:`${a}%`,width:`${100-a}%`}}),(0,S.jsx)(`span`,{className:w.used,"data-level":n,style:{width:`${e}%`}}),a===null?null:(0,S.jsx)(`span`,{className:w.ceiling,style:{left:`${a}%`}})]}),s=(0,S.jsx)(`span`,{className:w.value,"data-level":n,children:l(t.usedPercent)})}return(0,S.jsxs)(`div`,{className:w.bar,"data-binding":t.binding||void 0,"data-compact":r||void 0,children:[(0,S.jsx)(`span`,{className:w.barLabel,title:t.label,children:t.label.replace(/ window$/,``)}),o,s,!r&&t.resetText!==null?(0,S.jsx)(`span`,{className:w.reset,title:t.resetText,children:t.resetText}):null]})}function k({row:e,onSelect:t,selected:n}){let r=(0,S.jsxs)(S.Fragment,{children:[(0,S.jsx)(`span`,{className:w.name,children:e.label}),e.plan===null?null:(0,S.jsx)(`span`,{className:w.plan,children:e.plan})]});return t?(0,S.jsx)(`button`,{type:`button`,className:w.nameButton,"aria-pressed":n,onClick:()=>t(e.seatId),children:r}):(0,S.jsx)(`span`,{className:w.nameWrap,children:r})}function A({status:e}){return(0,S.jsxs)(`span`,{className:w.status,"data-tone":e.tone,"data-status":e.kind,children:[(0,S.jsx)(`span`,{className:w.dot,"aria-hidden":`true`}),(0,S.jsx)(`span`,{className:w.statusLabel,children:e.label}),e.detail===null?null:(0,S.jsx)(`span`,{className:w.statusDetail,children:`· ${e.detail}`})]})}function j({status:e}){return e.usableAgain===null&&e.checked===null?null:(0,S.jsxs)(`p`,{className:w.stamp,children:[e.usableAgain===null?null:(0,S.jsx)(`span`,{className:w.usableAgain,children:e.usableAgain}),e.usableAgain!==null&&e.checked!==null?` · `:null,e.checked===null?null:(0,S.jsx)(`span`,{title:e.checkedTitle??void 0,children:e.checked})]})}function M({row:e,compact:t,renderActions:n,onSelectSeat:r,selected:i,status:a}){let o=m(e.cls),s=e.windows.find(e=>e.binding)??null,c=t?s?[s]:[]:e.windows,l=n?n(e):null,u=e.reserve;return(0,S.jsxs)(`li`,{className:w.row,"data-capacity":e.cls,"data-compact":t||void 0,"data-status":a?.kind,children:[(0,S.jsx)(C,{monogram:e.monogram,engine:e.engine,size:`sm`}),(0,S.jsxs)(`div`,{className:w.main,children:[(0,S.jsxs)(`div`,{className:w.head,children:[(0,S.jsx)(k,{row:e,onSelect:r,selected:i}),a===null?(0,S.jsxs)(`span`,{className:w.word,"data-tone":o,children:[(0,S.jsx)(`span`,{className:w.dot,"aria-hidden":`true`}),e.word]}):(0,S.jsx)(A,{status:a}),e.connection!==null&&e.connection.connection!==`connected`&&e.connection.connection!==`unknown`&&!(a?.coversConnection??!1)&&a?.kind!==`signed-out`?(0,S.jsxs)(`span`,{className:w.word,"data-tone":e.connection.tone,children:[(0,S.jsx)(`span`,{className:w.dot,"aria-hidden":`true`}),e.connection.word]}):null]}),!t||c.length===0?(0,S.jsx)(`p`,{className:w.summary,children:e.summary}):null,a!==null&&!t?(0,S.jsx)(j,{status:a}):null,c.length>0?(0,S.jsx)(`div`,{className:w.bars,children:c.map(n=>(0,S.jsx)(O,{row:e,w:n,reservePercent:u?.percent??null,compact:t},n.id))}):null,!t&&(u!==null||e.credits!==null)?(0,S.jsxs)(`p`,{className:w.meta,children:[u===null?null:(0,S.jsxs)(`span`,{title:u.why,children:[u.label,u.autonomy===`off`?null:(0,S.jsxs)(S.Fragment,{children:[` · Autonomy: `,(0,S.jsx)(`span`,{className:w.autonomy,"data-status":u.autonomy,children:u.autonomyWord})]})]}),u!==null&&e.credits!==null?` · `:null,e.credits===null?null:(0,S.jsx)(`span`,{children:e.credits})]}):null]}),l?(0,S.jsx)(`div`,{className:w.actions,children:l}):null]})}function N({seats:e,health:t,budget:n,local:r,seatIds:i,density:a=`full`,headline:o,title:c=`Seat capacity`,labelledBy:l,renderActions:u,onSelectSeat:d,selectedSeatId:f=null,emptyText:p=`No seats yet. Connect an account or start Ollama — an empty roster, not seats at zero.`,accounts:m}){let h=(0,b.useId)(),[x,C]=(0,b.useState)(()=>Date.now());s(()=>C(Date.now()),E,{enabled:m!==void 0&&m.now===void 0});let T=m?.now??x,D=m?.healthRead??!1,O=m!==void 0,k=O?T:void 0,A=(0,b.useMemo)(()=>g(e,{health:t??null,budget:n??null,...r?{local:r}:{},...i?{seatIds:i}:{},...k===void 0?{}:{now:k}}),[e,t,n,r,i,k]),j=(0,b.useMemo)(()=>O?_(A,{healthRead:D,now:T}):A,[A,O,D,T]),N=a===`compact`,P=o??!N;return(0,S.jsxs)(l?`div`:`section`,{className:w.strip,"aria-labelledby":l?void 0:h,"data-density":a,children:[l?null:(0,S.jsx)(`h3`,{id:h,className:w.visuallyHidden,children:c}),P&&j.length>0?(0,S.jsx)(`p`,{className:w.headline,children:v(j)}):null,j.length===0?(0,S.jsx)(`p`,{className:w.empty,children:p}):(0,S.jsx)(`ul`,{className:w.rows,"aria-label":l?void 0:c,"aria-labelledby":l,children:j.map(e=>(0,S.jsx)(M,{row:e,compact:N,renderActions:u,onSelectSeat:d,selected:f===e.seatId,status:m?y(e,{healthRead:D,now:T,checking:m.checkingSeatId===e.seatId}):null},e.seatId))})]})}var P=6e4;function F(e={}){let t=o(),n=e.withBudget??!0,a=e.withHealth??!0,l=i(c);p(t);let u=f(t&&a),m=i(d),h=r(d);s(h,P,{enabled:n});let g=l.data;return{seats:g?.seats??[],health:a?u.data?.seats??null:null,budget:n?m.data??null:null,loading:g===void 0&&(l.status===`loading`||l.status===`idle`)}}function I({seats:e,...t}){let n=F();return e===void 0&&n.loading?(0,S.jsx)(`p`,{className:w.empty,"aria-busy":`true`,children:`Reading seats…`}):(0,S.jsx)(N,{...t,seats:e??n.seats,health:n.health,budget:n.budget})}export{C as a,F as i,N as n,x as o,I as r,E as t};
2
- //# sourceMappingURL=CapacityStrip-nWFHvqFB.js.map
1
+ import{a as e,n as t,s as n}from"./index-BVxOlseC.js";import{m as r,p as i}from"./global-oEl9Qj8u.js";import{t as a}from"./ProviderLogo-C5mBg8i0.js";import{i as o,r as s}from"./section-visibility-Yctxu-if.js";import{x as c}from"./VerseConsoleApp-DTjDpGCd.js";import{g as l}from"./format-BkWdOQDL.js";import{r as u}from"./Tag-DH15CUJp.js";import{n as d}from"./budget-queries-V3wcJVK_.js";import{n as f,t as p}from"./useSeatsRefresh-DgFy-Ph4.js";import{a as m,l as h,n as g,o as _,r as v,t as y}from"./capacity-strip-model-BDbmQ3e3.js";var b=n(e(),1),x={section:`_section_1vcn6_8`,scroll:`_scroll_1vcn6_16`,page:`_page_1vcn6_34`,header:`_header_1vcn6_43`,headerText:`_headerText_1vcn6_50`,title:`_title_1vcn6_56`,lede:`_lede_1vcn6_65`,headerMeta:`_headerMeta_1vcn6_71`,banner:`_banner_1vcn6_80`,accountsNote:`_accountsNote_1vcn6_96`,group:`_group_1vcn6_108`,groupHead:`_groupHead_1vcn6_114`,groupTitle:`_groupTitle_1vcn6_121`,caveat:`_caveat_1vcn6_138`,inlineCode:`_inlineCode_1vcn6_145`,card:`_card_1vcn6_154`,rows:`_rows_1vcn6_162`,row:`_row_1vcn6_162`,rowMain:`_rowMain_1vcn6_180`,rowHead:`_rowHead_1vcn6_187`,rowName:`_rowName_1vcn6_194`,rowVersion:`_rowVersion_1vcn6_200`,rowDesc:`_rowDesc_1vcn6_205`,rowDetail:`_rowDetail_1vcn6_206`,rowAside:`_rowAside_1vcn6_217`,health:`_health_1vcn6_228`,healthDot:`_healthDot_1vcn6_237`,loadingLine:`_loadingLine_1vcn6_263`,tile:`_tile_1vcn6_273`,pillWrap:`_pillWrap_1vcn6_314`,pill:`_pill_1vcn6_314`,pillText:`_pillText_1vcn6_348`,pillIcon:`_pillIcon_1vcn6_356`,visuallyHidden:`_visuallyHidden_1vcn6_367`,split:`_split_1vcn6_381`,disabledNote:`_disabledNote_1vcn6_394`,dialogBody:`_dialogBody_1vcn6_404`,commandBlock:`_commandBlock_1vcn6_415`,commandLabel:`_commandLabel_1vcn6_420`,dialogActions:`_dialogActions_1vcn6_428`,fieldset:`_fieldset_1vcn6_435`,legend:`_legend_1vcn6_443`,radio:`_radio_1vcn6_450`,error:`_error_1vcn6_460`,textarea:`_textarea_1vcn6_466`,fieldLabel:`_fieldLabel_1vcn6_483`,hint:`_hint_1vcn6_491`,warnings:`_warnings_1vcn6_495`,servers:`_servers_1vcn6_505`,reasonCode:`_reasonCode_1vcn6_511`,scopeLine:`_scopeLine_1vcn6_517`},S=t();function C({monogram:e,engine:t,size:n=`md`}){let r=t===null?void 0:{"--tile-hue":u(t)};return(0,S.jsx)(`span`,{className:x.tile,"data-size":n,"data-engine":t??void 0,style:r,"aria-hidden":`true`,children:t===null?e.slice(0,2):(0,S.jsx)(a,{engine:t,size:n===`sm`?14:18})})}var w={strip:`_strip_o9cqi_7`,visuallyHidden:`_visuallyHidden_o9cqi_15`,headline:`_headline_o9cqi_27`,empty:`_empty_o9cqi_35`,rows:`_rows_o9cqi_42`,row:`_row_o9cqi_42`,main:`_main_o9cqi_67`,head:`_head_o9cqi_27`,nameWrap:`_nameWrap_o9cqi_82`,nameButton:`_nameButton_o9cqi_83`,name:`_name_o9cqi_82`,plan:`_plan_o9cqi_121`,word:`_word_o9cqi_131`,dot:`_dot_o9cqi_140`,status:`_status_o9cqi_163`,statusLabel:`_statusLabel_o9cqi_176`,statusDetail:`_statusDetail_o9cqi_195`,stamp:`_stamp_o9cqi_199`,usableAgain:`_usableAgain_o9cqi_206`,summary:`_summary_o9cqi_211`,meta:`_meta_o9cqi_212`,autonomy:`_autonomy_o9cqi_222`,bars:`_bars_o9cqi_232`,bar:`_bar_o9cqi_232`,barLabel:`_barLabel_o9cqi_251`,track:`_track_o9cqi_262`,trackUnknown:`_trackUnknown_o9cqi_270`,used:`_used_o9cqi_276`,reserve:`_reserve_o9cqi_287`,ceiling:`_ceiling_o9cqi_297`,value:`_value_o9cqi_306`,reset:`_reset_o9cqi_319`,actions:`_actions_o9cqi_326`},T=90,E=3e4;function D(e){return Math.max(0,Math.min(100,Math.round(e)))}function O({row:e,w:t,reservePercent:n,compact:r}){let i=h(e,t,t.binding?n:null),a=t.binding&&n!==null&&n>0?100-D(n):null,o,s;if(t.limitReached)o=(0,S.jsx)(`span`,{className:w.track,role:`img`,"aria-label":i,children:(0,S.jsx)(`span`,{className:w.used,"data-level":`limit`,style:{width:`100%`}})}),s=(0,S.jsx)(`span`,{className:w.value,"data-level":`limit`,children:`limit reached`});else if(t.usedPercent===null)o=(0,S.jsx)(`span`,{className:w.trackUnknown,role:`img`,"aria-label":i}),s=(0,S.jsx)(`span`,{className:w.value,"data-level":`unknown`,children:`no reading`});else{let e=D(t.usedPercent),n=e>=T?`tight`:`ok`;o=(0,S.jsxs)(`span`,{className:w.track,role:`img`,"aria-label":i,children:[a===null?null:(0,S.jsx)(`span`,{className:w.reserve,style:{left:`${a}%`,width:`${100-a}%`}}),(0,S.jsx)(`span`,{className:w.used,"data-level":n,style:{width:`${e}%`}}),a===null?null:(0,S.jsx)(`span`,{className:w.ceiling,style:{left:`${a}%`}})]}),s=(0,S.jsx)(`span`,{className:w.value,"data-level":n,children:l(t.usedPercent)})}return(0,S.jsxs)(`div`,{className:w.bar,"data-binding":t.binding||void 0,"data-compact":r||void 0,children:[(0,S.jsx)(`span`,{className:w.barLabel,title:t.label,children:t.label.replace(/ window$/,``)}),o,s,!r&&t.resetText!==null?(0,S.jsx)(`span`,{className:w.reset,title:t.resetText,children:t.resetText}):null]})}function k({row:e,onSelect:t,selected:n}){let r=(0,S.jsxs)(S.Fragment,{children:[(0,S.jsx)(`span`,{className:w.name,children:e.label}),e.plan===null?null:(0,S.jsx)(`span`,{className:w.plan,children:e.plan})]});return t?(0,S.jsx)(`button`,{type:`button`,className:w.nameButton,"aria-pressed":n,onClick:()=>t(e.seatId),children:r}):(0,S.jsx)(`span`,{className:w.nameWrap,children:r})}function A({status:e}){return(0,S.jsxs)(`span`,{className:w.status,"data-tone":e.tone,"data-status":e.kind,children:[(0,S.jsx)(`span`,{className:w.dot,"aria-hidden":`true`}),(0,S.jsx)(`span`,{className:w.statusLabel,children:e.label}),e.detail===null?null:(0,S.jsx)(`span`,{className:w.statusDetail,children:`· ${e.detail}`})]})}function j({status:e}){return e.usableAgain===null&&e.checked===null?null:(0,S.jsxs)(`p`,{className:w.stamp,children:[e.usableAgain===null?null:(0,S.jsx)(`span`,{className:w.usableAgain,children:e.usableAgain}),e.usableAgain!==null&&e.checked!==null?` · `:null,e.checked===null?null:(0,S.jsx)(`span`,{title:e.checkedTitle??void 0,children:e.checked})]})}function M({row:e,compact:t,renderActions:n,onSelectSeat:r,selected:i,status:a}){let o=m(e.cls),s=e.windows.find(e=>e.binding)??null,c=t?s?[s]:[]:e.windows,l=n?n(e):null,u=e.reserve;return(0,S.jsxs)(`li`,{className:w.row,"data-capacity":e.cls,"data-compact":t||void 0,"data-status":a?.kind,children:[(0,S.jsx)(C,{monogram:e.monogram,engine:e.engine,size:`sm`}),(0,S.jsxs)(`div`,{className:w.main,children:[(0,S.jsxs)(`div`,{className:w.head,children:[(0,S.jsx)(k,{row:e,onSelect:r,selected:i}),a===null?(0,S.jsxs)(`span`,{className:w.word,"data-tone":o,children:[(0,S.jsx)(`span`,{className:w.dot,"aria-hidden":`true`}),e.word]}):(0,S.jsx)(A,{status:a}),e.connection!==null&&e.connection.connection!==`connected`&&e.connection.connection!==`unknown`&&!(a?.coversConnection??!1)&&a?.kind!==`signed-out`?(0,S.jsxs)(`span`,{className:w.word,"data-tone":e.connection.tone,children:[(0,S.jsx)(`span`,{className:w.dot,"aria-hidden":`true`}),e.connection.word]}):null]}),!t||c.length===0?(0,S.jsx)(`p`,{className:w.summary,children:e.summary}):null,a!==null&&!t?(0,S.jsx)(j,{status:a}):null,c.length>0?(0,S.jsx)(`div`,{className:w.bars,children:c.map(n=>(0,S.jsx)(O,{row:e,w:n,reservePercent:u?.percent??null,compact:t},n.id))}):null,!t&&(u!==null||e.credits!==null)?(0,S.jsxs)(`p`,{className:w.meta,children:[u===null?null:(0,S.jsxs)(`span`,{title:u.why,children:[u.label,u.autonomy===`off`?null:(0,S.jsxs)(S.Fragment,{children:[` · Autonomy: `,(0,S.jsx)(`span`,{className:w.autonomy,"data-status":u.autonomy,children:u.autonomyWord})]})]}),u!==null&&e.credits!==null?` · `:null,e.credits===null?null:(0,S.jsx)(`span`,{children:e.credits})]}):null]}),l?(0,S.jsx)(`div`,{className:w.actions,children:l}):null]})}function N({seats:e,health:t,budget:n,local:r,seatIds:i,density:a=`full`,headline:o,title:c=`Seat capacity`,labelledBy:l,renderActions:u,onSelectSeat:d,selectedSeatId:f=null,emptyText:p=`No seats yet. Connect an account or start Ollama — an empty roster, not seats at zero.`,accounts:m}){let h=(0,b.useId)(),[x,C]=(0,b.useState)(()=>Date.now());s(()=>C(Date.now()),E,{enabled:m!==void 0&&m.now===void 0});let T=m?.now??x,D=m?.healthRead??!1,O=m!==void 0,k=O?T:void 0,A=(0,b.useMemo)(()=>g(e,{health:t??null,budget:n??null,...r?{local:r}:{},...i?{seatIds:i}:{},...k===void 0?{}:{now:k}}),[e,t,n,r,i,k]),j=(0,b.useMemo)(()=>O?_(A,{healthRead:D,now:T}):A,[A,O,D,T]),N=a===`compact`,P=o??!N;return(0,S.jsxs)(l?`div`:`section`,{className:w.strip,"aria-labelledby":l?void 0:h,"data-density":a,children:[l?null:(0,S.jsx)(`h3`,{id:h,className:w.visuallyHidden,children:c}),P&&j.length>0?(0,S.jsx)(`p`,{className:w.headline,children:v(j)}):null,j.length===0?(0,S.jsx)(`p`,{className:w.empty,children:p}):(0,S.jsx)(`ul`,{className:w.rows,"aria-label":l?void 0:c,"aria-labelledby":l,children:j.map(e=>(0,S.jsx)(M,{row:e,compact:N,renderActions:u,onSelectSeat:d,selected:f===e.seatId,status:m?y(e,{healthRead:D,now:T,checking:m.checkingSeatId===e.seatId}):null},e.seatId))})]})}var P=6e4;function F(e={}){let t=o(),n=e.withBudget??!0,a=e.withHealth??!0,l=i(c);p(t);let u=f(t&&a),m=i(d),h=r(d);s(h,P,{enabled:n});let g=l.data;return{seats:g?.seats??[],health:a?u.data?.seats??null:null,budget:n?m.data??null:null,loading:g===void 0&&(l.status===`loading`||l.status===`idle`)}}function I({seats:e,...t}){let n=F();return e===void 0&&n.loading?(0,S.jsx)(`p`,{className:w.empty,"aria-busy":`true`,children:`Reading seats…`}):(0,S.jsx)(N,{...t,seats:e??n.seats,health:n.health,budget:n.budget})}export{C as a,F as i,N as n,x as o,I as r,E as t};
2
+ //# sourceMappingURL=CapacityStrip-qReu0RaF.js.map