@ashlr/hub 3.4.0 → 3.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (213) hide show
  1. package/CHANGELOG.md +56 -1
  2. package/README.md +3 -0
  3. package/dist/build-identity.json +2 -2
  4. package/dist/cli/index.js +11 -0
  5. package/dist/cli/index.js.map +1 -1
  6. package/dist/cli/local-runtime.js +40 -9
  7. package/dist/cli/local-runtime.js.map +1 -1
  8. package/dist/core/local-eval/classify.d.ts +57 -0
  9. package/dist/core/local-eval/classify.js +121 -0
  10. package/dist/core/local-eval/classify.js.map +1 -0
  11. package/dist/core/local-eval/configuration.d.ts +37 -0
  12. package/dist/core/local-eval/configuration.js +171 -0
  13. package/dist/core/local-eval/configuration.js.map +1 -0
  14. package/dist/core/local-eval/index.d.ts +15 -0
  15. package/dist/core/local-eval/index.js +16 -0
  16. package/dist/core/local-eval/index.js.map +1 -0
  17. package/dist/core/local-eval/main.d.ts +31 -0
  18. package/dist/core/local-eval/main.js +174 -0
  19. package/dist/core/local-eval/main.js.map +1 -0
  20. package/dist/core/local-eval/report.d.ts +25 -0
  21. package/dist/core/local-eval/report.js +157 -0
  22. package/dist/core/local-eval/report.js.map +1 -0
  23. package/dist/core/local-eval/runner.d.ts +55 -0
  24. package/dist/core/local-eval/runner.js +290 -0
  25. package/dist/core/local-eval/runner.js.map +1 -0
  26. package/dist/core/local-eval/tasks.d.ts +22 -0
  27. package/dist/core/local-eval/tasks.js +303 -0
  28. package/dist/core/local-eval/tasks.js.map +1 -0
  29. package/dist/core/local-eval/trace.d.ts +67 -0
  30. package/dist/core/local-eval/trace.js +309 -0
  31. package/dist/core/local-eval/trace.js.map +1 -0
  32. package/dist/core/local-eval/types.d.ts +262 -0
  33. package/dist/core/local-eval/types.js +23 -0
  34. package/dist/core/local-eval/types.js.map +1 -0
  35. package/dist/core/local-runtime/llama/anthropic-proxy-host.d.ts +68 -0
  36. package/dist/core/local-runtime/llama/anthropic-proxy-host.js +120 -0
  37. package/dist/core/local-runtime/llama/anthropic-proxy-host.js.map +1 -0
  38. package/dist/core/local-runtime/llama/anthropic-proxy-process.d.ts +15 -0
  39. package/dist/core/local-runtime/llama/anthropic-proxy-process.js +21 -0
  40. package/dist/core/local-runtime/llama/anthropic-proxy-process.js.map +1 -0
  41. package/dist/core/local-runtime/llama/anthropic-proxy.d.ts +2 -1
  42. package/dist/core/local-runtime/llama/anthropic-proxy.js +14 -6
  43. package/dist/core/local-runtime/llama/anthropic-proxy.js.map +1 -1
  44. package/dist/core/local-runtime/llama/anthropic-shim.d.ts +33 -0
  45. package/dist/core/local-runtime/llama/anthropic-shim.js +59 -0
  46. package/dist/core/local-runtime/llama/anthropic-shim.js.map +1 -1
  47. package/dist/core/local-runtime/llama/config.d.ts +101 -6
  48. package/dist/core/local-runtime/llama/config.js +174 -6
  49. package/dist/core/local-runtime/llama/config.js.map +1 -1
  50. package/dist/core/local-runtime/llama/index.d.ts +15 -0
  51. package/dist/core/local-runtime/llama/index.js +13 -0
  52. package/dist/core/local-runtime/llama/index.js.map +1 -1
  53. package/dist/core/local-runtime/llama/paths.d.ts +17 -0
  54. package/dist/core/local-runtime/llama/paths.js +25 -0
  55. package/dist/core/local-runtime/llama/paths.js.map +1 -1
  56. package/dist/core/local-runtime/llama/proxy-invocation.d.ts +101 -0
  57. package/dist/core/local-runtime/llama/proxy-invocation.js +134 -0
  58. package/dist/core/local-runtime/llama/proxy-invocation.js.map +1 -0
  59. package/dist/core/local-runtime/llama/proxy-launchd.d.ts +83 -0
  60. package/dist/core/local-runtime/llama/proxy-launchd.js +216 -0
  61. package/dist/core/local-runtime/llama/proxy-launchd.js.map +1 -0
  62. package/dist/core/local-runtime/llama/shapes.d.ts +2 -1
  63. package/dist/core/local-runtime/llama/shapes.js +2 -1
  64. package/dist/core/local-runtime/llama/shapes.js.map +1 -1
  65. package/dist/core/verse/adapters/claude.js +16 -0
  66. package/dist/core/verse/adapters/claude.js.map +1 -1
  67. package/dist/core/verse/adapters/codex.js +60 -2
  68. package/dist/core/verse/adapters/codex.js.map +1 -1
  69. package/dist/core/verse/adapters/grok.js +13 -0
  70. package/dist/core/verse/adapters/grok.js.map +1 -1
  71. package/dist/core/verse/control-api.d.ts +8 -9
  72. package/dist/core/verse/control-api.js +14 -114
  73. package/dist/core/verse/control-api.js.map +1 -1
  74. package/dist/core/verse/github-api.d.ts +50 -0
  75. package/dist/core/verse/github-api.js +211 -0
  76. package/dist/core/verse/github-api.js.map +1 -0
  77. package/dist/core/verse/github-proposal.d.ts +64 -0
  78. package/dist/core/verse/github-proposal.js +186 -0
  79. package/dist/core/verse/github-proposal.js.map +1 -0
  80. package/dist/core/verse/github-repo.d.ts +104 -0
  81. package/dist/core/verse/github-repo.js +476 -0
  82. package/dist/core/verse/github-repo.js.map +1 -0
  83. package/dist/core/verse/github-types.d.ts +174 -0
  84. package/dist/core/verse/github-types.js +31 -0
  85. package/dist/core/verse/github-types.js.map +1 -0
  86. package/dist/core/verse/mcp-cli-health.d.ts +149 -0
  87. package/dist/core/verse/mcp-cli-health.js +227 -0
  88. package/dist/core/verse/mcp-cli-health.js.map +1 -0
  89. package/dist/core/verse/mcp-control-api.d.ts +68 -0
  90. package/dist/core/verse/mcp-control-api.js +322 -0
  91. package/dist/core/verse/mcp-control-api.js.map +1 -0
  92. package/dist/core/verse/mcp-mutation.d.ts +187 -0
  93. package/dist/core/verse/mcp-mutation.js +471 -0
  94. package/dist/core/verse/mcp-mutation.js.map +1 -0
  95. package/dist/core/verse/mcp-scope.d.ts +114 -0
  96. package/dist/core/verse/mcp-scope.js +149 -0
  97. package/dist/core/verse/mcp-scope.js.map +1 -0
  98. package/dist/core/verse/mcp-seat-view.d.ts +197 -0
  99. package/dist/core/verse/mcp-seat-view.js +322 -0
  100. package/dist/core/verse/mcp-seat-view.js.map +1 -0
  101. package/dist/core/verse/path-guard.d.ts +115 -0
  102. package/dist/core/verse/path-guard.js +171 -0
  103. package/dist/core/verse/path-guard.js.map +1 -0
  104. package/dist/core/verse/seats.js +30 -2
  105. package/dist/core/verse/seats.js.map +1 -1
  106. package/dist/core/verse/session-engine.js +60 -1
  107. package/dist/core/verse/session-engine.js.map +1 -1
  108. package/dist/core/verse/session-store.js +20 -0
  109. package/dist/core/verse/session-store.js.map +1 -1
  110. package/dist/core/verse/types.d.ts +225 -1
  111. package/dist/core/verse/types.js +26 -0
  112. package/dist/core/verse/types.js.map +1 -1
  113. package/dist/core/verse/verse-api.d.ts +16 -1
  114. package/dist/core/verse/verse-api.js +338 -16
  115. package/dist/core/verse/verse-api.js.map +1 -1
  116. package/dist/core/verse/workspaces.d.ts +130 -0
  117. package/dist/core/verse/workspaces.js +501 -0
  118. package/dist/core/verse/workspaces.js.map +1 -0
  119. package/dist/core/web/api.js +23 -0
  120. package/dist/core/web/api.js.map +1 -1
  121. package/dist/core/web/public/next/assets/{App-LuILXjWG.js → App-CsbPYQqy.js} +2 -2
  122. package/dist/core/web/public/next/assets/{App-LuILXjWG.js.map → App-CsbPYQqy.js.map} +1 -1
  123. package/dist/core/web/public/next/assets/{ApprovalsSection-B_Xor8JH.js → ApprovalsSection-CBZquyLK.js} +2 -2
  124. package/dist/core/web/public/next/assets/{ApprovalsSection-B_Xor8JH.js.map → ApprovalsSection-CBZquyLK.js.map} +1 -1
  125. package/dist/core/web/public/next/assets/AutonomySection-CQVpEdCE.js +2 -0
  126. package/dist/core/web/public/next/assets/{AutonomySection-BEwITtPJ.js.map → AutonomySection-CQVpEdCE.js.map} +1 -1
  127. package/dist/core/web/public/next/assets/AutonomySection-DTN6m6QE.css +1 -0
  128. package/dist/core/web/public/next/assets/ChatSection-DiRvNX3Q.css +1 -0
  129. package/dist/core/web/public/next/assets/ChatSection-DmE9K0Tg.js +77 -0
  130. package/dist/core/web/public/next/assets/ChatSection-DmE9K0Tg.js.map +1 -0
  131. package/dist/core/web/public/next/assets/{ConfirmDialog-BqkZdPs_.js → ConfirmDialog-deO0C0iY.js} +2 -2
  132. package/dist/core/web/public/next/assets/{ConfirmDialog-BqkZdPs_.js.map → ConfirmDialog-deO0C0iY.js.map} +1 -1
  133. package/dist/core/web/public/next/assets/{Dialog-CPmedg4S.js → Dialog-CNd7q89m.js} +2 -2
  134. package/dist/core/web/public/next/assets/{Dialog-CPmedg4S.js.map → Dialog-CNd7q89m.js.map} +1 -1
  135. package/dist/core/web/public/next/assets/{DiffViewer-DmPJbeM_.js → DiffViewer-DTO0KRuG.js} +2 -2
  136. package/dist/core/web/public/next/assets/{DiffViewer-DmPJbeM_.js.map → DiffViewer-DTO0KRuG.js.map} +1 -1
  137. package/dist/core/web/public/next/assets/{Epistemic-M3SxLHjq.js → Epistemic-53PikaUI.js} +2 -2
  138. package/dist/core/web/public/next/assets/{Epistemic-M3SxLHjq.js.map → Epistemic-53PikaUI.js.map} +1 -1
  139. package/dist/core/web/public/next/assets/{Meter-D_X7c9U3.js → Meter-DRWZQgr1.js} +2 -2
  140. package/dist/core/web/public/next/assets/{Meter-D_X7c9U3.js.map → Meter-DRWZQgr1.js.map} +1 -1
  141. package/dist/core/web/public/next/assets/{MutationTokenDialog-Ba5ZHu-8.js → MutationTokenDialog-DYF8n_RD.js} +2 -2
  142. package/dist/core/web/public/next/assets/{MutationTokenDialog-Ba5ZHu-8.js.map → MutationTokenDialog-DYF8n_RD.js.map} +1 -1
  143. package/dist/core/web/public/next/assets/{RefreshIndicator-vHGpmyzb.js → RefreshIndicator-DXJQXKyA.js} +2 -2
  144. package/dist/core/web/public/next/assets/{RefreshIndicator-vHGpmyzb.js.map → RefreshIndicator-DXJQXKyA.js.map} +1 -1
  145. package/dist/core/web/public/next/assets/{ResourcePoolConsoleApp-B5g6JEVk.js → ResourcePoolConsoleApp-hDSEFdLU.js} +2 -2
  146. package/dist/core/web/public/next/assets/{ResourcePoolConsoleApp-B5g6JEVk.js.map → ResourcePoolConsoleApp-hDSEFdLU.js.map} +1 -1
  147. package/dist/core/web/public/next/assets/{RouteErrorBoundary-CroxuKoi.js → RouteErrorBoundary-CZd7ln8v.js} +2 -2
  148. package/dist/core/web/public/next/assets/{RouteErrorBoundary-CroxuKoi.js.map → RouteErrorBoundary-CZd7ln8v.js.map} +1 -1
  149. package/dist/core/web/public/next/assets/{SettingsSection-p-7FCGfn.js → SettingsSection-C9Qs9JWW.js} +2 -2
  150. package/dist/core/web/public/next/assets/{SettingsSection-p-7FCGfn.js.map → SettingsSection-C9Qs9JWW.js.map} +1 -1
  151. package/dist/core/web/public/next/assets/{Skeleton-4qq4HuJO.js → Skeleton-YkcOpgFb.js} +2 -2
  152. package/dist/core/web/public/next/assets/{Skeleton-4qq4HuJO.js.map → Skeleton-YkcOpgFb.js.map} +1 -1
  153. package/dist/core/web/public/next/assets/{StatusBadge-BbEdqEGn.js → StatusBadge-DJw0LSPg.js} +2 -2
  154. package/dist/core/web/public/next/assets/{StatusBadge-BbEdqEGn.js.map → StatusBadge-DJw0LSPg.js.map} +1 -1
  155. package/dist/core/web/public/next/assets/{TableView-nyYs7Sv1.js → TableView-Bj-w1O6o.js} +2 -2
  156. package/dist/core/web/public/next/assets/{TableView-nyYs7Sv1.js.map → TableView-Bj-w1O6o.js.map} +1 -1
  157. package/dist/core/web/public/next/assets/{UniverseConsoleApp-DjTpQUrA.js → UniverseConsoleApp-Bs2fxaen.js} +2 -2
  158. package/dist/core/web/public/next/assets/{UniverseConsoleApp-DjTpQUrA.js.map → UniverseConsoleApp-Bs2fxaen.js.map} +1 -1
  159. package/dist/core/web/public/next/assets/{UniverseView-BtApwayT.js → UniverseView-B6b2hw-8.js} +2 -2
  160. package/dist/core/web/public/next/assets/{UniverseView-BtApwayT.js.map → UniverseView-B6b2hw-8.js.map} +1 -1
  161. package/dist/core/web/public/next/assets/{UsageSection-Db99N6ao.js → UsageSection-C__ziNkV.js} +2 -2
  162. package/dist/core/web/public/next/assets/{UsageSection-Db99N6ao.js.map → UsageSection-C__ziNkV.js.map} +1 -1
  163. package/dist/core/web/public/next/assets/{VerseConsoleApp-COa3J2dO.js → VerseConsoleApp-Cu5aG6J6.js} +3 -3
  164. package/dist/core/web/public/next/assets/VerseConsoleApp-Cu5aG6J6.js.map +1 -0
  165. package/dist/core/web/public/next/assets/{global-CNVapoV1.js → global-BHjd6fVZ.js} +2 -2
  166. package/dist/core/web/public/next/assets/{global-CNVapoV1.js.map → global-BHjd6fVZ.js.map} +1 -1
  167. package/dist/core/web/public/next/assets/index-CJ-e8YA9.js +2 -0
  168. package/dist/core/web/public/next/assets/index-CJ-e8YA9.js.map +1 -0
  169. package/dist/core/web/public/next/assets/{index-BkUlX2Se.js → index-CpgkRaTi.js} +3 -3
  170. package/dist/core/web/public/next/assets/{index-BkUlX2Se.js.map → index-CpgkRaTi.js.map} +1 -1
  171. package/dist/core/web/public/next/assets/{queries-C9XS4SYq.js → queries-856qUN3Y.js} +2 -2
  172. package/dist/core/web/public/next/assets/{queries-C9XS4SYq.js.map → queries-856qUN3Y.js.map} +1 -1
  173. package/dist/core/web/public/next/assets/{use-guarded-action-Bql1nA-z.js → use-guarded-action-DwaESKVy.js} +2 -2
  174. package/dist/core/web/public/next/assets/{use-guarded-action-Bql1nA-z.js.map → use-guarded-action-DwaESKVy.js.map} +1 -1
  175. package/dist/core/web/public/next/assets/verse-model-Dllo8rRt.js +2 -0
  176. package/dist/core/web/public/next/assets/{verse-model-IrNQKtER.js.map → verse-model-Dllo8rRt.js.map} +1 -1
  177. package/dist/core/web/public/next/assets/workspace-model-JgmWDKt4.js +2 -0
  178. package/dist/core/web/public/next/assets/workspace-model-JgmWDKt4.js.map +1 -0
  179. package/dist/core/web/public/next/index.html +1 -1
  180. package/dist/release-dependency-inventory.json +1 -1
  181. package/docs/README.md +4 -0
  182. package/package.json +1 -1
  183. package/dist/cli/activation.d.ts +0 -41
  184. package/dist/cli/activation.js +0 -485
  185. package/dist/cli/activation.js.map +0 -1
  186. package/dist/core/fleet/generated-repair-resolution.d.ts +0 -36
  187. package/dist/core/fleet/generated-repair-resolution.js +0 -245
  188. package/dist/core/fleet/generated-repair-resolution.js.map +0 -1
  189. package/dist/core/local-runtime/llama/port.d.ts +0 -17
  190. package/dist/core/local-runtime/llama/port.js +0 -47
  191. package/dist/core/local-runtime/llama/port.js.map +0 -1
  192. package/dist/core/local-runtime/llama/proxy-host.d.ts +0 -54
  193. package/dist/core/local-runtime/llama/proxy-host.js +0 -159
  194. package/dist/core/local-runtime/llama/proxy-host.js.map +0 -1
  195. package/dist/core/local-runtime/llama/proxy-process.d.ts +0 -148
  196. package/dist/core/local-runtime/llama/proxy-process.js +0 -250
  197. package/dist/core/local-runtime/llama/proxy-process.js.map +0 -1
  198. package/dist/core/local-runtime/llama/proxy-record.d.ts +0 -40
  199. package/dist/core/local-runtime/llama/proxy-record.js +0 -133
  200. package/dist/core/local-runtime/llama/proxy-record.js.map +0 -1
  201. package/dist/core/local-runtime/llama/proxy-supervisor.d.ts +0 -118
  202. package/dist/core/local-runtime/llama/proxy-supervisor.js +0 -511
  203. package/dist/core/local-runtime/llama/proxy-supervisor.js.map +0 -1
  204. package/dist/core/web/public/next/assets/AutonomySection-BB8RD-tv.css +0 -1
  205. package/dist/core/web/public/next/assets/AutonomySection-BEwITtPJ.js +0 -2
  206. package/dist/core/web/public/next/assets/ChatSection-DrxqhBPK.css +0 -1
  207. package/dist/core/web/public/next/assets/ChatSection-bRAzlMth.js +0 -77
  208. package/dist/core/web/public/next/assets/ChatSection-bRAzlMth.js.map +0 -1
  209. package/dist/core/web/public/next/assets/VerseConsoleApp-COa3J2dO.js.map +0 -1
  210. package/dist/core/web/public/next/assets/index-YNTgDG2b.js +0 -2
  211. package/dist/core/web/public/next/assets/index-YNTgDG2b.js.map +0 -1
  212. package/dist/core/web/public/next/assets/verse-model-IrNQKtER.js +0 -2
  213. package/node_modules/which/CHANGELOG.md +0 -166
@@ -1,2 +1,2 @@
1
- import{r as t,j as s}from"./index-BkUlX2Se.js";const x="_region_1818x_1",w="_toast_1818x_12",v="_success_1818x_27",y="_danger_1818x_30",g="_dismiss_1818x_34",a={region:x,toast:w,"slide-in":"_slide-in_1818x_1",success:v,danger:y,dismiss:g},_=t.createContext(null);function k(){const o=t.useContext(_);if(!o)throw new Error("useToast() called outside <ToastProvider>");return o}const j=5e3;function N({children:o}){const[r,n]=t.useState([]),h=t.useRef(0),c=t.useCallback(e=>{n(d=>d.filter(i=>i.id!==e))},[]),u=t.useCallback((e,d="neutral")=>{const i=h.current++;n(p=>[...p,{id:i,message:e,tone:d}]),setTimeout(()=>c(i),j)},[c]),m=t.useMemo(()=>({show:u}),[u]);return s.jsxs(_.Provider,{value:m,children:[o,s.jsx("div",{className:a.region,role:"status","aria-live":"polite",children:r.map(e=>s.jsxs("div",{className:`${a.toast} ${a[e.tone]}`,children:[s.jsx("span",{children:e.message}),s.jsx("button",{type:"button",className:a.dismiss,onClick:()=>c(e.id),"aria-label":"Dismiss",children:"×"})]},e.id))})]})}const f="_wrap_1759l_1",T="_title_1759l_14",C="_detail_1759l_21",S="_retry_1759l_27",l={wrap:f,title:T,detail:C,retry:S};class D extends t.Component{state={error:null};static getDerivedStateFromError(r){return{error:r}}componentDidCatch(r,n){console.error("[ashlr] view crashed while rendering",r,n.componentStack)}componentDidUpdate(r){this.state.error&&r.resetKey!==this.props.resetKey&&this.setState({error:null})}render(){return this.state.error?s.jsxs("div",{className:l.wrap,role:"alert",children:[s.jsx("p",{className:l.title,children:"This view hit an error and couldn't render."}),s.jsxs("p",{className:l.detail,children:[this.state.error.message||"Unknown error."," — the rest of ashlr is still working; pick another view from the sidebar, or retry this one."]}),s.jsx("button",{type:"button",className:l.retry,onClick:()=>this.setState({error:null}),children:"Retry this view"})]}):this.props.children}}export{D as R,N as T,k as u};
2
- //# sourceMappingURL=RouteErrorBoundary-CroxuKoi.js.map
1
+ import{r as t,j as s}from"./index-CpgkRaTi.js";const x="_region_1818x_1",w="_toast_1818x_12",v="_success_1818x_27",y="_danger_1818x_30",g="_dismiss_1818x_34",a={region:x,toast:w,"slide-in":"_slide-in_1818x_1",success:v,danger:y,dismiss:g},_=t.createContext(null);function k(){const o=t.useContext(_);if(!o)throw new Error("useToast() called outside <ToastProvider>");return o}const j=5e3;function N({children:o}){const[r,n]=t.useState([]),h=t.useRef(0),c=t.useCallback(e=>{n(d=>d.filter(i=>i.id!==e))},[]),u=t.useCallback((e,d="neutral")=>{const i=h.current++;n(p=>[...p,{id:i,message:e,tone:d}]),setTimeout(()=>c(i),j)},[c]),m=t.useMemo(()=>({show:u}),[u]);return s.jsxs(_.Provider,{value:m,children:[o,s.jsx("div",{className:a.region,role:"status","aria-live":"polite",children:r.map(e=>s.jsxs("div",{className:`${a.toast} ${a[e.tone]}`,children:[s.jsx("span",{children:e.message}),s.jsx("button",{type:"button",className:a.dismiss,onClick:()=>c(e.id),"aria-label":"Dismiss",children:"×"})]},e.id))})]})}const f="_wrap_1759l_1",T="_title_1759l_14",C="_detail_1759l_21",S="_retry_1759l_27",l={wrap:f,title:T,detail:C,retry:S};class D extends t.Component{state={error:null};static getDerivedStateFromError(r){return{error:r}}componentDidCatch(r,n){console.error("[ashlr] view crashed while rendering",r,n.componentStack)}componentDidUpdate(r){this.state.error&&r.resetKey!==this.props.resetKey&&this.setState({error:null})}render(){return this.state.error?s.jsxs("div",{className:l.wrap,role:"alert",children:[s.jsx("p",{className:l.title,children:"This view hit an error and couldn't render."}),s.jsxs("p",{className:l.detail,children:[this.state.error.message||"Unknown error."," — the rest of ashlr is still working; pick another view from the sidebar, or retry this one."]}),s.jsx("button",{type:"button",className:l.retry,onClick:()=>this.setState({error:null}),children:"Retry this view"})]}):this.props.children}}export{D as R,N as T,k as u};
2
+ //# sourceMappingURL=RouteErrorBoundary-CZd7ln8v.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"RouteErrorBoundary-CroxuKoi.js","sources":["../../../../../../src/web-ui/components/primitives/Toast.tsx","../../../../../../src/web-ui/components/primitives/RouteErrorBoundary.tsx"],"sourcesContent":["/**\n * components/primitives/Toast.tsx — app-wide notifications. A single\n * aria-live region so screen readers announce toasts once, not per-toast\n * duplicate regions.\n */\nimport { createContext, useCallback, useContext, useMemo, useRef, useState, type ReactNode } from 'react';\nimport styles from './Toast.module.css';\n\nexport type ToastTone = 'neutral' | 'success' | 'danger';\n\ninterface ToastItem {\n id: number;\n message: string;\n tone: ToastTone;\n}\n\ninterface ToastContextValue {\n show: (message: string, tone?: ToastTone) => void;\n}\n\nconst ToastContext = createContext<ToastContextValue | null>(null);\n\nexport function useToast(): ToastContextValue {\n const ctx = useContext(ToastContext);\n if (!ctx) throw new Error('useToast() called outside <ToastProvider>');\n return ctx;\n}\n\nconst AUTO_DISMISS_MS = 5000;\n\nexport function ToastProvider({ children }: { children: ReactNode }) {\n const [toasts, setToasts] = useState<ToastItem[]>([]);\n const nextId = useRef(0);\n\n const dismiss = useCallback((id: number) => {\n setToasts((prev) => prev.filter((t) => t.id !== id));\n }, []);\n\n const show = useCallback(\n (message: string, tone: ToastTone = 'neutral') => {\n const id = nextId.current++;\n setToasts((prev) => [...prev, { id, message, tone }]);\n setTimeout(() => dismiss(id), AUTO_DISMISS_MS);\n },\n [dismiss],\n );\n\n const value = useMemo(() => ({ show }), [show]);\n\n return (\n <ToastContext.Provider value={value}>\n {children}\n <div className={styles.region} role=\"status\" aria-live=\"polite\">\n {toasts.map((t) => (\n <div key={t.id} className={`${styles.toast} ${styles[t.tone]}`}>\n <span>{t.message}</span>\n <button type=\"button\" className={styles.dismiss} onClick={() => dismiss(t.id)} aria-label=\"Dismiss\">\n ×\n </button>\n </div>\n ))}\n </div>\n </ToastContext.Provider>\n );\n}\n","/**\n * components/primitives/RouteErrorBoundary.tsx — the last line of defense\n * against a view crashing on real-world data that doesn't match its\n * expected shape (see SwarmsView.tsx's `plan?.tasks` guard for a concrete\n * example: 2 of 80 real swarm records on this machine predate the `plan`\n * field entirely).\n *\n * React error boundaries can only be class components — there is no hook\n * equivalent. Wraps `<Outlet/>` in Shell.tsx, not the whole app: if one\n * routed view throws during render, the sidebar/topbar/command palette\n * survive and the operator can navigate to a working view instead of being\n * stuck on a permanently blank screen (DESIGN.md §11 point 4 — \"never a\n * full-page error, the shell stays usable\" — extended here to cover\n * uncaught render exceptions, not just query-status `'error'`).\n */\nimport { Component, type ErrorInfo, type ReactNode } from 'react';\nimport styles from './RouteErrorBoundary.module.css';\n\ninterface Props {\n children: ReactNode;\n /** Identity that, when changed, resets the boundary — pass the route pathname. */\n resetKey: string;\n}\n\ninterface State {\n error: Error | null;\n}\n\nexport class RouteErrorBoundary extends Component<Props, State> {\n override state: State = { error: null };\n\n static getDerivedStateFromError(error: Error): State {\n return { error };\n }\n\n override componentDidCatch(error: Error, info: ErrorInfo) {\n console.error('[ashlr] view crashed while rendering', error, info.componentStack);\n }\n\n override componentDidUpdate(prevProps: Props) {\n if (this.state.error && prevProps.resetKey !== this.props.resetKey) {\n this.setState({ error: null });\n }\n }\n\n override render() {\n if (this.state.error) {\n return (\n <div className={styles.wrap} role=\"alert\">\n <p className={styles.title}>This view hit an error and couldn&apos;t render.</p>\n <p className={styles.detail}>\n {this.state.error.message || 'Unknown error.'} — the rest of ashlr is still working; pick another view\n from the sidebar, or retry this one.\n </p>\n <button type=\"button\" className={styles.retry} onClick={() => this.setState({ error: null })}>\n Retry this view\n </button>\n </div>\n );\n }\n return this.props.children;\n }\n}\n"],"names":["ToastContext","createContext","useToast","ctx","useContext","AUTO_DISMISS_MS","ToastProvider","children","toasts","setToasts","useState","nextId","useRef","dismiss","useCallback","id","prev","t","show","message","tone","value","useMemo","jsxs","jsx","styles","RouteErrorBoundary","Component","error","info","prevProps"],"mappings":"+OAoBMA,EAAeC,EAAAA,cAAwC,IAAI,EAE1D,SAASC,GAA8B,CAC5C,MAAMC,EAAMC,EAAAA,WAAWJ,CAAY,EACnC,GAAI,CAACG,EAAK,MAAM,IAAI,MAAM,2CAA2C,EACrE,OAAOA,CACT,CAEA,MAAME,EAAkB,IAEjB,SAASC,EAAc,CAAE,SAAAC,GAAqC,CACnE,KAAM,CAACC,EAAQC,CAAS,EAAIC,EAAAA,SAAsB,CAAA,CAAE,EAC9CC,EAASC,EAAAA,OAAO,CAAC,EAEjBC,EAAUC,cAAaC,GAAe,CAC1CN,EAAWO,GAASA,EAAK,OAAQC,GAAMA,EAAE,KAAOF,CAAE,CAAC,CACrD,EAAG,CAAA,CAAE,EAECG,EAAOJ,EAAAA,YACX,CAACK,EAAiBC,EAAkB,YAAc,CAChD,MAAML,EAAKJ,EAAO,UAClBF,EAAWO,GAAS,CAAC,GAAGA,EAAM,CAAE,GAAAD,EAAI,QAAAI,EAAS,KAAAC,CAAA,CAAM,CAAC,EACpD,WAAW,IAAMP,EAAQE,CAAE,EAAGV,CAAe,CAC/C,EACA,CAACQ,CAAO,CAAA,EAGJQ,EAAQC,EAAAA,QAAQ,KAAO,CAAE,KAAAJ,IAAS,CAACA,CAAI,CAAC,EAE9C,OACEK,EAAAA,KAACvB,EAAa,SAAb,CAAsB,MAAAqB,EACpB,SAAA,CAAAd,EACDiB,EAAAA,IAAC,MAAA,CAAI,UAAWC,EAAO,OAAQ,KAAK,SAAS,YAAU,SACpD,SAAAjB,EAAO,IAAKS,GACXM,EAAAA,KAAC,MAAA,CAAe,UAAW,GAAGE,EAAO,KAAK,IAAIA,EAAOR,EAAE,IAAI,CAAC,GAC1D,SAAA,CAAAO,EAAAA,IAAC,OAAA,CAAM,WAAE,OAAA,CAAQ,EACjBA,EAAAA,IAAC,SAAA,CAAO,KAAK,SAAS,UAAWC,EAAO,QAAS,QAAS,IAAMZ,EAAQI,EAAE,EAAE,EAAG,aAAW,UAAU,SAAA,GAAA,CAEpG,CAAA,GAJQA,EAAE,EAKZ,CACD,CAAA,CACH,CAAA,EACF,CAEJ,0HCpCO,MAAMS,UAA2BC,EAAAA,SAAwB,CACrD,MAAe,CAAE,MAAO,IAAA,EAEjC,OAAO,yBAAyBC,EAAqB,CACnD,MAAO,CAAE,MAAAA,CAAA,CACX,CAES,kBAAkBA,EAAcC,EAAiB,CACxD,QAAQ,MAAM,uCAAwCD,EAAOC,EAAK,cAAc,CAClF,CAES,mBAAmBC,EAAkB,CACxC,KAAK,MAAM,OAASA,EAAU,WAAa,KAAK,MAAM,UACxD,KAAK,SAAS,CAAE,MAAO,IAAA,CAAM,CAEjC,CAES,QAAS,CAChB,OAAI,KAAK,MAAM,aAEV,MAAA,CAAI,UAAWL,EAAO,KAAM,KAAK,QAChC,SAAA,CAAAD,EAAAA,IAAC,IAAA,CAAE,UAAWC,EAAO,MAAO,SAAA,8CAAgD,EAC5EF,EAAAA,KAAC,IAAA,CAAE,UAAWE,EAAO,OAClB,SAAA,CAAA,KAAK,MAAM,MAAM,SAAW,iBAAiB,+FAAA,EAEhD,QACC,SAAA,CAAO,KAAK,SAAS,UAAWA,EAAO,MAAO,QAAS,IAAM,KAAK,SAAS,CAAE,MAAO,IAAA,CAAM,EAAG,SAAA,iBAAA,CAE9F,CAAA,EACF,EAGG,KAAK,MAAM,QACpB,CACF"}
1
+ {"version":3,"file":"RouteErrorBoundary-CZd7ln8v.js","sources":["../../../../../../src/web-ui/components/primitives/Toast.tsx","../../../../../../src/web-ui/components/primitives/RouteErrorBoundary.tsx"],"sourcesContent":["/**\n * components/primitives/Toast.tsx — app-wide notifications. A single\n * aria-live region so screen readers announce toasts once, not per-toast\n * duplicate regions.\n */\nimport { createContext, useCallback, useContext, useMemo, useRef, useState, type ReactNode } from 'react';\nimport styles from './Toast.module.css';\n\nexport type ToastTone = 'neutral' | 'success' | 'danger';\n\ninterface ToastItem {\n id: number;\n message: string;\n tone: ToastTone;\n}\n\ninterface ToastContextValue {\n show: (message: string, tone?: ToastTone) => void;\n}\n\nconst ToastContext = createContext<ToastContextValue | null>(null);\n\nexport function useToast(): ToastContextValue {\n const ctx = useContext(ToastContext);\n if (!ctx) throw new Error('useToast() called outside <ToastProvider>');\n return ctx;\n}\n\nconst AUTO_DISMISS_MS = 5000;\n\nexport function ToastProvider({ children }: { children: ReactNode }) {\n const [toasts, setToasts] = useState<ToastItem[]>([]);\n const nextId = useRef(0);\n\n const dismiss = useCallback((id: number) => {\n setToasts((prev) => prev.filter((t) => t.id !== id));\n }, []);\n\n const show = useCallback(\n (message: string, tone: ToastTone = 'neutral') => {\n const id = nextId.current++;\n setToasts((prev) => [...prev, { id, message, tone }]);\n setTimeout(() => dismiss(id), AUTO_DISMISS_MS);\n },\n [dismiss],\n );\n\n const value = useMemo(() => ({ show }), [show]);\n\n return (\n <ToastContext.Provider value={value}>\n {children}\n <div className={styles.region} role=\"status\" aria-live=\"polite\">\n {toasts.map((t) => (\n <div key={t.id} className={`${styles.toast} ${styles[t.tone]}`}>\n <span>{t.message}</span>\n <button type=\"button\" className={styles.dismiss} onClick={() => dismiss(t.id)} aria-label=\"Dismiss\">\n ×\n </button>\n </div>\n ))}\n </div>\n </ToastContext.Provider>\n );\n}\n","/**\n * components/primitives/RouteErrorBoundary.tsx — the last line of defense\n * against a view crashing on real-world data that doesn't match its\n * expected shape (see SwarmsView.tsx's `plan?.tasks` guard for a concrete\n * example: 2 of 80 real swarm records on this machine predate the `plan`\n * field entirely).\n *\n * React error boundaries can only be class components — there is no hook\n * equivalent. Wraps `<Outlet/>` in Shell.tsx, not the whole app: if one\n * routed view throws during render, the sidebar/topbar/command palette\n * survive and the operator can navigate to a working view instead of being\n * stuck on a permanently blank screen (DESIGN.md §11 point 4 — \"never a\n * full-page error, the shell stays usable\" — extended here to cover\n * uncaught render exceptions, not just query-status `'error'`).\n */\nimport { Component, type ErrorInfo, type ReactNode } from 'react';\nimport styles from './RouteErrorBoundary.module.css';\n\ninterface Props {\n children: ReactNode;\n /** Identity that, when changed, resets the boundary — pass the route pathname. */\n resetKey: string;\n}\n\ninterface State {\n error: Error | null;\n}\n\nexport class RouteErrorBoundary extends Component<Props, State> {\n override state: State = { error: null };\n\n static getDerivedStateFromError(error: Error): State {\n return { error };\n }\n\n override componentDidCatch(error: Error, info: ErrorInfo) {\n console.error('[ashlr] view crashed while rendering', error, info.componentStack);\n }\n\n override componentDidUpdate(prevProps: Props) {\n if (this.state.error && prevProps.resetKey !== this.props.resetKey) {\n this.setState({ error: null });\n }\n }\n\n override render() {\n if (this.state.error) {\n return (\n <div className={styles.wrap} role=\"alert\">\n <p className={styles.title}>This view hit an error and couldn&apos;t render.</p>\n <p className={styles.detail}>\n {this.state.error.message || 'Unknown error.'} — the rest of ashlr is still working; pick another view\n from the sidebar, or retry this one.\n </p>\n <button type=\"button\" className={styles.retry} onClick={() => this.setState({ error: null })}>\n Retry this view\n </button>\n </div>\n );\n }\n return this.props.children;\n }\n}\n"],"names":["ToastContext","createContext","useToast","ctx","useContext","AUTO_DISMISS_MS","ToastProvider","children","toasts","setToasts","useState","nextId","useRef","dismiss","useCallback","id","prev","t","show","message","tone","value","useMemo","jsxs","jsx","styles","RouteErrorBoundary","Component","error","info","prevProps"],"mappings":"+OAoBMA,EAAeC,EAAAA,cAAwC,IAAI,EAE1D,SAASC,GAA8B,CAC5C,MAAMC,EAAMC,EAAAA,WAAWJ,CAAY,EACnC,GAAI,CAACG,EAAK,MAAM,IAAI,MAAM,2CAA2C,EACrE,OAAOA,CACT,CAEA,MAAME,EAAkB,IAEjB,SAASC,EAAc,CAAE,SAAAC,GAAqC,CACnE,KAAM,CAACC,EAAQC,CAAS,EAAIC,EAAAA,SAAsB,CAAA,CAAE,EAC9CC,EAASC,EAAAA,OAAO,CAAC,EAEjBC,EAAUC,cAAaC,GAAe,CAC1CN,EAAWO,GAASA,EAAK,OAAQC,GAAMA,EAAE,KAAOF,CAAE,CAAC,CACrD,EAAG,CAAA,CAAE,EAECG,EAAOJ,EAAAA,YACX,CAACK,EAAiBC,EAAkB,YAAc,CAChD,MAAML,EAAKJ,EAAO,UAClBF,EAAWO,GAAS,CAAC,GAAGA,EAAM,CAAE,GAAAD,EAAI,QAAAI,EAAS,KAAAC,CAAA,CAAM,CAAC,EACpD,WAAW,IAAMP,EAAQE,CAAE,EAAGV,CAAe,CAC/C,EACA,CAACQ,CAAO,CAAA,EAGJQ,EAAQC,EAAAA,QAAQ,KAAO,CAAE,KAAAJ,IAAS,CAACA,CAAI,CAAC,EAE9C,OACEK,EAAAA,KAACvB,EAAa,SAAb,CAAsB,MAAAqB,EACpB,SAAA,CAAAd,EACDiB,EAAAA,IAAC,MAAA,CAAI,UAAWC,EAAO,OAAQ,KAAK,SAAS,YAAU,SACpD,SAAAjB,EAAO,IAAKS,GACXM,EAAAA,KAAC,MAAA,CAAe,UAAW,GAAGE,EAAO,KAAK,IAAIA,EAAOR,EAAE,IAAI,CAAC,GAC1D,SAAA,CAAAO,EAAAA,IAAC,OAAA,CAAM,WAAE,OAAA,CAAQ,EACjBA,EAAAA,IAAC,SAAA,CAAO,KAAK,SAAS,UAAWC,EAAO,QAAS,QAAS,IAAMZ,EAAQI,EAAE,EAAE,EAAG,aAAW,UAAU,SAAA,GAAA,CAEpG,CAAA,GAJQA,EAAE,EAKZ,CACD,CAAA,CACH,CAAA,EACF,CAEJ,0HCpCO,MAAMS,UAA2BC,EAAAA,SAAwB,CACrD,MAAe,CAAE,MAAO,IAAA,EAEjC,OAAO,yBAAyBC,EAAqB,CACnD,MAAO,CAAE,MAAAA,CAAA,CACX,CAES,kBAAkBA,EAAcC,EAAiB,CACxD,QAAQ,MAAM,uCAAwCD,EAAOC,EAAK,cAAc,CAClF,CAES,mBAAmBC,EAAkB,CACxC,KAAK,MAAM,OAASA,EAAU,WAAa,KAAK,MAAM,UACxD,KAAK,SAAS,CAAE,MAAO,IAAA,CAAM,CAEjC,CAES,QAAS,CAChB,OAAI,KAAK,MAAM,aAEV,MAAA,CAAI,UAAWL,EAAO,KAAM,KAAK,QAChC,SAAA,CAAAD,EAAAA,IAAC,IAAA,CAAE,UAAWC,EAAO,MAAO,SAAA,8CAAgD,EAC5EF,EAAAA,KAAC,IAAA,CAAE,UAAWE,EAAO,OAClB,SAAA,CAAA,KAAK,MAAM,MAAM,SAAW,iBAAiB,+FAAA,EAEhD,QACC,SAAA,CAAO,KAAK,SAAS,UAAWA,EAAO,MAAO,QAAS,IAAM,KAAK,SAAS,CAAE,MAAO,IAAA,CAAM,EAAG,SAAA,iBAAA,CAE9F,CAAA,EACF,EAGG,KAAK,MAAM,QACpB,CACF"}
@@ -1,2 +1,2 @@
1
- import{r as v,j as e}from"./index-BkUlX2Se.js";import{H as z,I as L,J as A,K as B,h as W,u as K,c as U,n as G,L as V}from"./global-CNVapoV1.js";import{x as Y,B as f,y as J,z as T,D as Q,E as X,F as Z,G as ee,H as ne,J as te,K as se,L as ae,M as ie}from"./VerseConsoleApp-COa3J2dO.js";import"./index-YNTgDG2b.js";import{u as re}from"./RouteErrorBoundary-CroxuKoi.js";import{M as oe}from"./Meter-D_X7c9U3.js";import{S as q}from"./StatusBadge-BbEdqEGn.js";import{D as le}from"./Dialog-CPmedg4S.js";import"./queries-C9XS4SYq.js";const ce="_field_ki2n9_1",de="_label_ki2n9_8",ue="_shell_ki2n9_15",he="_sm_ki2n9_29",pe="_input_ki2n9_33",me="_invalid_ki2n9_50",be="_mono_ki2n9_80",_e="_prefix_ki2n9_85",fe="_hint_ki2n9_91",xe="_error_ki2n9_97",x={field:ce,label:de,shell:ue,sm:he,input:pe,invalid:me,mono:be,prefix:_e,hint:fe,error:xe};function O({label:n,hint:t,error:s,size:i="md",mono:r=!1,prefix:o,className:d,id:c,...h}){const p=v.useId(),a=c??p,u=`${a}-hint`,m=`${a}-error`,_=[h["aria-describedby"],t?u:null,s?m:null].filter(Boolean).join(" ");return e.jsxs("div",{className:`${x.field} ${d??""}`,children:[n?e.jsx("label",{className:x.label,htmlFor:a,children:n}):null,e.jsxs("div",{className:`${x.shell} ${x[i]} ${s?x.invalid:""}`,children:[o?e.jsx("span",{className:x.prefix,children:o}):null,e.jsx("input",{...h,id:a,className:`${x.input} ${r?x.mono:""}`,"aria-invalid":s?!0:h["aria-invalid"],"aria-describedby":_||void 0})]}),t?e.jsx("p",{id:u,className:x.hint,children:t}):null,s?e.jsx("p",{id:m,className:x.error,role:"alert",children:s}):null]})}const ge="_group_15ia8_1",ve="_block_15ia8_11",je="_option_15ia8_16",we="_sm_15ia8_45",ke="_glyph_15ia8_72",w={group:ge,block:ve,option:je,sm:we,glyph:ke};function S({options:n,value:t,onChange:s,size:i="md",block:r=!1,className:o,...d}){const c=v.useRef(null);function h(p){const a=n.filter(_=>!_.disabled);if(a.length===0)return;const u=a.findIndex(_=>_.value===t),m=a[((u+p)%a.length+a.length)%a.length];s(m.value),requestAnimationFrame(()=>{c.current?.querySelector(`[data-value="${m.value}"]`)?.focus()})}return e.jsx("div",{ref:c,role:"radiogroup",className:`${w.group} ${w[i]} ${r?w.block:""} ${o??""}`,...d,children:n.map(p=>{const a=p.value===t;return e.jsxs("button",{type:"button",role:"radio","aria-checked":a,"aria-label":p.ariaLabel,"data-value":p.value,tabIndex:a?0:-1,disabled:p.disabled,className:w.option,onClick:()=>s(p.value),onKeyDown:u=>{u.key==="ArrowRight"||u.key==="ArrowDown"?(u.preventDefault(),h(1)):(u.key==="ArrowLeft"||u.key==="ArrowUp")&&(u.preventDefault(),h(-1))},children:[p.icon?e.jsx("span",{className:w.glyph,children:p.icon}):null,p.label]},p.value)})})}const ye="_field_228wn_1",Ne="_label_228wn_8",Se="_row_228wn_15",$e="_value_228wn_22",Ie="_input_228wn_32",k={field:ye,label:Ne,row:Se,value:$e,input:Ie};function C({label:n,value:t,min:s=0,max:i=100,valueLabel:r,valueText:o,trackImage:d,className:c,id:h,...p}){const a=v.useId(),u=h??a,m=Math.max(1,i-s),_=Math.round((t-s)/m*100);return e.jsxs("div",{className:`${k.field} ${c??""}`,children:[n?e.jsx("label",{className:k.label,htmlFor:u,children:n}):null,e.jsxs("div",{className:k.row,children:[e.jsx("input",{...p,id:u,type:"range",className:k.input,value:t,min:s,max:i,"aria-valuetext":o,style:{"--slider-fill":`${_}%`,...d?{"--slider-track-image":d}:{}},"data-custom-track":d?"true":void 0}),r!==void 0?e.jsx("span",{className:k.value,children:r}):null]})]})}const Ce="_wrapper_1xq82_1",Te="_label_1xq82_8",qe="_track_1xq82_13",Re="_knob_1xq82_44",$={wrapper:Ce,label:Te,track:qe,knob:Re};function Le({checked:n,onChange:t,label:s,disabled:i=!1,id:r,className:o,...d}){const c=e.jsx("button",{type:"button",id:r,role:"switch","aria-checked":n,disabled:i,className:$.track,onClick:()=>t(!n),...d,children:e.jsx("span",{className:$.knob,"aria-hidden":"true"})});return s?e.jsxs("label",{className:`${$.wrapper} ${o??""}`,children:[c,e.jsx("span",{className:$.label,children:s})]}):e.jsx("span",{className:o,children:c})}const Ae="_section_3qpbp_5",Me="_strip_3qpbp_13",De="_stripTitle_3qpbp_25",He="_scroll_3qpbp_32",Ee="_column_3qpbp_38",Pe="_panel_3qpbp_51",Oe="_panelHead_3qpbp_56",Fe="_panelTitle_3qpbp_64",ze="_panelBody_3qpbp_74",Be="_row_3qpbp_81",We="_rowStacked_3qpbp_90",Ke="_rowText_3qpbp_95",Ue="_rowLabel_3qpbp_99",Ge="_rowDescription_3qpbp_107",Ve="_rowControl_3qpbp_114",Ye="_swatches_3qpbp_140",Je="_swatch_3qpbp_140",Qe="_swatchCheck_3qpbp_165",Xe="_sliderStack_3qpbp_173",Ze="_contrastWarning_3qpbp_180",en="_preview_3qpbp_197",nn="_previewRow_3qpbp_207",tn="_previewHeading_3qpbp_214",sn="_previewBody_3qpbp_222",an="_previewNumerals_3qpbp_228",rn="_origin_3qpbp_238",on="_note_3qpbp_242",ln="_noteIcon_3qpbp_258",cn="_code_3qpbp_249",dn="_shortcuts_3qpbp_278",un="_shortcut_3qpbp_278",hn="_keys_3qpbp_294",pn="_key_3qpbp_294",mn="_about_3qpbp_315",bn="_aboutLine_3qpbp_321",_n="_aboutName_3qpbp_329",fn="_link_3qpbp_338",l={section:Ae,strip:Me,stripTitle:De,scroll:He,column:Ee,panel:Pe,panelHead:Oe,panelTitle:Fe,panelBody:ze,row:Be,rowStacked:We,rowText:Ke,rowLabel:Ue,rowDescription:Ge,rowControl:Ve,swatches:Ye,swatch:Je,swatchCheck:Qe,sliderStack:Xe,contrastWarning:Ze,preview:en,previewRow:nn,previewHeading:tn,previewBody:sn,previewNumerals:an,origin:rn,note:on,noteIcon:ln,code:cn,shortcuts:dn,shortcut:un,keys:hn,key:pn,about:mn,aboutLine:bn,aboutName:_n,link:fn};function N({title:n,action:t,children:s}){return e.jsxs("section",{className:l.panel,children:[e.jsxs("div",{className:l.panelHead,children:[e.jsx("h3",{className:l.panelTitle,children:n}),t]}),e.jsx("div",{className:l.panelBody,children:s})]})}function b({label:n,description:t,htmlFor:s,labelId:i,stacked:r=!1,children:o}){const d=e.jsxs(e.Fragment,{children:[e.jsx("span",{className:l.rowLabel,id:i,children:n}),t?e.jsx("span",{className:l.rowDescription,children:t}):null]});return e.jsxs("div",{className:`${l.row} ${r?l.rowStacked:""}`,children:[e.jsx("div",{className:l.rowText,children:s?e.jsx("label",{htmlFor:s,className:l.rowText,children:d}):d}),e.jsx("div",{className:l.rowControl,children:o})]})}function xn(n,t){return n?`Last completed ${new Date(n).toLocaleDateString()}.`:t?"Skipped. Nothing was missed — it is all reachable from the sections themselves.":"Not seen yet."}function gn(){const{completedAt:n,dismissedAt:t,open:s}=Y();return e.jsx(N,{title:"Onboarding",children:e.jsx(b,{label:"Replay the first-run tour",description:`Your connected seats, whether a local runtime is available, and what each of the three stop controls really halts. ${xn(n,t)}`,children:e.jsx(f,{variant:"subtle",size:"sm",onClick:J,disabled:s,children:s?"Showing":"Replay"})})})}const vn="3.4.0",jn=vn,wn="Ashlr Verse";function kn(){return e.jsx(N,{title:"About",children:e.jsx("div",{className:`${l.row} ${l.rowStacked}`,children:e.jsxs("div",{className:l.about,children:[e.jsx("p",{className:l.aboutName,children:wn}),e.jsxs("p",{className:l.aboutLine,children:[e.jsxs(T,{mono:!0,children:["v",jn]}),e.jsx("span",{children:"ashlr-hub — local-first command center for agentic engineers."})]}),e.jsx("p",{className:l.aboutLine,children:"Every session, token and artifact stays on this machine. The console talks to one local server and no third-party service."}),e.jsx("p",{className:l.aboutLine,children:e.jsxs("a",{className:l.link,href:"https://github.com/ashlrai/ashlr-hub",target:"_blank",rel:"noreferrer noopener",children:["Source and changelog",e.jsx(Q,{size:12})]})})]})})})}const yn=/^#([0-9a-f]{3,8})$/i,Nn=/^(rgba?|hsla?)\(([^)]*)\)$/i;function g(n,t,s){return Math.min(s,Math.max(t,n))}function j(n,t){const s=n.trim();return s.endsWith("%")?Number.parseFloat(s)/100*t:Number.parseFloat(s)}function F(n,t,s){const i=(n%360+360)%360,r=(1-Math.abs(2*s-1))*t,o=r*(1-Math.abs(i/60%2-1)),d=s-r/2;let c;return i<60?c=[r,o,0]:i<120?c=[o,r,0]:i<180?c=[0,r,o]:i<240?c=[0,o,r]:i<300?c=[o,0,r]:c=[r,0,o],{r:Math.round((c[0]+d)*255),g:Math.round((c[1]+d)*255),b:Math.round((c[2]+d)*255)}}function Sn(n){const t=[];let s=0,i="";for(const r of n){if(r==="("?s+=1:r===")"&&(s-=1),r===","&&s===0){t.push(i),i="";continue}i+=r}return t.push(i),t.map(r=>r.trim()).filter(r=>r.length>0)}function M(n){const t=n.trim(),s=/\s(\d*\.?\d+)%$/.exec(t);if(s)return{color:t.slice(0,s.index).trim(),pct:Number.parseFloat(s[1])};const i=/^(\d*\.?\d+)%\s/.exec(t);return i?{color:t.slice(i[0].length).trim(),pct:Number.parseFloat(i[1])}:{color:t,pct:null}}function $n(n){const t=/^color-mix\((.*)\)$/is.exec(n.trim());if(!t)return null;const s=Sn(t[1]);if(s.length!==3||s[0].replace(/\s+/g," ").trim()!=="in srgb")return null;const i=M(s[1]),r=M(s[2]);if(!i||!r)return null;const o=y(i.color),d=y(r.color);if(!o||!d)return null;let c=i.pct,h=r.pct;c===null&&h===null?(c=50,h=50):c===null?c=100-h:h===null&&(h=100-c);const p=c+h;if(p<=0)return null;const a=c/p,u=h/p,m=o.a*a+d.a*u;if(m<=0)return{r:0,g:0,b:0,a:0};const _=R=>g(Math.round((o[R]*o.a*a+d[R]*d.a*u)/m),0,255);return{r:_("r"),g:_("g"),b:_("b"),a:g(m,0,1)}}function y(n){const t=n.trim().toLowerCase();if(t==="transparent")return{r:0,g:0,b:0,a:0};if(t.startsWith("color-mix("))return $n(t);const s=yn.exec(t);if(s){const a=s[1],u=m=>Number.parseInt(m.length===1?m+m:m,16);return a.length===3||a.length===4?{r:u(a[0]),g:u(a[1]),b:u(a[2]),a:a.length===4?u(a[3])/255:1}:a.length===6||a.length===8?{r:u(a.slice(0,2)),g:u(a.slice(2,4)),b:u(a.slice(4,6)),a:a.length===8?u(a.slice(6,8))/255:1}:null}const i=Nn.exec(t);if(!i)return null;const r=i[1],o=i[2].replace(/\//g," ").split(/[\s,]+/).filter(Boolean);if(o.length<3)return null;const d=o.length>=4?g(j(o[3],1),0,1):1;if(r.startsWith("rgb"))return{r:g(Math.round(j(o[0],255)),0,255),g:g(Math.round(j(o[1],255)),0,255),b:g(Math.round(j(o[2],255)),0,255),a:d};const c=Number.parseFloat(o[0]),h=g(j(o[1],1),0,1),p=g(j(o[2],1),0,1);return Number.isFinite(c)?{...F(c,h,p),a:d}:null}function D(n,t){if(n.a>=1)return n;const s=n.a;return{r:Math.round(n.r*s+t.r*(1-s)),g:Math.round(n.g*s+t.g*(1-s)),b:Math.round(n.b*s+t.b*(1-s)),a:1}}function H(n){const t=s=>{const i=s/255;return i<=.03928?i/12.92:((i+.055)/1.055)**2.4};return .2126*t(n.r)+.7152*t(n.g)+.0722*t(n.b)}function E(n,t,s="#ffffff"){const i=y(t),r=y(n),o=y(s);if(!i||!r||!o)return null;const d=D(i,o),c=D(r,d),h=H(c),p=H(d),[a,u]=h>=p?[h,p]:[p,h];return(a+.05)/(u+.05)}function I(n,t,s,i=0){const r=F(n,g(t,0,100)/100,g(s+i,0,100)/100),o=d=>d.toString(16).padStart(2,"0");return`#${o(r.r)}${o(r.g)}${o(r.b)}`}const In="#ffffff",Cn="#121214",Tn=6,P=8,qn=[{value:"system",label:"System",icon:e.jsx(ee,{})},{value:"light",label:"Light",icon:e.jsx(ne,{})},{value:"dark",label:"Dark",icon:e.jsx(te,{})}],Rn=[{value:"comfortable",label:"Comfortable"},{value:"compact",label:"Compact"}],Ln=[{value:"grotesk",label:"Space Grotesk"},{value:"ui",label:"UI sans"},{value:"mono",label:"Mono"}],An=[{value:"sharp",label:"Sharp"},{value:"default",label:"Default"},{value:"soft",label:"Soft"}];function Mn(n,t){return`linear-gradient(to right, ${[0,60,120,180,240,300,360].map(i=>`${I(i,n,t)} ${i/360*100}%`).join(", ")})`}function Dn(n,t,s){const i=I(n,t,s,-P),r=I(n,t,s,Tn+P),o=E(i,In),d=E(r,Cn),c=[];return o!==null&&o<4.5&&c.push("light"),d!==null&&d<4.5&&c.push("dark"),{lightRatio:o,darkRatio:d,failing:c}}function Hn({appearance:n,onChange:t,onReset:s}){const i=v.useId(),r=v.useId(),o=v.useId(),d=v.useId(),c=v.useId(),h=z(n),p=Dn(n.accentH,n.accentS,n.accentL);return e.jsxs(N,{title:"Appearance",action:e.jsx(f,{variant:"ghost",size:"sm",onClick:s,disabled:B(n),title:"Restore the shipped theme, accent, density, font, radius and motion",children:"Reset to defaults"}),children:[e.jsx(b,{label:"Theme",description:"System follows your OS appearance setting.",children:e.jsx(S,{"aria-label":"Theme",options:qn,value:n.theme,onChange:a=>t({theme:a})})}),e.jsx(b,{label:"Accent",labelId:i,description:h?`${h.label} — used for links, focus rings and the one primary action per surface.`:"Custom hue — used for links, focus rings and the one primary action per surface.",children:e.jsx("div",{className:l.swatches,role:"radiogroup","aria-labelledby":i,children:L.map(a=>{const u=h?.id===a.id;return e.jsx("button",{type:"button",role:"radio","aria-checked":u,"aria-label":a.label,tabIndex:u||!h&&a.id===L[0].id?0:-1,className:l.swatch,style:{background:I(a.h,a.s,a.l)},onClick:()=>t({accentH:a.h,accentS:a.s,accentL:a.l}),children:u?e.jsx("span",{className:l.swatchCheck,children:e.jsx(X,{size:12})}):null},a.id)})})}),e.jsx(b,{label:"Accent channels",description:"Hue, saturation and lightness are written straight onto the root element — the whole app follows as you drag.",stacked:!0,children:e.jsxs("div",{className:l.sliderStack,children:[e.jsx(C,{id:r,label:"Hue",min:0,max:359,value:n.accentH,valueLabel:`${n.accentH}°`,valueText:`${n.accentH} degrees`,trackImage:Mn(n.accentS,n.accentL),onChange:a=>t({accentH:Number(a.currentTarget.value)})}),e.jsx(C,{id:o,label:"Saturation",min:0,max:100,value:n.accentS,valueLabel:`${n.accentS}%`,valueText:`${n.accentS} percent`,onChange:a=>t({accentS:Number(a.currentTarget.value)})}),e.jsx(C,{id:d,label:"Lightness",min:A.min,max:A.max,value:n.accentL,valueLabel:`${n.accentL}%`,valueText:`${n.accentL} percent`,onChange:a=>t({accentL:Number(a.currentTarget.value)})}),p.failing.length>0?e.jsxs("p",{className:l.contrastWarning,role:"status",children:[e.jsx(Z,{size:14}),e.jsxs("span",{children:["This accent falls below 4.5:1 as link text in"," ",p.failing.length===2?"both themes":`${p.failing[0]} mode`,". Raise or lower the lightness to keep it readable."]})]}):null]})}),e.jsx(b,{label:"Density",description:"Row height and control padding across every view.",children:e.jsx(S,{"aria-label":"Density",options:Rn,value:n.density,onChange:a=>t({density:a})})}),e.jsx(b,{label:"Display font",description:"Titles, seat names, metrics and numerals. Body copy stays in the UI sans.",children:e.jsx(S,{"aria-label":"Display font",options:Ln,value:n.displayFont,onChange:a=>t({displayFont:a})})}),e.jsx(b,{label:"Corner radius",description:"Sharp reads like a terminal; soft reads like a consumer app.",children:e.jsx(S,{"aria-label":"Corner radius",options:An,value:n.radius,onChange:a=>t({radius:a})})}),e.jsx(b,{label:"Reduce motion",htmlFor:c,description:"Collapses every transition to 1ms. Defaults to your system preference; turning it off here overrides that.",children:e.jsx(Le,{id:c,checked:n.reduceMotion,onChange:a=>t({reduceMotion:a}),"aria-label":"Reduce motion"})}),e.jsx(b,{label:"Preview",description:"Live — these are the real primitives, not a picture of them.",stacked:!0,children:e.jsxs("div",{className:l.preview,children:[e.jsx("p",{className:l.previewHeading,children:"Ashlr Verse"}),e.jsxs("p",{className:l.previewBody,children:["Body copy stays in the UI sans at the reading measure; numerals like"," ",e.jsx("span",{className:l.previewNumerals,children:"18,420 / 66,000"})," use the display face."]}),e.jsxs("div",{className:l.previewRow,children:[e.jsx(f,{variant:"primary",size:"sm",children:"Primary"}),e.jsx(f,{variant:"subtle",size:"sm",children:"Subtle"}),e.jsx(f,{variant:"ghost",size:"sm",children:"Ghost"}),e.jsx(f,{variant:"danger",size:"sm",children:"Destructive"})]}),e.jsxs("div",{className:l.previewRow,children:[e.jsx(q,{status:"running"}),e.jsx(T,{engine:"claude",children:"Claude Max"}),e.jsx(T,{engine:"local",mono:!0,children:"qwen3-coder"})]}),e.jsx(oe,{value:18420,max:66e3,label:"Context"}),e.jsx(O,{"aria-label":"Preview field",placeholder:"A field at the current density",size:"sm"})]})})]})}function En(n){if(n===null)return"locked";const t=Math.max(0,Math.round((n-Date.now())/6e4));return t<=0?"expiring now":`unlocked for ${t} more minute${t===1?"":"s"}`}function Pn(){const n=W(),t=K(),s=re(),[i,r]=v.useState(!1),o=v.useRef(null),d=typeof window>"u"?"":window.location.origin;async function c(){try{await navigator.clipboard.writeText(d),s.show("Server address copied.")}catch{s.show("Could not reach the clipboard — select the field and copy manually.","danger")}}async function h(){r(!1),await G(),s.show("Disconnected. Paste the read token to reconnect.")}return e.jsxs(N,{title:"Connection",children:[e.jsxs(b,{label:"Server",description:"This window talks to one local hub. Nothing leaves your machine.",children:[e.jsx("div",{className:l.origin,children:e.jsx(O,{value:d,readOnly:!0,mono:!0,size:"sm","aria-label":"Server address"})}),e.jsx(f,{variant:"ghost",size:"sm",icon:e.jsx(se,{}),onClick:()=>void c(),children:"Copy"})]}),e.jsx(b,{label:"Read session",description:"A 15-minute signed cookie, renewed silently while this tab stays open.",children:e.jsx(q,{status:n==="authenticated"?"connected":n==="checking"?"checking":"disconnected",tone:n==="authenticated"?"success":n==="checking"?"running":"danger"})}),e.jsxs(b,{label:"Mutation hold",description:"Every action that changes something needs the mutation token. It is held in memory only, never stored, and clears when this tab closes.",children:[e.jsx(q,{status:t.hasHold?En(t.heldUntil):"locked",tone:t.hasHold?"success":"neutral"}),e.jsx(f,{variant:"subtle",size:"sm",icon:e.jsx(ae,{}),onClick:()=>{U(),s.show("Mutation hold cleared.")},disabled:!t.hasHold,children:"Lock now"})]}),e.jsx(b,{label:"Disconnect",description:"Ends the read session in this browser and clears the mutation hold. Chats on the server are untouched.",children:e.jsx(f,{variant:"danger",size:"sm",onClick:()=>r(!0),children:"Disconnect"})}),e.jsx("div",{className:l.row,children:e.jsxs("p",{className:l.note,children:[e.jsx("span",{className:l.noteIcon,children:e.jsx(ie,{size:14})}),e.jsxs("span",{children:[e.jsx("strong",{children:"Where the tokens come from."})," Start the console with"," ",e.jsx("code",{className:l.code,children:"ashlr verse"})," — it prints a read token and a mutation token in that terminal, and opens this page. The desktop app injects both for you. Tokens are never displayed here, and the hub never writes them into a page, a log line or an API response. Lost them? Stop the server and start it again; it mints a fresh pair."]})]})}),e.jsx(le,{open:i,onClose:()=>r(!1),titleId:"verse-settings-disconnect",title:"Disconnect from this server?",description:"You will need the read token again to get back in. Running sessions keep running on the server.",initialFocusRef:o,children:e.jsxs("div",{className:l.previewRow,style:{justifyContent:"flex-end"},children:[e.jsx(f,{ref:o,variant:"subtle",onClick:()=>r(!1),children:"Cancel"}),e.jsx(f,{variant:"danger",onClick:()=>void h(),children:"Disconnect"})]})})]})}function On(){if(typeof navigator>"u")return!0;const n=`${navigator.platform??""} ${navigator.userAgent??""}`;return/mac|iphone|ipad|ipod/i.test(n)}function Fn(n){return[{title:"Navigation",items:[{keys:[n,"1"],action:"Chat"},{keys:[n,"2"],action:"Autonomy"},{keys:[n,"3"],action:"Approvals"},{keys:[n,"4"],action:"Usage"},{keys:[n,"5"],action:"Settings"},{keys:[n,"K"],action:"Quick switcher"},{keys:[n,","],action:"Settings"}]},{title:"Chat",items:[{keys:[n,"N"],action:"New chat"},{keys:["Enter"],action:"Send message"},{keys:["Shift","Enter"],action:"New line"},{keys:["Esc"],action:"Stop dictation / close overlay"}]}]}function zn(){const n=On()?"⌘":"Ctrl";return e.jsx(N,{title:"Keyboard",children:e.jsx("div",{className:l.shortcuts,children:Fn(n).flatMap(t=>t.items.map(s=>e.jsxs("div",{className:l.shortcut,children:[e.jsx("span",{children:s.action}),e.jsx("span",{className:l.keys,children:s.keys.map(i=>e.jsx("kbd",{className:l.key,children:i},i))})]},`${t.title}-${s.action}-${s.keys.join("+")}`)))})})}function Xn(){const{appearance:n,set:t,reset:s}=V();return e.jsxs("div",{className:l.section,children:[e.jsx("header",{className:l.strip,"data-app-region":"drag",children:e.jsx("h2",{className:l.stripTitle,children:"Settings"})}),e.jsx("div",{className:l.scroll,children:e.jsxs("div",{className:l.column,children:[e.jsx(Hn,{appearance:n,onChange:t,onReset:s}),e.jsx(Pn,{}),e.jsx(zn,{}),e.jsx(gn,{}),e.jsx(kn,{})]})})]})}export{Xn as SettingsSection};
2
- //# sourceMappingURL=SettingsSection-p-7FCGfn.js.map
1
+ import{r as v,j as e}from"./index-CpgkRaTi.js";import{H as B,I as L,J as A,K as z,h as W,u as K,c as U,n as G,L as V}from"./global-BHjd6fVZ.js";import{B as Y,D as f,E as J,F as T,G as Q,H as X,J as Z,K as ee,L as ne,M as te,N as se,O as ae,Q as ie}from"./VerseConsoleApp-Cu5aG6J6.js";import"./index-CJ-e8YA9.js";import{u as re}from"./RouteErrorBoundary-CZd7ln8v.js";import{M as oe}from"./Meter-DRWZQgr1.js";import{S as q}from"./StatusBadge-DJw0LSPg.js";import{D as le}from"./Dialog-CNd7q89m.js";import"./queries-856qUN3Y.js";const ce="_field_ki2n9_1",de="_label_ki2n9_8",ue="_shell_ki2n9_15",he="_sm_ki2n9_29",pe="_input_ki2n9_33",me="_invalid_ki2n9_50",be="_mono_ki2n9_80",_e="_prefix_ki2n9_85",fe="_hint_ki2n9_91",xe="_error_ki2n9_97",x={field:ce,label:de,shell:ue,sm:he,input:pe,invalid:me,mono:be,prefix:_e,hint:fe,error:xe};function O({label:n,hint:t,error:s,size:i="md",mono:r=!1,prefix:o,className:d,id:c,...h}){const p=v.useId(),a=c??p,u=`${a}-hint`,m=`${a}-error`,_=[h["aria-describedby"],t?u:null,s?m:null].filter(Boolean).join(" ");return e.jsxs("div",{className:`${x.field} ${d??""}`,children:[n?e.jsx("label",{className:x.label,htmlFor:a,children:n}):null,e.jsxs("div",{className:`${x.shell} ${x[i]} ${s?x.invalid:""}`,children:[o?e.jsx("span",{className:x.prefix,children:o}):null,e.jsx("input",{...h,id:a,className:`${x.input} ${r?x.mono:""}`,"aria-invalid":s?!0:h["aria-invalid"],"aria-describedby":_||void 0})]}),t?e.jsx("p",{id:u,className:x.hint,children:t}):null,s?e.jsx("p",{id:m,className:x.error,role:"alert",children:s}):null]})}const ge="_group_15ia8_1",ve="_block_15ia8_11",je="_option_15ia8_16",we="_sm_15ia8_45",ke="_glyph_15ia8_72",w={group:ge,block:ve,option:je,sm:we,glyph:ke};function S({options:n,value:t,onChange:s,size:i="md",block:r=!1,className:o,...d}){const c=v.useRef(null);function h(p){const a=n.filter(_=>!_.disabled);if(a.length===0)return;const u=a.findIndex(_=>_.value===t),m=a[((u+p)%a.length+a.length)%a.length];s(m.value),requestAnimationFrame(()=>{c.current?.querySelector(`[data-value="${m.value}"]`)?.focus()})}return e.jsx("div",{ref:c,role:"radiogroup",className:`${w.group} ${w[i]} ${r?w.block:""} ${o??""}`,...d,children:n.map(p=>{const a=p.value===t;return e.jsxs("button",{type:"button",role:"radio","aria-checked":a,"aria-label":p.ariaLabel,"data-value":p.value,tabIndex:a?0:-1,disabled:p.disabled,className:w.option,onClick:()=>s(p.value),onKeyDown:u=>{u.key==="ArrowRight"||u.key==="ArrowDown"?(u.preventDefault(),h(1)):(u.key==="ArrowLeft"||u.key==="ArrowUp")&&(u.preventDefault(),h(-1))},children:[p.icon?e.jsx("span",{className:w.glyph,children:p.icon}):null,p.label]},p.value)})})}const ye="_field_228wn_1",Ne="_label_228wn_8",Se="_row_228wn_15",$e="_value_228wn_22",Ie="_input_228wn_32",k={field:ye,label:Ne,row:Se,value:$e,input:Ie};function C({label:n,value:t,min:s=0,max:i=100,valueLabel:r,valueText:o,trackImage:d,className:c,id:h,...p}){const a=v.useId(),u=h??a,m=Math.max(1,i-s),_=Math.round((t-s)/m*100);return e.jsxs("div",{className:`${k.field} ${c??""}`,children:[n?e.jsx("label",{className:k.label,htmlFor:u,children:n}):null,e.jsxs("div",{className:k.row,children:[e.jsx("input",{...p,id:u,type:"range",className:k.input,value:t,min:s,max:i,"aria-valuetext":o,style:{"--slider-fill":`${_}%`,...d?{"--slider-track-image":d}:{}},"data-custom-track":d?"true":void 0}),r!==void 0?e.jsx("span",{className:k.value,children:r}):null]})]})}const Ce="_wrapper_1xq82_1",Te="_label_1xq82_8",qe="_track_1xq82_13",Re="_knob_1xq82_44",$={wrapper:Ce,label:Te,track:qe,knob:Re};function Le({checked:n,onChange:t,label:s,disabled:i=!1,id:r,className:o,...d}){const c=e.jsx("button",{type:"button",id:r,role:"switch","aria-checked":n,disabled:i,className:$.track,onClick:()=>t(!n),...d,children:e.jsx("span",{className:$.knob,"aria-hidden":"true"})});return s?e.jsxs("label",{className:`${$.wrapper} ${o??""}`,children:[c,e.jsx("span",{className:$.label,children:s})]}):e.jsx("span",{className:o,children:c})}const Ae="_section_3qpbp_5",Me="_strip_3qpbp_13",De="_stripTitle_3qpbp_25",He="_scroll_3qpbp_32",Ee="_column_3qpbp_38",Pe="_panel_3qpbp_51",Oe="_panelHead_3qpbp_56",Fe="_panelTitle_3qpbp_64",Be="_panelBody_3qpbp_74",ze="_row_3qpbp_81",We="_rowStacked_3qpbp_90",Ke="_rowText_3qpbp_95",Ue="_rowLabel_3qpbp_99",Ge="_rowDescription_3qpbp_107",Ve="_rowControl_3qpbp_114",Ye="_swatches_3qpbp_140",Je="_swatch_3qpbp_140",Qe="_swatchCheck_3qpbp_165",Xe="_sliderStack_3qpbp_173",Ze="_contrastWarning_3qpbp_180",en="_preview_3qpbp_197",nn="_previewRow_3qpbp_207",tn="_previewHeading_3qpbp_214",sn="_previewBody_3qpbp_222",an="_previewNumerals_3qpbp_228",rn="_origin_3qpbp_238",on="_note_3qpbp_242",ln="_noteIcon_3qpbp_258",cn="_code_3qpbp_249",dn="_shortcuts_3qpbp_278",un="_shortcut_3qpbp_278",hn="_keys_3qpbp_294",pn="_key_3qpbp_294",mn="_about_3qpbp_315",bn="_aboutLine_3qpbp_321",_n="_aboutName_3qpbp_329",fn="_link_3qpbp_338",l={section:Ae,strip:Me,stripTitle:De,scroll:He,column:Ee,panel:Pe,panelHead:Oe,panelTitle:Fe,panelBody:Be,row:ze,rowStacked:We,rowText:Ke,rowLabel:Ue,rowDescription:Ge,rowControl:Ve,swatches:Ye,swatch:Je,swatchCheck:Qe,sliderStack:Xe,contrastWarning:Ze,preview:en,previewRow:nn,previewHeading:tn,previewBody:sn,previewNumerals:an,origin:rn,note:on,noteIcon:ln,code:cn,shortcuts:dn,shortcut:un,keys:hn,key:pn,about:mn,aboutLine:bn,aboutName:_n,link:fn};function N({title:n,action:t,children:s}){return e.jsxs("section",{className:l.panel,children:[e.jsxs("div",{className:l.panelHead,children:[e.jsx("h3",{className:l.panelTitle,children:n}),t]}),e.jsx("div",{className:l.panelBody,children:s})]})}function b({label:n,description:t,htmlFor:s,labelId:i,stacked:r=!1,children:o}){const d=e.jsxs(e.Fragment,{children:[e.jsx("span",{className:l.rowLabel,id:i,children:n}),t?e.jsx("span",{className:l.rowDescription,children:t}):null]});return e.jsxs("div",{className:`${l.row} ${r?l.rowStacked:""}`,children:[e.jsx("div",{className:l.rowText,children:s?e.jsx("label",{htmlFor:s,className:l.rowText,children:d}):d}),e.jsx("div",{className:l.rowControl,children:o})]})}function xn(n,t){return n?`Last completed ${new Date(n).toLocaleDateString()}.`:t?"Skipped. Nothing was missed — it is all reachable from the sections themselves.":"Not seen yet."}function gn(){const{completedAt:n,dismissedAt:t,open:s}=Y();return e.jsx(N,{title:"Onboarding",children:e.jsx(b,{label:"Replay the first-run tour",description:`Your connected seats, whether a local runtime is available, and what each of the three stop controls really halts. ${xn(n,t)}`,children:e.jsx(f,{variant:"subtle",size:"sm",onClick:J,disabled:s,children:s?"Showing":"Replay"})})})}const vn="3.5.0",jn=vn,wn="Ashlr Verse";function kn(){return e.jsx(N,{title:"About",children:e.jsx("div",{className:`${l.row} ${l.rowStacked}`,children:e.jsxs("div",{className:l.about,children:[e.jsx("p",{className:l.aboutName,children:wn}),e.jsxs("p",{className:l.aboutLine,children:[e.jsxs(T,{mono:!0,children:["v",jn]}),e.jsx("span",{children:"ashlr-hub — local-first command center for agentic engineers."})]}),e.jsx("p",{className:l.aboutLine,children:"Every session, token and artifact stays on this machine. The console talks to one local server and no third-party service."}),e.jsx("p",{className:l.aboutLine,children:e.jsxs("a",{className:l.link,href:"https://github.com/ashlrai/ashlr-hub",target:"_blank",rel:"noreferrer noopener",children:["Source and changelog",e.jsx(Q,{size:12})]})})]})})})}const yn=/^#([0-9a-f]{3,8})$/i,Nn=/^(rgba?|hsla?)\(([^)]*)\)$/i;function g(n,t,s){return Math.min(s,Math.max(t,n))}function j(n,t){const s=n.trim();return s.endsWith("%")?Number.parseFloat(s)/100*t:Number.parseFloat(s)}function F(n,t,s){const i=(n%360+360)%360,r=(1-Math.abs(2*s-1))*t,o=r*(1-Math.abs(i/60%2-1)),d=s-r/2;let c;return i<60?c=[r,o,0]:i<120?c=[o,r,0]:i<180?c=[0,r,o]:i<240?c=[0,o,r]:i<300?c=[o,0,r]:c=[r,0,o],{r:Math.round((c[0]+d)*255),g:Math.round((c[1]+d)*255),b:Math.round((c[2]+d)*255)}}function Sn(n){const t=[];let s=0,i="";for(const r of n){if(r==="("?s+=1:r===")"&&(s-=1),r===","&&s===0){t.push(i),i="";continue}i+=r}return t.push(i),t.map(r=>r.trim()).filter(r=>r.length>0)}function M(n){const t=n.trim(),s=/\s(\d*\.?\d+)%$/.exec(t);if(s)return{color:t.slice(0,s.index).trim(),pct:Number.parseFloat(s[1])};const i=/^(\d*\.?\d+)%\s/.exec(t);return i?{color:t.slice(i[0].length).trim(),pct:Number.parseFloat(i[1])}:{color:t,pct:null}}function $n(n){const t=/^color-mix\((.*)\)$/is.exec(n.trim());if(!t)return null;const s=Sn(t[1]);if(s.length!==3||s[0].replace(/\s+/g," ").trim()!=="in srgb")return null;const i=M(s[1]),r=M(s[2]);if(!i||!r)return null;const o=y(i.color),d=y(r.color);if(!o||!d)return null;let c=i.pct,h=r.pct;c===null&&h===null?(c=50,h=50):c===null?c=100-h:h===null&&(h=100-c);const p=c+h;if(p<=0)return null;const a=c/p,u=h/p,m=o.a*a+d.a*u;if(m<=0)return{r:0,g:0,b:0,a:0};const _=R=>g(Math.round((o[R]*o.a*a+d[R]*d.a*u)/m),0,255);return{r:_("r"),g:_("g"),b:_("b"),a:g(m,0,1)}}function y(n){const t=n.trim().toLowerCase();if(t==="transparent")return{r:0,g:0,b:0,a:0};if(t.startsWith("color-mix("))return $n(t);const s=yn.exec(t);if(s){const a=s[1],u=m=>Number.parseInt(m.length===1?m+m:m,16);return a.length===3||a.length===4?{r:u(a[0]),g:u(a[1]),b:u(a[2]),a:a.length===4?u(a[3])/255:1}:a.length===6||a.length===8?{r:u(a.slice(0,2)),g:u(a.slice(2,4)),b:u(a.slice(4,6)),a:a.length===8?u(a.slice(6,8))/255:1}:null}const i=Nn.exec(t);if(!i)return null;const r=i[1],o=i[2].replace(/\//g," ").split(/[\s,]+/).filter(Boolean);if(o.length<3)return null;const d=o.length>=4?g(j(o[3],1),0,1):1;if(r.startsWith("rgb"))return{r:g(Math.round(j(o[0],255)),0,255),g:g(Math.round(j(o[1],255)),0,255),b:g(Math.round(j(o[2],255)),0,255),a:d};const c=Number.parseFloat(o[0]),h=g(j(o[1],1),0,1),p=g(j(o[2],1),0,1);return Number.isFinite(c)?{...F(c,h,p),a:d}:null}function D(n,t){if(n.a>=1)return n;const s=n.a;return{r:Math.round(n.r*s+t.r*(1-s)),g:Math.round(n.g*s+t.g*(1-s)),b:Math.round(n.b*s+t.b*(1-s)),a:1}}function H(n){const t=s=>{const i=s/255;return i<=.03928?i/12.92:((i+.055)/1.055)**2.4};return .2126*t(n.r)+.7152*t(n.g)+.0722*t(n.b)}function E(n,t,s="#ffffff"){const i=y(t),r=y(n),o=y(s);if(!i||!r||!o)return null;const d=D(i,o),c=D(r,d),h=H(c),p=H(d),[a,u]=h>=p?[h,p]:[p,h];return(a+.05)/(u+.05)}function I(n,t,s,i=0){const r=F(n,g(t,0,100)/100,g(s+i,0,100)/100),o=d=>d.toString(16).padStart(2,"0");return`#${o(r.r)}${o(r.g)}${o(r.b)}`}const In="#ffffff",Cn="#121214",Tn=6,P=8,qn=[{value:"system",label:"System",icon:e.jsx(ee,{})},{value:"light",label:"Light",icon:e.jsx(ne,{})},{value:"dark",label:"Dark",icon:e.jsx(te,{})}],Rn=[{value:"comfortable",label:"Comfortable"},{value:"compact",label:"Compact"}],Ln=[{value:"grotesk",label:"Space Grotesk"},{value:"ui",label:"UI sans"},{value:"mono",label:"Mono"}],An=[{value:"sharp",label:"Sharp"},{value:"default",label:"Default"},{value:"soft",label:"Soft"}];function Mn(n,t){return`linear-gradient(to right, ${[0,60,120,180,240,300,360].map(i=>`${I(i,n,t)} ${i/360*100}%`).join(", ")})`}function Dn(n,t,s){const i=I(n,t,s,-P),r=I(n,t,s,Tn+P),o=E(i,In),d=E(r,Cn),c=[];return o!==null&&o<4.5&&c.push("light"),d!==null&&d<4.5&&c.push("dark"),{lightRatio:o,darkRatio:d,failing:c}}function Hn({appearance:n,onChange:t,onReset:s}){const i=v.useId(),r=v.useId(),o=v.useId(),d=v.useId(),c=v.useId(),h=B(n),p=Dn(n.accentH,n.accentS,n.accentL);return e.jsxs(N,{title:"Appearance",action:e.jsx(f,{variant:"ghost",size:"sm",onClick:s,disabled:z(n),title:"Restore the shipped theme, accent, density, font, radius and motion",children:"Reset to defaults"}),children:[e.jsx(b,{label:"Theme",description:"System follows your OS appearance setting.",children:e.jsx(S,{"aria-label":"Theme",options:qn,value:n.theme,onChange:a=>t({theme:a})})}),e.jsx(b,{label:"Accent",labelId:i,description:h?`${h.label} — used for links, focus rings and the one primary action per surface.`:"Custom hue — used for links, focus rings and the one primary action per surface.",children:e.jsx("div",{className:l.swatches,role:"radiogroup","aria-labelledby":i,children:L.map(a=>{const u=h?.id===a.id;return e.jsx("button",{type:"button",role:"radio","aria-checked":u,"aria-label":a.label,tabIndex:u||!h&&a.id===L[0].id?0:-1,className:l.swatch,style:{background:I(a.h,a.s,a.l)},onClick:()=>t({accentH:a.h,accentS:a.s,accentL:a.l}),children:u?e.jsx("span",{className:l.swatchCheck,children:e.jsx(X,{size:12})}):null},a.id)})})}),e.jsx(b,{label:"Accent channels",description:"Hue, saturation and lightness are written straight onto the root element — the whole app follows as you drag.",stacked:!0,children:e.jsxs("div",{className:l.sliderStack,children:[e.jsx(C,{id:r,label:"Hue",min:0,max:359,value:n.accentH,valueLabel:`${n.accentH}°`,valueText:`${n.accentH} degrees`,trackImage:Mn(n.accentS,n.accentL),onChange:a=>t({accentH:Number(a.currentTarget.value)})}),e.jsx(C,{id:o,label:"Saturation",min:0,max:100,value:n.accentS,valueLabel:`${n.accentS}%`,valueText:`${n.accentS} percent`,onChange:a=>t({accentS:Number(a.currentTarget.value)})}),e.jsx(C,{id:d,label:"Lightness",min:A.min,max:A.max,value:n.accentL,valueLabel:`${n.accentL}%`,valueText:`${n.accentL} percent`,onChange:a=>t({accentL:Number(a.currentTarget.value)})}),p.failing.length>0?e.jsxs("p",{className:l.contrastWarning,role:"status",children:[e.jsx(Z,{size:14}),e.jsxs("span",{children:["This accent falls below 4.5:1 as link text in"," ",p.failing.length===2?"both themes":`${p.failing[0]} mode`,". Raise or lower the lightness to keep it readable."]})]}):null]})}),e.jsx(b,{label:"Density",description:"Row height and control padding across every view.",children:e.jsx(S,{"aria-label":"Density",options:Rn,value:n.density,onChange:a=>t({density:a})})}),e.jsx(b,{label:"Display font",description:"Titles, seat names, metrics and numerals. Body copy stays in the UI sans.",children:e.jsx(S,{"aria-label":"Display font",options:Ln,value:n.displayFont,onChange:a=>t({displayFont:a})})}),e.jsx(b,{label:"Corner radius",description:"Sharp reads like a terminal; soft reads like a consumer app.",children:e.jsx(S,{"aria-label":"Corner radius",options:An,value:n.radius,onChange:a=>t({radius:a})})}),e.jsx(b,{label:"Reduce motion",htmlFor:c,description:"Collapses every transition to 1ms. Defaults to your system preference; turning it off here overrides that.",children:e.jsx(Le,{id:c,checked:n.reduceMotion,onChange:a=>t({reduceMotion:a}),"aria-label":"Reduce motion"})}),e.jsx(b,{label:"Preview",description:"Live — these are the real primitives, not a picture of them.",stacked:!0,children:e.jsxs("div",{className:l.preview,children:[e.jsx("p",{className:l.previewHeading,children:"Ashlr Verse"}),e.jsxs("p",{className:l.previewBody,children:["Body copy stays in the UI sans at the reading measure; numerals like"," ",e.jsx("span",{className:l.previewNumerals,children:"18,420 / 66,000"})," use the display face."]}),e.jsxs("div",{className:l.previewRow,children:[e.jsx(f,{variant:"primary",size:"sm",children:"Primary"}),e.jsx(f,{variant:"subtle",size:"sm",children:"Subtle"}),e.jsx(f,{variant:"ghost",size:"sm",children:"Ghost"}),e.jsx(f,{variant:"danger",size:"sm",children:"Destructive"})]}),e.jsxs("div",{className:l.previewRow,children:[e.jsx(q,{status:"running"}),e.jsx(T,{engine:"claude",children:"Claude Max"}),e.jsx(T,{engine:"local",mono:!0,children:"qwen3-coder"})]}),e.jsx(oe,{value:18420,max:66e3,label:"Context"}),e.jsx(O,{"aria-label":"Preview field",placeholder:"A field at the current density",size:"sm"})]})})]})}function En(n){if(n===null)return"locked";const t=Math.max(0,Math.round((n-Date.now())/6e4));return t<=0?"expiring now":`unlocked for ${t} more minute${t===1?"":"s"}`}function Pn(){const n=W(),t=K(),s=re(),[i,r]=v.useState(!1),o=v.useRef(null),d=typeof window>"u"?"":window.location.origin;async function c(){try{await navigator.clipboard.writeText(d),s.show("Server address copied.")}catch{s.show("Could not reach the clipboard — select the field and copy manually.","danger")}}async function h(){r(!1),await G(),s.show("Disconnected. Paste the read token to reconnect.")}return e.jsxs(N,{title:"Connection",children:[e.jsxs(b,{label:"Server",description:"This window talks to one local hub. Nothing leaves your machine.",children:[e.jsx("div",{className:l.origin,children:e.jsx(O,{value:d,readOnly:!0,mono:!0,size:"sm","aria-label":"Server address"})}),e.jsx(f,{variant:"ghost",size:"sm",icon:e.jsx(se,{}),onClick:()=>void c(),children:"Copy"})]}),e.jsx(b,{label:"Read session",description:"A 15-minute signed cookie, renewed silently while this tab stays open.",children:e.jsx(q,{status:n==="authenticated"?"connected":n==="checking"?"checking":"disconnected",tone:n==="authenticated"?"success":n==="checking"?"running":"danger"})}),e.jsxs(b,{label:"Mutation hold",description:"Every action that changes something needs the mutation token. It is held in memory only, never stored, and clears when this tab closes.",children:[e.jsx(q,{status:t.hasHold?En(t.heldUntil):"locked",tone:t.hasHold?"success":"neutral"}),e.jsx(f,{variant:"subtle",size:"sm",icon:e.jsx(ae,{}),onClick:()=>{U(),s.show("Mutation hold cleared.")},disabled:!t.hasHold,children:"Lock now"})]}),e.jsx(b,{label:"Disconnect",description:"Ends the read session in this browser and clears the mutation hold. Chats on the server are untouched.",children:e.jsx(f,{variant:"danger",size:"sm",onClick:()=>r(!0),children:"Disconnect"})}),e.jsx("div",{className:l.row,children:e.jsxs("p",{className:l.note,children:[e.jsx("span",{className:l.noteIcon,children:e.jsx(ie,{size:14})}),e.jsxs("span",{children:[e.jsx("strong",{children:"Where the tokens come from."})," Start the console with"," ",e.jsx("code",{className:l.code,children:"ashlr verse"})," — it prints a read token and a mutation token in that terminal, and opens this page. The desktop app injects both for you. Tokens are never displayed here, and the hub never writes them into a page, a log line or an API response. Lost them? Stop the server and start it again; it mints a fresh pair."]})]})}),e.jsx(le,{open:i,onClose:()=>r(!1),titleId:"verse-settings-disconnect",title:"Disconnect from this server?",description:"You will need the read token again to get back in. Running sessions keep running on the server.",initialFocusRef:o,children:e.jsxs("div",{className:l.previewRow,style:{justifyContent:"flex-end"},children:[e.jsx(f,{ref:o,variant:"subtle",onClick:()=>r(!1),children:"Cancel"}),e.jsx(f,{variant:"danger",onClick:()=>void h(),children:"Disconnect"})]})})]})}function On(){if(typeof navigator>"u")return!0;const n=`${navigator.platform??""} ${navigator.userAgent??""}`;return/mac|iphone|ipad|ipod/i.test(n)}function Fn(n){return[{title:"Navigation",items:[{keys:[n,"1"],action:"Chat"},{keys:[n,"2"],action:"Autonomy"},{keys:[n,"3"],action:"Approvals"},{keys:[n,"4"],action:"Usage"},{keys:[n,"5"],action:"Settings"},{keys:[n,"K"],action:"Quick switcher"},{keys:[n,","],action:"Settings"}]},{title:"Chat",items:[{keys:[n,"N"],action:"New chat"},{keys:["Enter"],action:"Send message"},{keys:["Shift","Enter"],action:"New line"},{keys:["Esc"],action:"Stop dictation / close overlay"}]}]}function Bn(){const n=On()?"⌘":"Ctrl";return e.jsx(N,{title:"Keyboard",children:e.jsx("div",{className:l.shortcuts,children:Fn(n).flatMap(t=>t.items.map(s=>e.jsxs("div",{className:l.shortcut,children:[e.jsx("span",{children:s.action}),e.jsx("span",{className:l.keys,children:s.keys.map(i=>e.jsx("kbd",{className:l.key,children:i},i))})]},`${t.title}-${s.action}-${s.keys.join("+")}`)))})})}function Xn(){const{appearance:n,set:t,reset:s}=V();return e.jsxs("div",{className:l.section,children:[e.jsx("header",{className:l.strip,"data-app-region":"drag",children:e.jsx("h2",{className:l.stripTitle,children:"Settings"})}),e.jsx("div",{className:l.scroll,children:e.jsxs("div",{className:l.column,children:[e.jsx(Hn,{appearance:n,onChange:t,onReset:s}),e.jsx(Pn,{}),e.jsx(Bn,{}),e.jsx(gn,{}),e.jsx(kn,{})]})})]})}export{Xn as SettingsSection};
2
+ //# sourceMappingURL=SettingsSection-C9Qs9JWW.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"SettingsSection-p-7FCGfn.js","sources":["../../../../../../src/web-ui/components/primitives/Input.tsx","../../../../../../src/web-ui/components/primitives/Segmented.tsx","../../../../../../src/web-ui/components/primitives/Slider.tsx","../../../../../../src/web-ui/components/primitives/Switch.tsx","../../../../../../src/web-ui/routes/verse/sections/SettingRow.tsx","../../../../../../src/web-ui/routes/verse/onboarding/OnboardingPanel.tsx","../../../../../../src/web-ui/routes/verse/sections/app-version.ts","../../../../../../src/web-ui/routes/verse/sections/AboutPanel.tsx","../../../../../../src/web-ui/design/contrast.ts","../../../../../../src/web-ui/routes/verse/sections/AppearancePanel.tsx","../../../../../../src/web-ui/routes/verse/sections/ConnectionPanel.tsx","../../../../../../src/web-ui/routes/verse/sections/ShortcutsPanel.tsx","../../../../../../src/web-ui/routes/verse/sections/SettingsSection.tsx"],"sourcesContent":["/**\n * components/primitives/Input.tsx — single-line text/number entry.\n *\n * Nothing here is a default browser control: hairline border, no inner card,\n * accent on focus. The accessible name comes from `label` when the field\n * stands alone, or from the caller's own `aria-label`/`aria-labelledby` when\n * it sits in a two-column settings row whose label lives on the other side.\n * An `error` is announced via role=\"alert\" and wired with aria-describedby —\n * red text alone never carries the message (design doc §6).\n */\nimport { useId, type InputHTMLAttributes, type ReactNode } from 'react';\nimport styles from './Input.module.css';\n\nexport interface InputProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'size' | 'className' | 'prefix'> {\n label?: ReactNode;\n /** Quiet helper text under the field. */\n hint?: ReactNode;\n /** Error message; also flips the field into its invalid styling. */\n error?: ReactNode;\n size?: 'sm' | 'md';\n /** Paths, ids, tokens counts — anything that should not be kerned. */\n mono?: boolean;\n /** Non-interactive leading text (e.g. \"$\", \"http://\"). Shadows the rarely\n * used HTML `prefix` attribute on purpose — this is the useful meaning. */\n prefix?: ReactNode;\n className?: string;\n}\n\nexport function Input({\n label,\n hint,\n error,\n size = 'md',\n mono = false,\n prefix,\n className,\n id,\n ...rest\n}: InputProps) {\n const generatedId = useId();\n const inputId = id ?? generatedId;\n const hintId = `${inputId}-hint`;\n const errorId = `${inputId}-error`;\n const describedBy = [rest['aria-describedby'], hint ? hintId : null, error ? errorId : null]\n .filter(Boolean)\n .join(' ');\n\n return (\n <div className={`${styles.field} ${className ?? ''}`}>\n {label ? (\n <label className={styles.label} htmlFor={inputId}>\n {label}\n </label>\n ) : null}\n <div className={`${styles.shell} ${styles[size]} ${error ? styles.invalid : ''}`}>\n {prefix ? <span className={styles.prefix}>{prefix}</span> : null}\n <input\n {...rest}\n id={inputId}\n className={`${styles.input} ${mono ? styles.mono : ''}`}\n aria-invalid={error ? true : rest['aria-invalid']}\n aria-describedby={describedBy || undefined}\n />\n </div>\n {hint ? (\n <p id={hintId} className={styles.hint}>\n {hint}\n </p>\n ) : null}\n {error ? (\n <p id={errorId} className={styles.error} role=\"alert\">\n {error}\n </p>\n ) : null}\n </div>\n );\n}\n","/**\n * components/primitives/Segmented.tsx — pick one of 2-4 options where the\n * choice applies instantly (theme, density, a status filter). It replaces\n * both a <select> (too heavy for three options) and a row of toggle buttons\n * (no single-selection semantics for a screen reader).\n *\n * Implemented as a radiogroup with ROVING TABINDEX: one Tab stop for the\n * group, arrows move between options and select as they go — the WAI-ARIA\n * radio-group pattern. Every option is reachable by keyboard and announced\n * as \"N of M\".\n */\nimport { useRef, type ReactNode } from 'react';\nimport styles from './Segmented.module.css';\n\nexport interface SegmentedOption<T extends string> {\n value: T;\n label: ReactNode;\n /** Leading 16px glyph; the text label always stays visible. */\n icon?: ReactNode;\n /** Spoken name when `label` is a glyph or an abbreviation. */\n ariaLabel?: string;\n disabled?: boolean;\n}\n\nexport interface SegmentedProps<T extends string> {\n options: ReadonlyArray<SegmentedOption<T>>;\n value: T;\n onChange: (next: T) => void;\n /** Accessible name for the group — required when no visible label precedes it. */\n 'aria-label'?: string;\n 'aria-labelledby'?: string;\n size?: 'sm' | 'md';\n /** Stretch each option to an equal share of the width. */\n block?: boolean;\n className?: string;\n}\n\nexport function Segmented<T extends string>({\n options,\n value,\n onChange,\n size = 'md',\n block = false,\n className,\n ...aria\n}: SegmentedProps<T>) {\n const groupRef = useRef<HTMLDivElement>(null);\n\n function move(delta: number): void {\n const enabled = options.filter((o) => !o.disabled);\n if (enabled.length === 0) return;\n const current = enabled.findIndex((o) => o.value === value);\n const next = enabled[(((current + delta) % enabled.length) + enabled.length) % enabled.length]!;\n onChange(next.value);\n // Keep DOM focus on the newly selected option (roving tabindex).\n requestAnimationFrame(() => {\n groupRef.current?.querySelector<HTMLButtonElement>(`[data-value=\"${next.value}\"]`)?.focus();\n });\n }\n\n return (\n <div\n ref={groupRef}\n role=\"radiogroup\"\n className={`${styles.group} ${styles[size]} ${block ? styles.block : ''} ${className ?? ''}`}\n {...aria}\n >\n {options.map((option) => {\n const selected = option.value === value;\n return (\n <button\n key={option.value}\n type=\"button\"\n role=\"radio\"\n aria-checked={selected}\n aria-label={option.ariaLabel}\n data-value={option.value}\n tabIndex={selected ? 0 : -1}\n disabled={option.disabled}\n className={styles.option}\n onClick={() => onChange(option.value)}\n onKeyDown={(e) => {\n if (e.key === 'ArrowRight' || e.key === 'ArrowDown') {\n e.preventDefault();\n move(1);\n } else if (e.key === 'ArrowLeft' || e.key === 'ArrowUp') {\n e.preventDefault();\n move(-1);\n }\n }}\n >\n {option.icon ? <span className={styles.glyph}>{option.icon}</span> : null}\n {option.label}\n </button>\n );\n })}\n </div>\n );\n}\n","/**\n * components/primitives/Slider.tsx — a continuous value (accent hue,\n * saturation, a budget). Native <input type=\"range\"> so the platform's\n * keyboard model (arrows, Home/End, PageUp/PageDown) comes for free; the\n * track and thumb are restyled to the token system.\n *\n * `valueLabel` renders the number in the display face next to the control.\n * It is presentational: the control's own accessible value is carried by\n * aria-valuetext when a unit would otherwise be lost (\"245\" -> \"245 degrees\").\n */\nimport { useId, type InputHTMLAttributes, type ReactNode } from 'react';\nimport styles from './Slider.module.css';\n\nexport interface SliderProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'type' | 'className' | 'value'> {\n label?: ReactNode;\n value: number;\n min?: number;\n max?: number;\n /** Rendered to the right of the track, in the display face. */\n valueLabel?: ReactNode;\n /** Spoken value, when the raw number needs a unit. */\n valueText?: string;\n /** Paint the filled portion of the track (hue sliders want a gradient instead). */\n trackImage?: string;\n className?: string;\n}\n\nexport function Slider({\n label,\n value,\n min = 0,\n max = 100,\n valueLabel,\n valueText,\n trackImage,\n className,\n id,\n ...rest\n}: SliderProps) {\n const generatedId = useId();\n const sliderId = id ?? generatedId;\n const span = Math.max(1, max - min);\n const percent = Math.round(((value - min) / span) * 100);\n\n return (\n <div className={`${styles.field} ${className ?? ''}`}>\n {label ? (\n <label className={styles.label} htmlFor={sliderId}>\n {label}\n </label>\n ) : null}\n <div className={styles.row}>\n <input\n {...rest}\n id={sliderId}\n type=\"range\"\n className={styles.input}\n value={value}\n min={min}\n max={max}\n aria-valuetext={valueText}\n style={\n {\n '--slider-fill': `${percent}%`,\n ...(trackImage ? { '--slider-track-image': trackImage } : {}),\n } as React.CSSProperties\n }\n data-custom-track={trackImage ? 'true' : undefined}\n />\n {valueLabel !== undefined ? <span className={styles.value}>{valueLabel}</span> : null}\n </div>\n </div>\n );\n}\n","/**\n * components/primitives/Switch.tsx — a binary setting that takes effect\n * immediately (no form submit). role=\"switch\" + aria-checked, so a screen\n * reader announces \"on\"/\"off\" rather than \"checkbox, checked\".\n *\n * State is never carried by color alone: the knob's POSITION is the primary\n * signal (design doc §6), the accent fill is reinforcement.\n */\nimport type { ReactNode } from 'react';\nimport styles from './Switch.module.css';\n\nexport interface SwitchProps {\n checked: boolean;\n onChange: (next: boolean) => void;\n /** Visible label; when omitted, pass `aria-label`. */\n label?: ReactNode;\n 'aria-label'?: string;\n 'aria-describedby'?: string;\n disabled?: boolean;\n id?: string;\n className?: string;\n}\n\nexport function Switch({\n checked,\n onChange,\n label,\n disabled = false,\n id,\n className,\n ...aria\n}: SwitchProps) {\n const control = (\n <button\n type=\"button\"\n id={id}\n role=\"switch\"\n aria-checked={checked}\n disabled={disabled}\n className={styles.track}\n onClick={() => onChange(!checked)}\n {...aria}\n >\n <span className={styles.knob} aria-hidden=\"true\" />\n </button>\n );\n\n if (!label) return <span className={className}>{control}</span>;\n\n return (\n <label className={`${styles.wrapper} ${className ?? ''}`}>\n {control}\n <span className={styles.label}>{label}</span>\n </label>\n );\n}\n","/**\n * routes/verse/sections/SettingRow.tsx — the Settings layout primitive:\n * label + description on the left, control on the right, hairline between.\n *\n * The label is a real <label> bound to the control's id when one is given;\n * for composite controls (a radiogroup, a swatch grid) pass `labelId` and\n * point the group's `aria-labelledby` at it instead — a <label> cannot name\n * a group, and an unnamed radiogroup is announced as \"group\".\n */\nimport type { ReactNode } from 'react';\nimport styles from './SettingsSection.module.css';\n\nexport interface PanelProps {\n title: ReactNode;\n /** Right-aligned affordance in the panel header (e.g. \"Reset\"). */\n action?: ReactNode;\n children: ReactNode;\n}\n\nexport function Panel({ title, action, children }: PanelProps) {\n return (\n <section className={styles.panel}>\n <div className={styles.panelHead}>\n <h3 className={styles.panelTitle}>{title}</h3>\n {action}\n </div>\n <div className={styles.panelBody}>{children}</div>\n </section>\n );\n}\n\nexport interface SettingRowProps {\n label: ReactNode;\n description?: ReactNode;\n /** id of the control this row labels (renders a real <label for>). */\n htmlFor?: string;\n /** id to put on the label text, for a control using aria-labelledby. */\n labelId?: string;\n /** Put the control under the text instead of beside it (sliders, previews). */\n stacked?: boolean;\n children: ReactNode;\n}\n\nexport function SettingRow({\n label,\n description,\n htmlFor,\n labelId,\n stacked = false,\n children,\n}: SettingRowProps) {\n const text = (\n <>\n <span className={styles.rowLabel} id={labelId}>\n {label}\n </span>\n {description ? <span className={styles.rowDescription}>{description}</span> : null}\n </>\n );\n\n return (\n <div className={`${styles.row} ${stacked ? styles.rowStacked : ''}`}>\n <div className={styles.rowText}>\n {htmlFor ? (\n <label htmlFor={htmlFor} className={styles.rowText}>\n {text}\n </label>\n ) : (\n text\n )}\n </div>\n <div className={styles.rowControl}>{children}</div>\n </div>\n );\n}\n","/**\n * routes/verse/onboarding/OnboardingPanel.tsx — the Settings row that brings\n * the first-run tour back.\n *\n * It lives here rather than in sections/ so the whole onboarding feature is\n * one folder; SettingsSection.tsx imports it the same way it imports its own\n * panels, and reuses the same Panel/SettingRow primitives so the row keeps\n * the label-left / control-right rhythm of every other setting.\n *\n * The description states what the tour actually covers, and — because this\n * is the only place the stored answer is visible — whether it has been seen.\n */\nimport { Button } from '../../../components/primitives/index.js';\nimport { Panel, SettingRow } from '../sections/SettingRow.js';\nimport { replayOnboarding } from './onboarding-store.js';\nimport { useOnboarding } from './useOnboarding.js';\n\nfunction describe(completedAt: string | null, dismissedAt: string | null): string {\n if (completedAt) return `Last completed ${new Date(completedAt).toLocaleDateString()}.`;\n if (dismissedAt) return 'Skipped. Nothing was missed — it is all reachable from the sections themselves.';\n return 'Not seen yet.';\n}\n\nexport function OnboardingPanel() {\n const { completedAt, dismissedAt, open } = useOnboarding();\n\n return (\n <Panel title=\"Onboarding\">\n <SettingRow\n label=\"Replay the first-run tour\"\n description={`Your connected seats, whether a local runtime is available, and what each of the three stop controls really halts. ${describe(completedAt, dismissedAt)}`}\n >\n <Button variant=\"subtle\" size=\"sm\" onClick={replayOnboarding} disabled={open}>\n {open ? 'Showing' : 'Replay'}\n </Button>\n </SettingRow>\n </Panel>\n );\n}\n","/**\n * routes/verse/sections/app-version.ts — the hub's version, for About.\n *\n * Read straight from package.json (Vite inlines the named export at build\n * time and `resolveJsonModule` types it), because no API route reports it:\n * /api/health answers liveness, /api/snapshot answers fleet state, and\n * neither carries the running hub's version. A hardcoded string here would\n * silently drift from the published package on every release.\n */\nimport { version } from '../../../../../package.json';\n\nexport const APP_VERSION: string = version;\nexport const APP_NAME = 'Ashlr Verse';\n","/**\n * routes/verse/sections/AboutPanel.tsx — what this is and which build it is.\n * The version comes from package.json at build time (./app-version.ts).\n */\nimport { IconExternalLink } from '../../../components/primitives/icons.js';\nimport { Tag } from '../../../components/primitives/index.js';\nimport { APP_NAME, APP_VERSION } from './app-version.js';\nimport { Panel } from './SettingRow.js';\nimport styles from './SettingsSection.module.css';\n\nexport function AboutPanel() {\n return (\n <Panel title=\"About\">\n <div className={`${styles.row} ${styles.rowStacked}`}>\n <div className={styles.about}>\n <p className={styles.aboutName}>{APP_NAME}</p>\n <p className={styles.aboutLine}>\n <Tag mono>v{APP_VERSION}</Tag>\n <span>ashlr-hub — local-first command center for agentic engineers.</span>\n </p>\n <p className={styles.aboutLine}>\n Every session, token and artifact stays on this machine. The console talks to one local server and no\n third-party service.\n </p>\n <p className={styles.aboutLine}>\n <a\n className={styles.link}\n href=\"https://github.com/ashlrai/ashlr-hub\"\n target=\"_blank\"\n rel=\"noreferrer noopener\"\n >\n Source and changelog\n <IconExternalLink size={12} />\n </a>\n </p>\n </div>\n </div>\n </Panel>\n );\n}\n","/**\n * design/contrast.ts — WCAG 2.1 contrast math over CSS color strings.\n *\n * Two callers, one implementation:\n * - routes/verse/sections/AppearancePanel.tsx warns, live, when a\n * hand-dragged accent stops being readable as link/button text in the\n * active theme. The design language allows any hue; it does not allow an\n * unreadable one to ship silently.\n * - design/tokens-contrast.test.ts asserts the whole palette in BOTH\n * themes (design doc §6: >= 4.5:1 body text, >= 3:1 meaningful borders).\n *\n * Deliberately dependency-free and DOM-free: parse -> linearize -> ratio.\n * Supports the subset of CSS color syntax the stylesheets actually use —\n * #rgb / #rrggbb / #rrggbbaa, rgb()/rgba(), hsl()/hsla(), both the legacy\n * comma form and the modern space form, plus `color-mix(in srgb, ...)`.\n * Anything else returns null rather than guessing a color.\n *\n * `color-mix` is in that list because the meaning-carrying marks that the\n * contrast suite has to guard are not all plain tokens: the chart gridline,\n * the empty half of a window meter and the diff row tints are all declared as\n * a mix in a CSS module. Without this the suite could only assert the token a\n * mix is DERIVED from, which is precisely the gap that let a 45%-alpha\n * gridline ship under a comment claiming it cleared 3:1.\n */\n\nexport interface Rgba {\n /** 0-255 */\n r: number;\n /** 0-255 */\n g: number;\n /** 0-255 */\n b: number;\n /** 0-1 */\n a: number;\n}\n\nconst HEX_RE = /^#([0-9a-f]{3,8})$/i;\nconst FN_RE = /^(rgba?|hsla?)\\(([^)]*)\\)$/i;\n\nfunction clamp(n: number, min: number, max: number): number {\n return Math.min(max, Math.max(min, n));\n}\n\n/** \"50%\" -> 0.5, \"0.5\" -> 0.5, \"128\" (of 255) handled by the caller. */\nfunction unitValue(raw: string, scale: number): number {\n const text = raw.trim();\n if (text.endsWith('%')) return (Number.parseFloat(text) / 100) * scale;\n return Number.parseFloat(text);\n}\n\nfunction hslToRgb(h: number, s: number, l: number): { r: number; g: number; b: number } {\n const hue = ((h % 360) + 360) % 360;\n const c = (1 - Math.abs(2 * l - 1)) * s;\n const x = c * (1 - Math.abs(((hue / 60) % 2) - 1));\n const m = l - c / 2;\n let rgb: [number, number, number];\n if (hue < 60) rgb = [c, x, 0];\n else if (hue < 120) rgb = [x, c, 0];\n else if (hue < 180) rgb = [0, c, x];\n else if (hue < 240) rgb = [0, x, c];\n else if (hue < 300) rgb = [x, 0, c];\n else rgb = [c, 0, x];\n return {\n r: Math.round((rgb[0] + m) * 255),\n g: Math.round((rgb[1] + m) * 255),\n b: Math.round((rgb[2] + m) * 255),\n };\n}\n\n/**\n * Split a function's argument list on top-level commas, so a nested\n * `rgb(...)`/`color-mix(...)` argument survives intact.\n */\nfunction splitTopLevel(text: string): string[] {\n const parts: string[] = [];\n let depth = 0;\n let current = '';\n for (const ch of text) {\n if (ch === '(') depth += 1;\n else if (ch === ')') depth -= 1;\n if (ch === ',' && depth === 0) {\n parts.push(current);\n current = '';\n continue;\n }\n current += ch;\n }\n parts.push(current);\n return parts.map((p) => p.trim()).filter((p) => p.length > 0);\n}\n\n/** `#abc 40%` -> ['#abc', 40]; a missing percentage comes back as null. */\nfunction colorWithPercent(raw: string): { color: string; pct: number | null } | null {\n const text = raw.trim();\n const m = /\\s(\\d*\\.?\\d+)%$/.exec(text);\n if (m) return { color: text.slice(0, m.index).trim(), pct: Number.parseFloat(m[1]!) };\n const lead = /^(\\d*\\.?\\d+)%\\s/.exec(text);\n if (lead) return { color: text.slice(lead[0].length).trim(), pct: Number.parseFloat(lead[1]!) };\n return { color: text, pct: null };\n}\n\n/**\n * `color-mix(in srgb, <color> [p%], <color> [p%])`, per CSS Color 5: the two\n * percentages are normalized to sum to 100, the result's alpha is their\n * alpha-weighted sum, and the channels are mixed PREMULTIPLIED — which is why\n * mixing against `transparent` yields the first color at that alpha rather\n * than a color darkened toward black.\n *\n * Only the `srgb` color space is accepted. Every other space would need its\n * own transfer function, and silently treating `oklab` as srgb would report a\n * contrast ratio the browser does not agree with.\n */\nfunction parseColorMix(text: string): Rgba | null {\n const body = /^color-mix\\((.*)\\)$/is.exec(text.trim());\n if (!body) return null;\n const args = splitTopLevel(body[1]!);\n if (args.length !== 3) return null;\n if (args[0]!.replace(/\\s+/g, ' ').trim() !== 'in srgb') return null;\n\n const first = colorWithPercent(args[1]!);\n const second = colorWithPercent(args[2]!);\n if (!first || !second) return null;\n const c1 = parseColor(first.color);\n const c2 = parseColor(second.color);\n if (!c1 || !c2) return null;\n\n let p1 = first.pct;\n let p2 = second.pct;\n if (p1 === null && p2 === null) {\n p1 = 50;\n p2 = 50;\n } else if (p1 === null) p1 = 100 - p2!;\n else if (p2 === null) p2 = 100 - p1;\n const total = p1 + p2!;\n if (total <= 0) return null;\n const w1 = p1 / total;\n const w2 = p2! / total;\n\n const alpha = c1.a * w1 + c2.a * w2;\n if (alpha <= 0) return { r: 0, g: 0, b: 0, a: 0 };\n const channel = (k: 'r' | 'g' | 'b'): number =>\n clamp(Math.round((c1[k] * c1.a * w1 + c2[k] * c2.a * w2) / alpha), 0, 255);\n return { r: channel('r'), g: channel('g'), b: channel('b'), a: clamp(alpha, 0, 1) };\n}\n\n/** Parse a CSS color string. Returns null for anything unrecognized. */\nexport function parseColor(input: string): Rgba | null {\n const text = input.trim().toLowerCase();\n if (text === 'transparent') return { r: 0, g: 0, b: 0, a: 0 };\n if (text.startsWith('color-mix(')) return parseColorMix(text);\n\n const hex = HEX_RE.exec(text);\n if (hex) {\n const body = hex[1]!;\n const expand = (s: string) => Number.parseInt(s.length === 1 ? s + s : s, 16);\n if (body.length === 3 || body.length === 4) {\n return {\n r: expand(body[0]!),\n g: expand(body[1]!),\n b: expand(body[2]!),\n a: body.length === 4 ? expand(body[3]!) / 255 : 1,\n };\n }\n if (body.length === 6 || body.length === 8) {\n return {\n r: expand(body.slice(0, 2)),\n g: expand(body.slice(2, 4)),\n b: expand(body.slice(4, 6)),\n a: body.length === 8 ? expand(body.slice(6, 8)) / 255 : 1,\n };\n }\n return null;\n }\n\n const fn = FN_RE.exec(text);\n if (!fn) return null;\n const name = fn[1]!;\n // Both syntaxes: `a, b, c, d` and `a b c / d`.\n const parts = fn[2]!\n .replace(/\\//g, ' ')\n .split(/[\\s,]+/)\n .filter(Boolean);\n if (parts.length < 3) return null;\n const alpha = parts.length >= 4 ? clamp(unitValue(parts[3]!, 1), 0, 1) : 1;\n\n if (name.startsWith('rgb')) {\n return {\n r: clamp(Math.round(unitValue(parts[0]!, 255)), 0, 255),\n g: clamp(Math.round(unitValue(parts[1]!, 255)), 0, 255),\n b: clamp(Math.round(unitValue(parts[2]!, 255)), 0, 255),\n a: alpha,\n };\n }\n\n const hue = Number.parseFloat(parts[0]!);\n const sat = clamp(unitValue(parts[1]!, 1), 0, 1);\n const light = clamp(unitValue(parts[2]!, 1), 0, 1);\n if (!Number.isFinite(hue)) return null;\n return { ...hslToRgb(hue, sat, light), a: alpha };\n}\n\n/** Composite a (possibly translucent) color over an opaque backdrop. */\nexport function flatten(color: Rgba, backdrop: Rgba): Rgba {\n if (color.a >= 1) return color;\n const a = color.a;\n return {\n r: Math.round(color.r * a + backdrop.r * (1 - a)),\n g: Math.round(color.g * a + backdrop.g * (1 - a)),\n b: Math.round(color.b * a + backdrop.b * (1 - a)),\n a: 1,\n };\n}\n\n/** WCAG relative luminance of an opaque color. */\nexport function relativeLuminance(color: Rgba): number {\n const channel = (v: number): number => {\n const s = v / 255;\n return s <= 0.03928 ? s / 12.92 : ((s + 0.055) / 1.055) ** 2.4;\n };\n return 0.2126 * channel(color.r) + 0.7152 * channel(color.g) + 0.0722 * channel(color.b);\n}\n\n/**\n * WCAG contrast ratio (1-21) between two CSS colors. A translucent color is\n * composited over `backdrop` first (default white) — asking for the contrast\n * of a 14%-alpha status background is otherwise meaningless.\n * Returns null when either color cannot be parsed, so a caller can say\n * \"unknown\" instead of asserting on a guess.\n */\nexport function contrastRatio(foreground: string, background: string, backdrop = '#ffffff'): number | null {\n const bgRaw = parseColor(background);\n const fgRaw = parseColor(foreground);\n const base = parseColor(backdrop);\n if (!bgRaw || !fgRaw || !base) return null;\n const bg = flatten(bgRaw, base);\n const fg = flatten(fgRaw, bg);\n const l1 = relativeLuminance(fg);\n const l2 = relativeLuminance(bg);\n const [hi, lo] = l1 >= l2 ? [l1, l2] : [l2, l1];\n return (hi + 0.05) / (lo + 0.05);\n}\n\n/** Convenience for the appearance panel: does this pair clear body-text contrast? */\nexport function meetsTextContrast(foreground: string, background: string, backdrop?: string): boolean {\n const ratio = contrastRatio(foreground, background, backdrop);\n return ratio !== null && ratio >= 4.5;\n}\n\n/**\n * The accent, resolved to a hex the same way tokens.css derives its ramp\n * (hsl channels + a per-step lightness offset). Used by the appearance panel\n * to preview and contrast-check a hue the operator is dragging, without\n * reading computed styles mid-drag.\n */\nexport function accentHex(h: number, s: number, l: number, lightnessOffset = 0): string {\n const rgb = hslToRgb(h, clamp(s, 0, 100) / 100, clamp(l + lightnessOffset, 0, 100) / 100);\n const hex = (n: number) => n.toString(16).padStart(2, '0');\n return `#${hex(rgb.r)}${hex(rgb.g)}${hex(rgb.b)}`;\n}\n","/**\n * routes/verse/sections/AppearancePanel.tsx — the \"Linux\" part of the design\n * language: theme, accent, density, display face, radius, motion.\n *\n * Every control applies IMMEDIATELY (design doc §3: live preview, no save\n * button) because the whole app is the preview — the panel writes through\n * data/appearance-store.ts, which writes the tokens on <html>. The preview\n * block at the end exists to show type, numerals, a filled action and a\n * meter in one place, so the effect of a change is visible without leaving\n * Settings.\n *\n * The hue slider is free-range, so the panel checks the resulting link color\n * against BOTH themes with design/contrast.ts and warns when a choice drops\n * under 4.5:1 — the operator keeps the hue they asked for, but is never\n * allowed to make it unreadable without being told.\n */\nimport { useId } from 'react';\nimport { Button, Input, Meter, Segmented, Slider, StatusBadge, Switch, Tag } from '../../../components/primitives/index.js';\nimport { IconAlert, IconCheck, IconMonitor, IconMoon, IconSun } from '../../../components/primitives/icons.js';\nimport { accentHex, contrastRatio } from '../../../design/contrast.js';\nimport {\n ACCENT_LIGHTNESS_RANGE,\n ACCENT_PRESETS,\n isDefaultAppearance,\n matchingAccentPreset,\n type Appearance,\n type Density,\n type DisplayFont,\n type RadiusScale,\n type ThemePreference,\n} from '../../../data/appearance-store.js';\nimport { Panel, SettingRow } from './SettingRow.js';\nimport styles from './SettingsSection.module.css';\n\n/**\n * The literal `--bg-surface` of each theme (design/tokens.css). Used only to\n * score a candidate accent; design/tokens-contrast.test.ts asserts these two\n * constants still match the stylesheet, so a future retune cannot leave the\n * warning scoring against a color the app no longer paints.\n */\nexport const LIGHT_SURFACE = '#ffffff';\nexport const DARK_SURFACE = '#121214';\n/** Dark raises accent lightness by --accent-l-shift; --accent-600 sits 8% below/above it. */\nconst DARK_L_SHIFT = 6;\nconst LINK_STEP = 8;\n\nconst THEME_OPTIONS = [\n { value: 'system' as ThemePreference, label: 'System', icon: <IconMonitor /> },\n { value: 'light' as ThemePreference, label: 'Light', icon: <IconSun /> },\n { value: 'dark' as ThemePreference, label: 'Dark', icon: <IconMoon /> },\n];\n\nconst DENSITY_OPTIONS = [\n { value: 'comfortable' as Density, label: 'Comfortable' },\n { value: 'compact' as Density, label: 'Compact' },\n];\n\nconst FONT_OPTIONS = [\n { value: 'grotesk' as DisplayFont, label: 'Space Grotesk' },\n { value: 'ui' as DisplayFont, label: 'UI sans' },\n { value: 'mono' as DisplayFont, label: 'Mono' },\n];\n\nconst RADIUS_OPTIONS = [\n { value: 'sharp' as RadiusScale, label: 'Sharp' },\n { value: 'default' as RadiusScale, label: 'Default' },\n { value: 'soft' as RadiusScale, label: 'Soft' },\n];\n\n/** A 360° sweep at the current saturation/lightness, so the track shows the choice. */\nfunction hueTrack(s: number, l: number): string {\n const stops = [0, 60, 120, 180, 240, 300, 360].map((h) => `${accentHex(h, s, l)} ${(h / 360) * 100}%`);\n return `linear-gradient(to right, ${stops.join(', ')})`;\n}\n\nexport interface AccentReadability {\n lightRatio: number | null;\n darkRatio: number | null;\n /** Themes in which the derived link color drops below 4.5:1. */\n failing: Array<'light' | 'dark'>;\n}\n\n/** Exported for the section's test: the same math the warning renders from. */\nexport function accentReadability(h: number, s: number, l: number): AccentReadability {\n const lightLink = accentHex(h, s, l, -LINK_STEP);\n const darkLink = accentHex(h, s, l, DARK_L_SHIFT + LINK_STEP);\n const lightRatio = contrastRatio(lightLink, LIGHT_SURFACE);\n const darkRatio = contrastRatio(darkLink, DARK_SURFACE);\n const failing: Array<'light' | 'dark'> = [];\n if (lightRatio !== null && lightRatio < 4.5) failing.push('light');\n if (darkRatio !== null && darkRatio < 4.5) failing.push('dark');\n return { lightRatio, darkRatio, failing };\n}\n\nexport interface AppearancePanelProps {\n appearance: Appearance;\n onChange: (patch: Partial<Appearance>) => void;\n onReset: () => void;\n}\n\nexport function AppearancePanel({ appearance, onChange, onReset }: AppearancePanelProps) {\n const accentLabelId = useId();\n const hueId = useId();\n const satId = useId();\n const lightId = useId();\n const motionId = useId();\n\n const preset = matchingAccentPreset(appearance);\n const readability = accentReadability(appearance.accentH, appearance.accentS, appearance.accentL);\n\n return (\n <Panel\n title=\"Appearance\"\n action={\n <Button\n variant=\"ghost\"\n size=\"sm\"\n onClick={onReset}\n disabled={isDefaultAppearance(appearance)}\n title=\"Restore the shipped theme, accent, density, font, radius and motion\"\n >\n Reset to defaults\n </Button>\n }\n >\n <SettingRow label=\"Theme\" description=\"System follows your OS appearance setting.\">\n <Segmented\n aria-label=\"Theme\"\n options={THEME_OPTIONS}\n value={appearance.theme}\n onChange={(theme) => onChange({ theme })}\n />\n </SettingRow>\n\n <SettingRow\n label=\"Accent\"\n labelId={accentLabelId}\n description={\n preset\n ? `${preset.label} — used for links, focus rings and the one primary action per surface.`\n : 'Custom hue — used for links, focus rings and the one primary action per surface.'\n }\n >\n <div className={styles.swatches} role=\"radiogroup\" aria-labelledby={accentLabelId}>\n {ACCENT_PRESETS.map((p) => {\n const selected = preset?.id === p.id;\n return (\n <button\n key={p.id}\n type=\"button\"\n role=\"radio\"\n aria-checked={selected}\n aria-label={p.label}\n tabIndex={selected || (!preset && p.id === ACCENT_PRESETS[0]!.id) ? 0 : -1}\n className={styles.swatch}\n style={{ background: accentHex(p.h, p.s, p.l) }}\n onClick={() => onChange({ accentH: p.h, accentS: p.s, accentL: p.l })}\n >\n {selected ? (\n <span className={styles.swatchCheck}>\n <IconCheck size={12} />\n </span>\n ) : null}\n </button>\n );\n })}\n </div>\n </SettingRow>\n\n <SettingRow\n label=\"Accent channels\"\n description=\"Hue, saturation and lightness are written straight onto the root element — the whole app follows as you drag.\"\n stacked\n >\n <div className={styles.sliderStack}>\n <Slider\n id={hueId}\n label=\"Hue\"\n min={0}\n max={359}\n value={appearance.accentH}\n valueLabel={`${appearance.accentH}°`}\n valueText={`${appearance.accentH} degrees`}\n trackImage={hueTrack(appearance.accentS, appearance.accentL)}\n onChange={(e) => onChange({ accentH: Number(e.currentTarget.value) })}\n />\n <Slider\n id={satId}\n label=\"Saturation\"\n min={0}\n max={100}\n value={appearance.accentS}\n valueLabel={`${appearance.accentS}%`}\n valueText={`${appearance.accentS} percent`}\n onChange={(e) => onChange({ accentS: Number(e.currentTarget.value) })}\n />\n <Slider\n id={lightId}\n label=\"Lightness\"\n min={ACCENT_LIGHTNESS_RANGE.min}\n max={ACCENT_LIGHTNESS_RANGE.max}\n value={appearance.accentL}\n valueLabel={`${appearance.accentL}%`}\n valueText={`${appearance.accentL} percent`}\n onChange={(e) => onChange({ accentL: Number(e.currentTarget.value) })}\n />\n {readability.failing.length > 0 ? (\n <p className={styles.contrastWarning} role=\"status\">\n <IconAlert size={14} />\n <span>\n This accent falls below 4.5:1 as link text in{' '}\n {readability.failing.length === 2 ? 'both themes' : `${readability.failing[0]} mode`}. Raise or lower\n the lightness to keep it readable.\n </span>\n </p>\n ) : null}\n </div>\n </SettingRow>\n\n <SettingRow label=\"Density\" description=\"Row height and control padding across every view.\">\n <Segmented\n aria-label=\"Density\"\n options={DENSITY_OPTIONS}\n value={appearance.density}\n onChange={(density) => onChange({ density })}\n />\n </SettingRow>\n\n <SettingRow label=\"Display font\" description=\"Titles, seat names, metrics and numerals. Body copy stays in the UI sans.\">\n <Segmented\n aria-label=\"Display font\"\n options={FONT_OPTIONS}\n value={appearance.displayFont}\n onChange={(displayFont) => onChange({ displayFont })}\n />\n </SettingRow>\n\n <SettingRow label=\"Corner radius\" description=\"Sharp reads like a terminal; soft reads like a consumer app.\">\n <Segmented\n aria-label=\"Corner radius\"\n options={RADIUS_OPTIONS}\n value={appearance.radius}\n onChange={(radius) => onChange({ radius })}\n />\n </SettingRow>\n\n <SettingRow\n label=\"Reduce motion\"\n htmlFor={motionId}\n description=\"Collapses every transition to 1ms. Defaults to your system preference; turning it off here overrides that.\"\n >\n <Switch\n id={motionId}\n checked={appearance.reduceMotion}\n onChange={(reduceMotion) => onChange({ reduceMotion })}\n aria-label=\"Reduce motion\"\n />\n </SettingRow>\n\n <SettingRow label=\"Preview\" description=\"Live — these are the real primitives, not a picture of them.\" stacked>\n <div className={styles.preview}>\n <p className={styles.previewHeading}>Ashlr Verse</p>\n <p className={styles.previewBody}>\n Body copy stays in the UI sans at the reading measure; numerals like{' '}\n <span className={styles.previewNumerals}>18,420 / 66,000</span> use the display face.\n </p>\n <div className={styles.previewRow}>\n <Button variant=\"primary\" size=\"sm\">\n Primary\n </Button>\n <Button variant=\"subtle\" size=\"sm\">\n Subtle\n </Button>\n <Button variant=\"ghost\" size=\"sm\">\n Ghost\n </Button>\n <Button variant=\"danger\" size=\"sm\">\n Destructive\n </Button>\n </div>\n <div className={styles.previewRow}>\n <StatusBadge status=\"running\" />\n <Tag engine=\"claude\">Claude Max</Tag>\n <Tag engine=\"local\" mono>\n qwen3-coder\n </Tag>\n </div>\n <Meter value={18_420} max={66_000} label=\"Context\" />\n <Input aria-label=\"Preview field\" placeholder=\"A field at the current density\" size=\"sm\" />\n </div>\n </SettingRow>\n </Panel>\n );\n}\n","/**\n * routes/verse/sections/ConnectionPanel.tsx — which server this window is\n * talking to, what authority it currently holds, and how to get the tokens\n * back if it loses them.\n *\n * SECURITY: this panel never renders, copies or logs a token. It shows the\n * STATE of the two authorities (read session, mutation hold) and tells the\n * operator where the real values are printed — the terminal that started the\n * server. The mutation token is memory-only by design (data/auth-store.ts);\n * showing it here would put it on screen, in a screenshot, and in any\n * screen-recording of a demo.\n */\nimport { useRef, useState } from 'react';\nimport { Button, Dialog, Input, StatusBadge } from '../../../components/primitives/index.js';\nimport { IconCopy, IconInfo, IconLock } from '../../../components/primitives/icons.js';\nimport { clearMutationToken, clearReadSession } from '../../../data/auth-store.js';\nimport { useAuthPhase, useMutationHold } from '../../../data/hooks.js';\nimport { useToast } from '../../../components/primitives/Toast.js';\nimport { Panel, SettingRow } from './SettingRow.js';\nimport styles from './SettingsSection.module.css';\n\nfunction formatHoldExpiry(heldUntil: number | null): string {\n if (heldUntil === null) return 'locked';\n const minutes = Math.max(0, Math.round((heldUntil - Date.now()) / 60_000));\n if (minutes <= 0) return 'expiring now';\n return `unlocked for ${minutes} more minute${minutes === 1 ? '' : 's'}`;\n}\n\nexport function ConnectionPanel() {\n const phase = useAuthPhase();\n const hold = useMutationHold();\n const toast = useToast();\n const [confirmOpen, setConfirmOpen] = useState(false);\n const cancelRef = useRef<HTMLButtonElement>(null);\n\n const origin = typeof window === 'undefined' ? '' : window.location.origin;\n\n async function copyOrigin(): Promise<void> {\n try {\n await navigator.clipboard.writeText(origin);\n toast.show('Server address copied.');\n } catch {\n toast.show('Could not reach the clipboard — select the field and copy manually.', 'danger');\n }\n }\n\n async function disconnect(): Promise<void> {\n setConfirmOpen(false);\n await clearReadSession();\n toast.show('Disconnected. Paste the read token to reconnect.');\n }\n\n return (\n <Panel title=\"Connection\">\n <SettingRow label=\"Server\" description=\"This window talks to one local hub. Nothing leaves your machine.\">\n <div className={styles.origin}>\n <Input value={origin} readOnly mono size=\"sm\" aria-label=\"Server address\" />\n </div>\n <Button variant=\"ghost\" size=\"sm\" icon={<IconCopy />} onClick={() => void copyOrigin()}>\n Copy\n </Button>\n </SettingRow>\n\n <SettingRow label=\"Read session\" description=\"A 15-minute signed cookie, renewed silently while this tab stays open.\">\n <StatusBadge\n status={phase === 'authenticated' ? 'connected' : phase === 'checking' ? 'checking' : 'disconnected'}\n tone={phase === 'authenticated' ? 'success' : phase === 'checking' ? 'running' : 'danger'}\n />\n </SettingRow>\n\n <SettingRow\n label=\"Mutation hold\"\n description=\"Every action that changes something needs the mutation token. It is held in memory only, never stored, and clears when this tab closes.\"\n >\n <StatusBadge\n status={hold.hasHold ? formatHoldExpiry(hold.heldUntil) : 'locked'}\n tone={hold.hasHold ? 'success' : 'neutral'}\n />\n <Button\n variant=\"subtle\"\n size=\"sm\"\n icon={<IconLock />}\n onClick={() => {\n clearMutationToken();\n toast.show('Mutation hold cleared.');\n }}\n disabled={!hold.hasHold}\n >\n Lock now\n </Button>\n </SettingRow>\n\n <SettingRow\n label=\"Disconnect\"\n description=\"Ends the read session in this browser and clears the mutation hold. Chats on the server are untouched.\"\n >\n <Button variant=\"danger\" size=\"sm\" onClick={() => setConfirmOpen(true)}>\n Disconnect\n </Button>\n </SettingRow>\n\n <div className={styles.row}>\n <p className={styles.note}>\n <span className={styles.noteIcon}>\n <IconInfo size={14} />\n </span>\n <span>\n <strong>Where the tokens come from.</strong> Start the console with{' '}\n <code className={styles.code}>ashlr verse</code> — it prints a read token and a mutation token in that\n terminal, and opens this page. The desktop app injects both for you. Tokens are never displayed here, and\n the hub never writes them into a page, a log line or an API response. Lost them? Stop the server and start\n it again; it mints a fresh pair.\n </span>\n </p>\n </div>\n\n <Dialog\n open={confirmOpen}\n onClose={() => setConfirmOpen(false)}\n titleId=\"verse-settings-disconnect\"\n title=\"Disconnect from this server?\"\n description=\"You will need the read token again to get back in. Running sessions keep running on the server.\"\n initialFocusRef={cancelRef}\n >\n <div className={styles.previewRow} style={{ justifyContent: 'flex-end' }}>\n <Button ref={cancelRef} variant=\"subtle\" onClick={() => setConfirmOpen(false)}>\n Cancel\n </Button>\n <Button variant=\"danger\" onClick={() => void disconnect()}>\n Disconnect\n </Button>\n </div>\n </Dialog>\n </Panel>\n );\n}\n","/**\n * routes/verse/sections/ShortcutsPanel.tsx — the keyboard reference.\n *\n * It documents the bindings the V2 shell contract fixes (⌘1-⌘5, ⌘K, ⌘N, ⌘,)\n * plus the composer's own keys. It is a REFERENCE, not the implementation:\n * the handlers live with the shell (owner C) and the composer. Keeping the\n * list here means an operator can find a binding without a manual; keeping\n * it declarative means it is one array to update when a binding changes.\n */\nimport { Panel } from './SettingRow.js';\nimport styles from './SettingsSection.module.css';\n\n/** ⌘ on Apple platforms, Ctrl everywhere else. */\nexport function isApplePlatform(): boolean {\n if (typeof navigator === 'undefined') return true;\n const source = `${navigator.platform ?? ''} ${navigator.userAgent ?? ''}`;\n return /mac|iphone|ipad|ipod/i.test(source);\n}\n\ninterface Shortcut {\n keys: string[];\n action: string;\n}\n\nexport function shortcutGroups(mod: string): Array<{ title: string; items: Shortcut[] }> {\n return [\n {\n title: 'Navigation',\n items: [\n { keys: [mod, '1'], action: 'Chat' },\n { keys: [mod, '2'], action: 'Autonomy' },\n { keys: [mod, '3'], action: 'Approvals' },\n { keys: [mod, '4'], action: 'Usage' },\n { keys: [mod, '5'], action: 'Settings' },\n { keys: [mod, 'K'], action: 'Quick switcher' },\n { keys: [mod, ','], action: 'Settings' },\n ],\n },\n {\n title: 'Chat',\n items: [\n { keys: [mod, 'N'], action: 'New chat' },\n { keys: ['Enter'], action: 'Send message' },\n { keys: ['Shift', 'Enter'], action: 'New line' },\n { keys: ['Esc'], action: 'Stop dictation / close overlay' },\n ],\n },\n ];\n}\n\nexport function ShortcutsPanel() {\n const mod = isApplePlatform() ? '⌘' : 'Ctrl';\n return (\n <Panel title=\"Keyboard\">\n <div className={styles.shortcuts}>\n {shortcutGroups(mod).flatMap((group) =>\n group.items.map((item) => (\n <div key={`${group.title}-${item.action}-${item.keys.join('+')}`} className={styles.shortcut}>\n <span>{item.action}</span>\n <span className={styles.keys}>\n {item.keys.map((key) => (\n <kbd key={key} className={styles.key}>\n {key}\n </kbd>\n ))}\n </span>\n </div>\n )),\n )}\n </div>\n </Panel>\n );\n}\n","/**\n * routes/verse/sections/SettingsSection.tsx — the Settings rail item\n * (VERSE-CONTRACT-V2, owner A). Named export, NO props: the shell\n * lazy-mounts it and it reads everything it needs from the stores.\n *\n * Four panels in one 720px reading column: Appearance (live, no save\n * button), Connection (server, authority state, how to get tokens back),\n * Keyboard, and About. Each row is label + description on the left, control\n * on the right — the same rhythm all the way down, so the page reads as one\n * object rather than four inventions.\n */\nimport { useAppearance } from '../../../data/hooks.js';\nimport { OnboardingPanel } from '../onboarding/OnboardingPanel.js';\nimport { AboutPanel } from './AboutPanel.js';\nimport { AppearancePanel } from './AppearancePanel.js';\nimport { ConnectionPanel } from './ConnectionPanel.js';\nimport { ShortcutsPanel } from './ShortcutsPanel.js';\nimport styles from './SettingsSection.module.css';\n\nexport function SettingsSection() {\n const { appearance, set, reset } = useAppearance();\n\n return (\n <div className={styles.section}>\n <header className={styles.strip} data-app-region=\"drag\">\n <h2 className={styles.stripTitle}>Settings</h2>\n </header>\n <div className={styles.scroll}>\n <div className={styles.column}>\n <AppearancePanel appearance={appearance} onChange={set} onReset={reset} />\n <ConnectionPanel />\n <ShortcutsPanel />\n <OnboardingPanel />\n <AboutPanel />\n </div>\n </div>\n </div>\n );\n}\n"],"names":["Input","label","hint","error","size","mono","prefix","className","id","rest","generatedId","useId","inputId","hintId","errorId","describedBy","jsxs","styles","jsx","Segmented","options","value","onChange","block","aria","groupRef","useRef","move","delta","enabled","o","current","next","option","selected","e","Slider","min","max","valueLabel","valueText","trackImage","sliderId","span","percent","Switch","checked","disabled","control","Panel","title","action","children","SettingRow","description","htmlFor","labelId","stacked","text","Fragment","describe","completedAt","dismissedAt","OnboardingPanel","open","useOnboarding","Button","replayOnboarding","APP_VERSION","version","APP_NAME","AboutPanel","Tag","IconExternalLink","HEX_RE","FN_RE","clamp","unitValue","raw","scale","hslToRgb","h","s","l","hue","c","x","m","rgb","splitTopLevel","parts","depth","ch","p","colorWithPercent","lead","parseColorMix","body","args","first","second","c1","parseColor","c2","p1","p2","total","w1","w2","alpha","channel","k","input","hex","expand","fn","name","sat","light","flatten","color","backdrop","a","relativeLuminance","v","contrastRatio","foreground","background","bgRaw","fgRaw","base","bg","fg","l1","l2","hi","lo","accentHex","lightnessOffset","n","LIGHT_SURFACE","DARK_SURFACE","DARK_L_SHIFT","LINK_STEP","THEME_OPTIONS","IconMonitor","IconSun","IconMoon","DENSITY_OPTIONS","FONT_OPTIONS","RADIUS_OPTIONS","hueTrack","accentReadability","lightLink","darkLink","lightRatio","darkRatio","failing","AppearancePanel","appearance","onReset","accentLabelId","hueId","satId","lightId","motionId","preset","matchingAccentPreset","readability","isDefaultAppearance","theme","ACCENT_PRESETS","IconCheck","ACCENT_LIGHTNESS_RANGE","IconAlert","density","displayFont","radius","reduceMotion","StatusBadge","Meter","formatHoldExpiry","heldUntil","minutes","ConnectionPanel","phase","useAuthPhase","hold","useMutationHold","toast","useToast","confirmOpen","setConfirmOpen","useState","cancelRef","origin","copyOrigin","disconnect","clearReadSession","IconCopy","IconLock","clearMutationToken","IconInfo","Dialog","isApplePlatform","source","shortcutGroups","mod","ShortcutsPanel","group","item","key","SettingsSection","set","reset","useAppearance"],"mappings":"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"}
1
+ {"version":3,"file":"SettingsSection-C9Qs9JWW.js","sources":["../../../../../../src/web-ui/components/primitives/Input.tsx","../../../../../../src/web-ui/components/primitives/Segmented.tsx","../../../../../../src/web-ui/components/primitives/Slider.tsx","../../../../../../src/web-ui/components/primitives/Switch.tsx","../../../../../../src/web-ui/routes/verse/sections/SettingRow.tsx","../../../../../../src/web-ui/routes/verse/onboarding/OnboardingPanel.tsx","../../../../../../src/web-ui/routes/verse/sections/app-version.ts","../../../../../../src/web-ui/routes/verse/sections/AboutPanel.tsx","../../../../../../src/web-ui/design/contrast.ts","../../../../../../src/web-ui/routes/verse/sections/AppearancePanel.tsx","../../../../../../src/web-ui/routes/verse/sections/ConnectionPanel.tsx","../../../../../../src/web-ui/routes/verse/sections/ShortcutsPanel.tsx","../../../../../../src/web-ui/routes/verse/sections/SettingsSection.tsx"],"sourcesContent":["/**\n * components/primitives/Input.tsx — single-line text/number entry.\n *\n * Nothing here is a default browser control: hairline border, no inner card,\n * accent on focus. The accessible name comes from `label` when the field\n * stands alone, or from the caller's own `aria-label`/`aria-labelledby` when\n * it sits in a two-column settings row whose label lives on the other side.\n * An `error` is announced via role=\"alert\" and wired with aria-describedby —\n * red text alone never carries the message (design doc §6).\n */\nimport { useId, type InputHTMLAttributes, type ReactNode } from 'react';\nimport styles from './Input.module.css';\n\nexport interface InputProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'size' | 'className' | 'prefix'> {\n label?: ReactNode;\n /** Quiet helper text under the field. */\n hint?: ReactNode;\n /** Error message; also flips the field into its invalid styling. */\n error?: ReactNode;\n size?: 'sm' | 'md';\n /** Paths, ids, tokens counts — anything that should not be kerned. */\n mono?: boolean;\n /** Non-interactive leading text (e.g. \"$\", \"http://\"). Shadows the rarely\n * used HTML `prefix` attribute on purpose — this is the useful meaning. */\n prefix?: ReactNode;\n className?: string;\n}\n\nexport function Input({\n label,\n hint,\n error,\n size = 'md',\n mono = false,\n prefix,\n className,\n id,\n ...rest\n}: InputProps) {\n const generatedId = useId();\n const inputId = id ?? generatedId;\n const hintId = `${inputId}-hint`;\n const errorId = `${inputId}-error`;\n const describedBy = [rest['aria-describedby'], hint ? hintId : null, error ? errorId : null]\n .filter(Boolean)\n .join(' ');\n\n return (\n <div className={`${styles.field} ${className ?? ''}`}>\n {label ? (\n <label className={styles.label} htmlFor={inputId}>\n {label}\n </label>\n ) : null}\n <div className={`${styles.shell} ${styles[size]} ${error ? styles.invalid : ''}`}>\n {prefix ? <span className={styles.prefix}>{prefix}</span> : null}\n <input\n {...rest}\n id={inputId}\n className={`${styles.input} ${mono ? styles.mono : ''}`}\n aria-invalid={error ? true : rest['aria-invalid']}\n aria-describedby={describedBy || undefined}\n />\n </div>\n {hint ? (\n <p id={hintId} className={styles.hint}>\n {hint}\n </p>\n ) : null}\n {error ? (\n <p id={errorId} className={styles.error} role=\"alert\">\n {error}\n </p>\n ) : null}\n </div>\n );\n}\n","/**\n * components/primitives/Segmented.tsx — pick one of 2-4 options where the\n * choice applies instantly (theme, density, a status filter). It replaces\n * both a <select> (too heavy for three options) and a row of toggle buttons\n * (no single-selection semantics for a screen reader).\n *\n * Implemented as a radiogroup with ROVING TABINDEX: one Tab stop for the\n * group, arrows move between options and select as they go — the WAI-ARIA\n * radio-group pattern. Every option is reachable by keyboard and announced\n * as \"N of M\".\n */\nimport { useRef, type ReactNode } from 'react';\nimport styles from './Segmented.module.css';\n\nexport interface SegmentedOption<T extends string> {\n value: T;\n label: ReactNode;\n /** Leading 16px glyph; the text label always stays visible. */\n icon?: ReactNode;\n /** Spoken name when `label` is a glyph or an abbreviation. */\n ariaLabel?: string;\n disabled?: boolean;\n}\n\nexport interface SegmentedProps<T extends string> {\n options: ReadonlyArray<SegmentedOption<T>>;\n value: T;\n onChange: (next: T) => void;\n /** Accessible name for the group — required when no visible label precedes it. */\n 'aria-label'?: string;\n 'aria-labelledby'?: string;\n size?: 'sm' | 'md';\n /** Stretch each option to an equal share of the width. */\n block?: boolean;\n className?: string;\n}\n\nexport function Segmented<T extends string>({\n options,\n value,\n onChange,\n size = 'md',\n block = false,\n className,\n ...aria\n}: SegmentedProps<T>) {\n const groupRef = useRef<HTMLDivElement>(null);\n\n function move(delta: number): void {\n const enabled = options.filter((o) => !o.disabled);\n if (enabled.length === 0) return;\n const current = enabled.findIndex((o) => o.value === value);\n const next = enabled[(((current + delta) % enabled.length) + enabled.length) % enabled.length]!;\n onChange(next.value);\n // Keep DOM focus on the newly selected option (roving tabindex).\n requestAnimationFrame(() => {\n groupRef.current?.querySelector<HTMLButtonElement>(`[data-value=\"${next.value}\"]`)?.focus();\n });\n }\n\n return (\n <div\n ref={groupRef}\n role=\"radiogroup\"\n className={`${styles.group} ${styles[size]} ${block ? styles.block : ''} ${className ?? ''}`}\n {...aria}\n >\n {options.map((option) => {\n const selected = option.value === value;\n return (\n <button\n key={option.value}\n type=\"button\"\n role=\"radio\"\n aria-checked={selected}\n aria-label={option.ariaLabel}\n data-value={option.value}\n tabIndex={selected ? 0 : -1}\n disabled={option.disabled}\n className={styles.option}\n onClick={() => onChange(option.value)}\n onKeyDown={(e) => {\n if (e.key === 'ArrowRight' || e.key === 'ArrowDown') {\n e.preventDefault();\n move(1);\n } else if (e.key === 'ArrowLeft' || e.key === 'ArrowUp') {\n e.preventDefault();\n move(-1);\n }\n }}\n >\n {option.icon ? <span className={styles.glyph}>{option.icon}</span> : null}\n {option.label}\n </button>\n );\n })}\n </div>\n );\n}\n","/**\n * components/primitives/Slider.tsx — a continuous value (accent hue,\n * saturation, a budget). Native <input type=\"range\"> so the platform's\n * keyboard model (arrows, Home/End, PageUp/PageDown) comes for free; the\n * track and thumb are restyled to the token system.\n *\n * `valueLabel` renders the number in the display face next to the control.\n * It is presentational: the control's own accessible value is carried by\n * aria-valuetext when a unit would otherwise be lost (\"245\" -> \"245 degrees\").\n */\nimport { useId, type InputHTMLAttributes, type ReactNode } from 'react';\nimport styles from './Slider.module.css';\n\nexport interface SliderProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'type' | 'className' | 'value'> {\n label?: ReactNode;\n value: number;\n min?: number;\n max?: number;\n /** Rendered to the right of the track, in the display face. */\n valueLabel?: ReactNode;\n /** Spoken value, when the raw number needs a unit. */\n valueText?: string;\n /** Paint the filled portion of the track (hue sliders want a gradient instead). */\n trackImage?: string;\n className?: string;\n}\n\nexport function Slider({\n label,\n value,\n min = 0,\n max = 100,\n valueLabel,\n valueText,\n trackImage,\n className,\n id,\n ...rest\n}: SliderProps) {\n const generatedId = useId();\n const sliderId = id ?? generatedId;\n const span = Math.max(1, max - min);\n const percent = Math.round(((value - min) / span) * 100);\n\n return (\n <div className={`${styles.field} ${className ?? ''}`}>\n {label ? (\n <label className={styles.label} htmlFor={sliderId}>\n {label}\n </label>\n ) : null}\n <div className={styles.row}>\n <input\n {...rest}\n id={sliderId}\n type=\"range\"\n className={styles.input}\n value={value}\n min={min}\n max={max}\n aria-valuetext={valueText}\n style={\n {\n '--slider-fill': `${percent}%`,\n ...(trackImage ? { '--slider-track-image': trackImage } : {}),\n } as React.CSSProperties\n }\n data-custom-track={trackImage ? 'true' : undefined}\n />\n {valueLabel !== undefined ? <span className={styles.value}>{valueLabel}</span> : null}\n </div>\n </div>\n );\n}\n","/**\n * components/primitives/Switch.tsx — a binary setting that takes effect\n * immediately (no form submit). role=\"switch\" + aria-checked, so a screen\n * reader announces \"on\"/\"off\" rather than \"checkbox, checked\".\n *\n * State is never carried by color alone: the knob's POSITION is the primary\n * signal (design doc §6), the accent fill is reinforcement.\n */\nimport type { ReactNode } from 'react';\nimport styles from './Switch.module.css';\n\nexport interface SwitchProps {\n checked: boolean;\n onChange: (next: boolean) => void;\n /** Visible label; when omitted, pass `aria-label`. */\n label?: ReactNode;\n 'aria-label'?: string;\n 'aria-describedby'?: string;\n disabled?: boolean;\n id?: string;\n className?: string;\n}\n\nexport function Switch({\n checked,\n onChange,\n label,\n disabled = false,\n id,\n className,\n ...aria\n}: SwitchProps) {\n const control = (\n <button\n type=\"button\"\n id={id}\n role=\"switch\"\n aria-checked={checked}\n disabled={disabled}\n className={styles.track}\n onClick={() => onChange(!checked)}\n {...aria}\n >\n <span className={styles.knob} aria-hidden=\"true\" />\n </button>\n );\n\n if (!label) return <span className={className}>{control}</span>;\n\n return (\n <label className={`${styles.wrapper} ${className ?? ''}`}>\n {control}\n <span className={styles.label}>{label}</span>\n </label>\n );\n}\n","/**\n * routes/verse/sections/SettingRow.tsx — the Settings layout primitive:\n * label + description on the left, control on the right, hairline between.\n *\n * The label is a real <label> bound to the control's id when one is given;\n * for composite controls (a radiogroup, a swatch grid) pass `labelId` and\n * point the group's `aria-labelledby` at it instead — a <label> cannot name\n * a group, and an unnamed radiogroup is announced as \"group\".\n */\nimport type { ReactNode } from 'react';\nimport styles from './SettingsSection.module.css';\n\nexport interface PanelProps {\n title: ReactNode;\n /** Right-aligned affordance in the panel header (e.g. \"Reset\"). */\n action?: ReactNode;\n children: ReactNode;\n}\n\nexport function Panel({ title, action, children }: PanelProps) {\n return (\n <section className={styles.panel}>\n <div className={styles.panelHead}>\n <h3 className={styles.panelTitle}>{title}</h3>\n {action}\n </div>\n <div className={styles.panelBody}>{children}</div>\n </section>\n );\n}\n\nexport interface SettingRowProps {\n label: ReactNode;\n description?: ReactNode;\n /** id of the control this row labels (renders a real <label for>). */\n htmlFor?: string;\n /** id to put on the label text, for a control using aria-labelledby. */\n labelId?: string;\n /** Put the control under the text instead of beside it (sliders, previews). */\n stacked?: boolean;\n children: ReactNode;\n}\n\nexport function SettingRow({\n label,\n description,\n htmlFor,\n labelId,\n stacked = false,\n children,\n}: SettingRowProps) {\n const text = (\n <>\n <span className={styles.rowLabel} id={labelId}>\n {label}\n </span>\n {description ? <span className={styles.rowDescription}>{description}</span> : null}\n </>\n );\n\n return (\n <div className={`${styles.row} ${stacked ? styles.rowStacked : ''}`}>\n <div className={styles.rowText}>\n {htmlFor ? (\n <label htmlFor={htmlFor} className={styles.rowText}>\n {text}\n </label>\n ) : (\n text\n )}\n </div>\n <div className={styles.rowControl}>{children}</div>\n </div>\n );\n}\n","/**\n * routes/verse/onboarding/OnboardingPanel.tsx — the Settings row that brings\n * the first-run tour back.\n *\n * It lives here rather than in sections/ so the whole onboarding feature is\n * one folder; SettingsSection.tsx imports it the same way it imports its own\n * panels, and reuses the same Panel/SettingRow primitives so the row keeps\n * the label-left / control-right rhythm of every other setting.\n *\n * The description states what the tour actually covers, and — because this\n * is the only place the stored answer is visible — whether it has been seen.\n */\nimport { Button } from '../../../components/primitives/index.js';\nimport { Panel, SettingRow } from '../sections/SettingRow.js';\nimport { replayOnboarding } from './onboarding-store.js';\nimport { useOnboarding } from './useOnboarding.js';\n\nfunction describe(completedAt: string | null, dismissedAt: string | null): string {\n if (completedAt) return `Last completed ${new Date(completedAt).toLocaleDateString()}.`;\n if (dismissedAt) return 'Skipped. Nothing was missed — it is all reachable from the sections themselves.';\n return 'Not seen yet.';\n}\n\nexport function OnboardingPanel() {\n const { completedAt, dismissedAt, open } = useOnboarding();\n\n return (\n <Panel title=\"Onboarding\">\n <SettingRow\n label=\"Replay the first-run tour\"\n description={`Your connected seats, whether a local runtime is available, and what each of the three stop controls really halts. ${describe(completedAt, dismissedAt)}`}\n >\n <Button variant=\"subtle\" size=\"sm\" onClick={replayOnboarding} disabled={open}>\n {open ? 'Showing' : 'Replay'}\n </Button>\n </SettingRow>\n </Panel>\n );\n}\n","/**\n * routes/verse/sections/app-version.ts — the hub's version, for About.\n *\n * Read straight from package.json (Vite inlines the named export at build\n * time and `resolveJsonModule` types it), because no API route reports it:\n * /api/health answers liveness, /api/snapshot answers fleet state, and\n * neither carries the running hub's version. A hardcoded string here would\n * silently drift from the published package on every release.\n */\nimport { version } from '../../../../../package.json';\n\nexport const APP_VERSION: string = version;\nexport const APP_NAME = 'Ashlr Verse';\n","/**\n * routes/verse/sections/AboutPanel.tsx — what this is and which build it is.\n * The version comes from package.json at build time (./app-version.ts).\n */\nimport { IconExternalLink } from '../../../components/primitives/icons.js';\nimport { Tag } from '../../../components/primitives/index.js';\nimport { APP_NAME, APP_VERSION } from './app-version.js';\nimport { Panel } from './SettingRow.js';\nimport styles from './SettingsSection.module.css';\n\nexport function AboutPanel() {\n return (\n <Panel title=\"About\">\n <div className={`${styles.row} ${styles.rowStacked}`}>\n <div className={styles.about}>\n <p className={styles.aboutName}>{APP_NAME}</p>\n <p className={styles.aboutLine}>\n <Tag mono>v{APP_VERSION}</Tag>\n <span>ashlr-hub — local-first command center for agentic engineers.</span>\n </p>\n <p className={styles.aboutLine}>\n Every session, token and artifact stays on this machine. The console talks to one local server and no\n third-party service.\n </p>\n <p className={styles.aboutLine}>\n <a\n className={styles.link}\n href=\"https://github.com/ashlrai/ashlr-hub\"\n target=\"_blank\"\n rel=\"noreferrer noopener\"\n >\n Source and changelog\n <IconExternalLink size={12} />\n </a>\n </p>\n </div>\n </div>\n </Panel>\n );\n}\n","/**\n * design/contrast.ts — WCAG 2.1 contrast math over CSS color strings.\n *\n * Two callers, one implementation:\n * - routes/verse/sections/AppearancePanel.tsx warns, live, when a\n * hand-dragged accent stops being readable as link/button text in the\n * active theme. The design language allows any hue; it does not allow an\n * unreadable one to ship silently.\n * - design/tokens-contrast.test.ts asserts the whole palette in BOTH\n * themes (design doc §6: >= 4.5:1 body text, >= 3:1 meaningful borders).\n *\n * Deliberately dependency-free and DOM-free: parse -> linearize -> ratio.\n * Supports the subset of CSS color syntax the stylesheets actually use —\n * #rgb / #rrggbb / #rrggbbaa, rgb()/rgba(), hsl()/hsla(), both the legacy\n * comma form and the modern space form, plus `color-mix(in srgb, ...)`.\n * Anything else returns null rather than guessing a color.\n *\n * `color-mix` is in that list because the meaning-carrying marks that the\n * contrast suite has to guard are not all plain tokens: the chart gridline,\n * the empty half of a window meter and the diff row tints are all declared as\n * a mix in a CSS module. Without this the suite could only assert the token a\n * mix is DERIVED from, which is precisely the gap that let a 45%-alpha\n * gridline ship under a comment claiming it cleared 3:1.\n */\n\nexport interface Rgba {\n /** 0-255 */\n r: number;\n /** 0-255 */\n g: number;\n /** 0-255 */\n b: number;\n /** 0-1 */\n a: number;\n}\n\nconst HEX_RE = /^#([0-9a-f]{3,8})$/i;\nconst FN_RE = /^(rgba?|hsla?)\\(([^)]*)\\)$/i;\n\nfunction clamp(n: number, min: number, max: number): number {\n return Math.min(max, Math.max(min, n));\n}\n\n/** \"50%\" -> 0.5, \"0.5\" -> 0.5, \"128\" (of 255) handled by the caller. */\nfunction unitValue(raw: string, scale: number): number {\n const text = raw.trim();\n if (text.endsWith('%')) return (Number.parseFloat(text) / 100) * scale;\n return Number.parseFloat(text);\n}\n\nfunction hslToRgb(h: number, s: number, l: number): { r: number; g: number; b: number } {\n const hue = ((h % 360) + 360) % 360;\n const c = (1 - Math.abs(2 * l - 1)) * s;\n const x = c * (1 - Math.abs(((hue / 60) % 2) - 1));\n const m = l - c / 2;\n let rgb: [number, number, number];\n if (hue < 60) rgb = [c, x, 0];\n else if (hue < 120) rgb = [x, c, 0];\n else if (hue < 180) rgb = [0, c, x];\n else if (hue < 240) rgb = [0, x, c];\n else if (hue < 300) rgb = [x, 0, c];\n else rgb = [c, 0, x];\n return {\n r: Math.round((rgb[0] + m) * 255),\n g: Math.round((rgb[1] + m) * 255),\n b: Math.round((rgb[2] + m) * 255),\n };\n}\n\n/**\n * Split a function's argument list on top-level commas, so a nested\n * `rgb(...)`/`color-mix(...)` argument survives intact.\n */\nfunction splitTopLevel(text: string): string[] {\n const parts: string[] = [];\n let depth = 0;\n let current = '';\n for (const ch of text) {\n if (ch === '(') depth += 1;\n else if (ch === ')') depth -= 1;\n if (ch === ',' && depth === 0) {\n parts.push(current);\n current = '';\n continue;\n }\n current += ch;\n }\n parts.push(current);\n return parts.map((p) => p.trim()).filter((p) => p.length > 0);\n}\n\n/** `#abc 40%` -> ['#abc', 40]; a missing percentage comes back as null. */\nfunction colorWithPercent(raw: string): { color: string; pct: number | null } | null {\n const text = raw.trim();\n const m = /\\s(\\d*\\.?\\d+)%$/.exec(text);\n if (m) return { color: text.slice(0, m.index).trim(), pct: Number.parseFloat(m[1]!) };\n const lead = /^(\\d*\\.?\\d+)%\\s/.exec(text);\n if (lead) return { color: text.slice(lead[0].length).trim(), pct: Number.parseFloat(lead[1]!) };\n return { color: text, pct: null };\n}\n\n/**\n * `color-mix(in srgb, <color> [p%], <color> [p%])`, per CSS Color 5: the two\n * percentages are normalized to sum to 100, the result's alpha is their\n * alpha-weighted sum, and the channels are mixed PREMULTIPLIED — which is why\n * mixing against `transparent` yields the first color at that alpha rather\n * than a color darkened toward black.\n *\n * Only the `srgb` color space is accepted. Every other space would need its\n * own transfer function, and silently treating `oklab` as srgb would report a\n * contrast ratio the browser does not agree with.\n */\nfunction parseColorMix(text: string): Rgba | null {\n const body = /^color-mix\\((.*)\\)$/is.exec(text.trim());\n if (!body) return null;\n const args = splitTopLevel(body[1]!);\n if (args.length !== 3) return null;\n if (args[0]!.replace(/\\s+/g, ' ').trim() !== 'in srgb') return null;\n\n const first = colorWithPercent(args[1]!);\n const second = colorWithPercent(args[2]!);\n if (!first || !second) return null;\n const c1 = parseColor(first.color);\n const c2 = parseColor(second.color);\n if (!c1 || !c2) return null;\n\n let p1 = first.pct;\n let p2 = second.pct;\n if (p1 === null && p2 === null) {\n p1 = 50;\n p2 = 50;\n } else if (p1 === null) p1 = 100 - p2!;\n else if (p2 === null) p2 = 100 - p1;\n const total = p1 + p2!;\n if (total <= 0) return null;\n const w1 = p1 / total;\n const w2 = p2! / total;\n\n const alpha = c1.a * w1 + c2.a * w2;\n if (alpha <= 0) return { r: 0, g: 0, b: 0, a: 0 };\n const channel = (k: 'r' | 'g' | 'b'): number =>\n clamp(Math.round((c1[k] * c1.a * w1 + c2[k] * c2.a * w2) / alpha), 0, 255);\n return { r: channel('r'), g: channel('g'), b: channel('b'), a: clamp(alpha, 0, 1) };\n}\n\n/** Parse a CSS color string. Returns null for anything unrecognized. */\nexport function parseColor(input: string): Rgba | null {\n const text = input.trim().toLowerCase();\n if (text === 'transparent') return { r: 0, g: 0, b: 0, a: 0 };\n if (text.startsWith('color-mix(')) return parseColorMix(text);\n\n const hex = HEX_RE.exec(text);\n if (hex) {\n const body = hex[1]!;\n const expand = (s: string) => Number.parseInt(s.length === 1 ? s + s : s, 16);\n if (body.length === 3 || body.length === 4) {\n return {\n r: expand(body[0]!),\n g: expand(body[1]!),\n b: expand(body[2]!),\n a: body.length === 4 ? expand(body[3]!) / 255 : 1,\n };\n }\n if (body.length === 6 || body.length === 8) {\n return {\n r: expand(body.slice(0, 2)),\n g: expand(body.slice(2, 4)),\n b: expand(body.slice(4, 6)),\n a: body.length === 8 ? expand(body.slice(6, 8)) / 255 : 1,\n };\n }\n return null;\n }\n\n const fn = FN_RE.exec(text);\n if (!fn) return null;\n const name = fn[1]!;\n // Both syntaxes: `a, b, c, d` and `a b c / d`.\n const parts = fn[2]!\n .replace(/\\//g, ' ')\n .split(/[\\s,]+/)\n .filter(Boolean);\n if (parts.length < 3) return null;\n const alpha = parts.length >= 4 ? clamp(unitValue(parts[3]!, 1), 0, 1) : 1;\n\n if (name.startsWith('rgb')) {\n return {\n r: clamp(Math.round(unitValue(parts[0]!, 255)), 0, 255),\n g: clamp(Math.round(unitValue(parts[1]!, 255)), 0, 255),\n b: clamp(Math.round(unitValue(parts[2]!, 255)), 0, 255),\n a: alpha,\n };\n }\n\n const hue = Number.parseFloat(parts[0]!);\n const sat = clamp(unitValue(parts[1]!, 1), 0, 1);\n const light = clamp(unitValue(parts[2]!, 1), 0, 1);\n if (!Number.isFinite(hue)) return null;\n return { ...hslToRgb(hue, sat, light), a: alpha };\n}\n\n/** Composite a (possibly translucent) color over an opaque backdrop. */\nexport function flatten(color: Rgba, backdrop: Rgba): Rgba {\n if (color.a >= 1) return color;\n const a = color.a;\n return {\n r: Math.round(color.r * a + backdrop.r * (1 - a)),\n g: Math.round(color.g * a + backdrop.g * (1 - a)),\n b: Math.round(color.b * a + backdrop.b * (1 - a)),\n a: 1,\n };\n}\n\n/** WCAG relative luminance of an opaque color. */\nexport function relativeLuminance(color: Rgba): number {\n const channel = (v: number): number => {\n const s = v / 255;\n return s <= 0.03928 ? s / 12.92 : ((s + 0.055) / 1.055) ** 2.4;\n };\n return 0.2126 * channel(color.r) + 0.7152 * channel(color.g) + 0.0722 * channel(color.b);\n}\n\n/**\n * WCAG contrast ratio (1-21) between two CSS colors. A translucent color is\n * composited over `backdrop` first (default white) — asking for the contrast\n * of a 14%-alpha status background is otherwise meaningless.\n * Returns null when either color cannot be parsed, so a caller can say\n * \"unknown\" instead of asserting on a guess.\n */\nexport function contrastRatio(foreground: string, background: string, backdrop = '#ffffff'): number | null {\n const bgRaw = parseColor(background);\n const fgRaw = parseColor(foreground);\n const base = parseColor(backdrop);\n if (!bgRaw || !fgRaw || !base) return null;\n const bg = flatten(bgRaw, base);\n const fg = flatten(fgRaw, bg);\n const l1 = relativeLuminance(fg);\n const l2 = relativeLuminance(bg);\n const [hi, lo] = l1 >= l2 ? [l1, l2] : [l2, l1];\n return (hi + 0.05) / (lo + 0.05);\n}\n\n/** Convenience for the appearance panel: does this pair clear body-text contrast? */\nexport function meetsTextContrast(foreground: string, background: string, backdrop?: string): boolean {\n const ratio = contrastRatio(foreground, background, backdrop);\n return ratio !== null && ratio >= 4.5;\n}\n\n/**\n * The accent, resolved to a hex the same way tokens.css derives its ramp\n * (hsl channels + a per-step lightness offset). Used by the appearance panel\n * to preview and contrast-check a hue the operator is dragging, without\n * reading computed styles mid-drag.\n */\nexport function accentHex(h: number, s: number, l: number, lightnessOffset = 0): string {\n const rgb = hslToRgb(h, clamp(s, 0, 100) / 100, clamp(l + lightnessOffset, 0, 100) / 100);\n const hex = (n: number) => n.toString(16).padStart(2, '0');\n return `#${hex(rgb.r)}${hex(rgb.g)}${hex(rgb.b)}`;\n}\n","/**\n * routes/verse/sections/AppearancePanel.tsx — the \"Linux\" part of the design\n * language: theme, accent, density, display face, radius, motion.\n *\n * Every control applies IMMEDIATELY (design doc §3: live preview, no save\n * button) because the whole app is the preview — the panel writes through\n * data/appearance-store.ts, which writes the tokens on <html>. The preview\n * block at the end exists to show type, numerals, a filled action and a\n * meter in one place, so the effect of a change is visible without leaving\n * Settings.\n *\n * The hue slider is free-range, so the panel checks the resulting link color\n * against BOTH themes with design/contrast.ts and warns when a choice drops\n * under 4.5:1 — the operator keeps the hue they asked for, but is never\n * allowed to make it unreadable without being told.\n */\nimport { useId } from 'react';\nimport { Button, Input, Meter, Segmented, Slider, StatusBadge, Switch, Tag } from '../../../components/primitives/index.js';\nimport { IconAlert, IconCheck, IconMonitor, IconMoon, IconSun } from '../../../components/primitives/icons.js';\nimport { accentHex, contrastRatio } from '../../../design/contrast.js';\nimport {\n ACCENT_LIGHTNESS_RANGE,\n ACCENT_PRESETS,\n isDefaultAppearance,\n matchingAccentPreset,\n type Appearance,\n type Density,\n type DisplayFont,\n type RadiusScale,\n type ThemePreference,\n} from '../../../data/appearance-store.js';\nimport { Panel, SettingRow } from './SettingRow.js';\nimport styles from './SettingsSection.module.css';\n\n/**\n * The literal `--bg-surface` of each theme (design/tokens.css). Used only to\n * score a candidate accent; design/tokens-contrast.test.ts asserts these two\n * constants still match the stylesheet, so a future retune cannot leave the\n * warning scoring against a color the app no longer paints.\n */\nexport const LIGHT_SURFACE = '#ffffff';\nexport const DARK_SURFACE = '#121214';\n/** Dark raises accent lightness by --accent-l-shift; --accent-600 sits 8% below/above it. */\nconst DARK_L_SHIFT = 6;\nconst LINK_STEP = 8;\n\nconst THEME_OPTIONS = [\n { value: 'system' as ThemePreference, label: 'System', icon: <IconMonitor /> },\n { value: 'light' as ThemePreference, label: 'Light', icon: <IconSun /> },\n { value: 'dark' as ThemePreference, label: 'Dark', icon: <IconMoon /> },\n];\n\nconst DENSITY_OPTIONS = [\n { value: 'comfortable' as Density, label: 'Comfortable' },\n { value: 'compact' as Density, label: 'Compact' },\n];\n\nconst FONT_OPTIONS = [\n { value: 'grotesk' as DisplayFont, label: 'Space Grotesk' },\n { value: 'ui' as DisplayFont, label: 'UI sans' },\n { value: 'mono' as DisplayFont, label: 'Mono' },\n];\n\nconst RADIUS_OPTIONS = [\n { value: 'sharp' as RadiusScale, label: 'Sharp' },\n { value: 'default' as RadiusScale, label: 'Default' },\n { value: 'soft' as RadiusScale, label: 'Soft' },\n];\n\n/** A 360° sweep at the current saturation/lightness, so the track shows the choice. */\nfunction hueTrack(s: number, l: number): string {\n const stops = [0, 60, 120, 180, 240, 300, 360].map((h) => `${accentHex(h, s, l)} ${(h / 360) * 100}%`);\n return `linear-gradient(to right, ${stops.join(', ')})`;\n}\n\nexport interface AccentReadability {\n lightRatio: number | null;\n darkRatio: number | null;\n /** Themes in which the derived link color drops below 4.5:1. */\n failing: Array<'light' | 'dark'>;\n}\n\n/** Exported for the section's test: the same math the warning renders from. */\nexport function accentReadability(h: number, s: number, l: number): AccentReadability {\n const lightLink = accentHex(h, s, l, -LINK_STEP);\n const darkLink = accentHex(h, s, l, DARK_L_SHIFT + LINK_STEP);\n const lightRatio = contrastRatio(lightLink, LIGHT_SURFACE);\n const darkRatio = contrastRatio(darkLink, DARK_SURFACE);\n const failing: Array<'light' | 'dark'> = [];\n if (lightRatio !== null && lightRatio < 4.5) failing.push('light');\n if (darkRatio !== null && darkRatio < 4.5) failing.push('dark');\n return { lightRatio, darkRatio, failing };\n}\n\nexport interface AppearancePanelProps {\n appearance: Appearance;\n onChange: (patch: Partial<Appearance>) => void;\n onReset: () => void;\n}\n\nexport function AppearancePanel({ appearance, onChange, onReset }: AppearancePanelProps) {\n const accentLabelId = useId();\n const hueId = useId();\n const satId = useId();\n const lightId = useId();\n const motionId = useId();\n\n const preset = matchingAccentPreset(appearance);\n const readability = accentReadability(appearance.accentH, appearance.accentS, appearance.accentL);\n\n return (\n <Panel\n title=\"Appearance\"\n action={\n <Button\n variant=\"ghost\"\n size=\"sm\"\n onClick={onReset}\n disabled={isDefaultAppearance(appearance)}\n title=\"Restore the shipped theme, accent, density, font, radius and motion\"\n >\n Reset to defaults\n </Button>\n }\n >\n <SettingRow label=\"Theme\" description=\"System follows your OS appearance setting.\">\n <Segmented\n aria-label=\"Theme\"\n options={THEME_OPTIONS}\n value={appearance.theme}\n onChange={(theme) => onChange({ theme })}\n />\n </SettingRow>\n\n <SettingRow\n label=\"Accent\"\n labelId={accentLabelId}\n description={\n preset\n ? `${preset.label} — used for links, focus rings and the one primary action per surface.`\n : 'Custom hue — used for links, focus rings and the one primary action per surface.'\n }\n >\n <div className={styles.swatches} role=\"radiogroup\" aria-labelledby={accentLabelId}>\n {ACCENT_PRESETS.map((p) => {\n const selected = preset?.id === p.id;\n return (\n <button\n key={p.id}\n type=\"button\"\n role=\"radio\"\n aria-checked={selected}\n aria-label={p.label}\n tabIndex={selected || (!preset && p.id === ACCENT_PRESETS[0]!.id) ? 0 : -1}\n className={styles.swatch}\n style={{ background: accentHex(p.h, p.s, p.l) }}\n onClick={() => onChange({ accentH: p.h, accentS: p.s, accentL: p.l })}\n >\n {selected ? (\n <span className={styles.swatchCheck}>\n <IconCheck size={12} />\n </span>\n ) : null}\n </button>\n );\n })}\n </div>\n </SettingRow>\n\n <SettingRow\n label=\"Accent channels\"\n description=\"Hue, saturation and lightness are written straight onto the root element — the whole app follows as you drag.\"\n stacked\n >\n <div className={styles.sliderStack}>\n <Slider\n id={hueId}\n label=\"Hue\"\n min={0}\n max={359}\n value={appearance.accentH}\n valueLabel={`${appearance.accentH}°`}\n valueText={`${appearance.accentH} degrees`}\n trackImage={hueTrack(appearance.accentS, appearance.accentL)}\n onChange={(e) => onChange({ accentH: Number(e.currentTarget.value) })}\n />\n <Slider\n id={satId}\n label=\"Saturation\"\n min={0}\n max={100}\n value={appearance.accentS}\n valueLabel={`${appearance.accentS}%`}\n valueText={`${appearance.accentS} percent`}\n onChange={(e) => onChange({ accentS: Number(e.currentTarget.value) })}\n />\n <Slider\n id={lightId}\n label=\"Lightness\"\n min={ACCENT_LIGHTNESS_RANGE.min}\n max={ACCENT_LIGHTNESS_RANGE.max}\n value={appearance.accentL}\n valueLabel={`${appearance.accentL}%`}\n valueText={`${appearance.accentL} percent`}\n onChange={(e) => onChange({ accentL: Number(e.currentTarget.value) })}\n />\n {readability.failing.length > 0 ? (\n <p className={styles.contrastWarning} role=\"status\">\n <IconAlert size={14} />\n <span>\n This accent falls below 4.5:1 as link text in{' '}\n {readability.failing.length === 2 ? 'both themes' : `${readability.failing[0]} mode`}. Raise or lower\n the lightness to keep it readable.\n </span>\n </p>\n ) : null}\n </div>\n </SettingRow>\n\n <SettingRow label=\"Density\" description=\"Row height and control padding across every view.\">\n <Segmented\n aria-label=\"Density\"\n options={DENSITY_OPTIONS}\n value={appearance.density}\n onChange={(density) => onChange({ density })}\n />\n </SettingRow>\n\n <SettingRow label=\"Display font\" description=\"Titles, seat names, metrics and numerals. Body copy stays in the UI sans.\">\n <Segmented\n aria-label=\"Display font\"\n options={FONT_OPTIONS}\n value={appearance.displayFont}\n onChange={(displayFont) => onChange({ displayFont })}\n />\n </SettingRow>\n\n <SettingRow label=\"Corner radius\" description=\"Sharp reads like a terminal; soft reads like a consumer app.\">\n <Segmented\n aria-label=\"Corner radius\"\n options={RADIUS_OPTIONS}\n value={appearance.radius}\n onChange={(radius) => onChange({ radius })}\n />\n </SettingRow>\n\n <SettingRow\n label=\"Reduce motion\"\n htmlFor={motionId}\n description=\"Collapses every transition to 1ms. Defaults to your system preference; turning it off here overrides that.\"\n >\n <Switch\n id={motionId}\n checked={appearance.reduceMotion}\n onChange={(reduceMotion) => onChange({ reduceMotion })}\n aria-label=\"Reduce motion\"\n />\n </SettingRow>\n\n <SettingRow label=\"Preview\" description=\"Live — these are the real primitives, not a picture of them.\" stacked>\n <div className={styles.preview}>\n <p className={styles.previewHeading}>Ashlr Verse</p>\n <p className={styles.previewBody}>\n Body copy stays in the UI sans at the reading measure; numerals like{' '}\n <span className={styles.previewNumerals}>18,420 / 66,000</span> use the display face.\n </p>\n <div className={styles.previewRow}>\n <Button variant=\"primary\" size=\"sm\">\n Primary\n </Button>\n <Button variant=\"subtle\" size=\"sm\">\n Subtle\n </Button>\n <Button variant=\"ghost\" size=\"sm\">\n Ghost\n </Button>\n <Button variant=\"danger\" size=\"sm\">\n Destructive\n </Button>\n </div>\n <div className={styles.previewRow}>\n <StatusBadge status=\"running\" />\n <Tag engine=\"claude\">Claude Max</Tag>\n <Tag engine=\"local\" mono>\n qwen3-coder\n </Tag>\n </div>\n <Meter value={18_420} max={66_000} label=\"Context\" />\n <Input aria-label=\"Preview field\" placeholder=\"A field at the current density\" size=\"sm\" />\n </div>\n </SettingRow>\n </Panel>\n );\n}\n","/**\n * routes/verse/sections/ConnectionPanel.tsx — which server this window is\n * talking to, what authority it currently holds, and how to get the tokens\n * back if it loses them.\n *\n * SECURITY: this panel never renders, copies or logs a token. It shows the\n * STATE of the two authorities (read session, mutation hold) and tells the\n * operator where the real values are printed — the terminal that started the\n * server. The mutation token is memory-only by design (data/auth-store.ts);\n * showing it here would put it on screen, in a screenshot, and in any\n * screen-recording of a demo.\n */\nimport { useRef, useState } from 'react';\nimport { Button, Dialog, Input, StatusBadge } from '../../../components/primitives/index.js';\nimport { IconCopy, IconInfo, IconLock } from '../../../components/primitives/icons.js';\nimport { clearMutationToken, clearReadSession } from '../../../data/auth-store.js';\nimport { useAuthPhase, useMutationHold } from '../../../data/hooks.js';\nimport { useToast } from '../../../components/primitives/Toast.js';\nimport { Panel, SettingRow } from './SettingRow.js';\nimport styles from './SettingsSection.module.css';\n\nfunction formatHoldExpiry(heldUntil: number | null): string {\n if (heldUntil === null) return 'locked';\n const minutes = Math.max(0, Math.round((heldUntil - Date.now()) / 60_000));\n if (minutes <= 0) return 'expiring now';\n return `unlocked for ${minutes} more minute${minutes === 1 ? '' : 's'}`;\n}\n\nexport function ConnectionPanel() {\n const phase = useAuthPhase();\n const hold = useMutationHold();\n const toast = useToast();\n const [confirmOpen, setConfirmOpen] = useState(false);\n const cancelRef = useRef<HTMLButtonElement>(null);\n\n const origin = typeof window === 'undefined' ? '' : window.location.origin;\n\n async function copyOrigin(): Promise<void> {\n try {\n await navigator.clipboard.writeText(origin);\n toast.show('Server address copied.');\n } catch {\n toast.show('Could not reach the clipboard — select the field and copy manually.', 'danger');\n }\n }\n\n async function disconnect(): Promise<void> {\n setConfirmOpen(false);\n await clearReadSession();\n toast.show('Disconnected. Paste the read token to reconnect.');\n }\n\n return (\n <Panel title=\"Connection\">\n <SettingRow label=\"Server\" description=\"This window talks to one local hub. Nothing leaves your machine.\">\n <div className={styles.origin}>\n <Input value={origin} readOnly mono size=\"sm\" aria-label=\"Server address\" />\n </div>\n <Button variant=\"ghost\" size=\"sm\" icon={<IconCopy />} onClick={() => void copyOrigin()}>\n Copy\n </Button>\n </SettingRow>\n\n <SettingRow label=\"Read session\" description=\"A 15-minute signed cookie, renewed silently while this tab stays open.\">\n <StatusBadge\n status={phase === 'authenticated' ? 'connected' : phase === 'checking' ? 'checking' : 'disconnected'}\n tone={phase === 'authenticated' ? 'success' : phase === 'checking' ? 'running' : 'danger'}\n />\n </SettingRow>\n\n <SettingRow\n label=\"Mutation hold\"\n description=\"Every action that changes something needs the mutation token. It is held in memory only, never stored, and clears when this tab closes.\"\n >\n <StatusBadge\n status={hold.hasHold ? formatHoldExpiry(hold.heldUntil) : 'locked'}\n tone={hold.hasHold ? 'success' : 'neutral'}\n />\n <Button\n variant=\"subtle\"\n size=\"sm\"\n icon={<IconLock />}\n onClick={() => {\n clearMutationToken();\n toast.show('Mutation hold cleared.');\n }}\n disabled={!hold.hasHold}\n >\n Lock now\n </Button>\n </SettingRow>\n\n <SettingRow\n label=\"Disconnect\"\n description=\"Ends the read session in this browser and clears the mutation hold. Chats on the server are untouched.\"\n >\n <Button variant=\"danger\" size=\"sm\" onClick={() => setConfirmOpen(true)}>\n Disconnect\n </Button>\n </SettingRow>\n\n <div className={styles.row}>\n <p className={styles.note}>\n <span className={styles.noteIcon}>\n <IconInfo size={14} />\n </span>\n <span>\n <strong>Where the tokens come from.</strong> Start the console with{' '}\n <code className={styles.code}>ashlr verse</code> — it prints a read token and a mutation token in that\n terminal, and opens this page. The desktop app injects both for you. Tokens are never displayed here, and\n the hub never writes them into a page, a log line or an API response. Lost them? Stop the server and start\n it again; it mints a fresh pair.\n </span>\n </p>\n </div>\n\n <Dialog\n open={confirmOpen}\n onClose={() => setConfirmOpen(false)}\n titleId=\"verse-settings-disconnect\"\n title=\"Disconnect from this server?\"\n description=\"You will need the read token again to get back in. Running sessions keep running on the server.\"\n initialFocusRef={cancelRef}\n >\n <div className={styles.previewRow} style={{ justifyContent: 'flex-end' }}>\n <Button ref={cancelRef} variant=\"subtle\" onClick={() => setConfirmOpen(false)}>\n Cancel\n </Button>\n <Button variant=\"danger\" onClick={() => void disconnect()}>\n Disconnect\n </Button>\n </div>\n </Dialog>\n </Panel>\n );\n}\n","/**\n * routes/verse/sections/ShortcutsPanel.tsx — the keyboard reference.\n *\n * It documents the bindings the V2 shell contract fixes (⌘1-⌘5, ⌘K, ⌘N, ⌘,)\n * plus the composer's own keys. It is a REFERENCE, not the implementation:\n * the handlers live with the shell (owner C) and the composer. Keeping the\n * list here means an operator can find a binding without a manual; keeping\n * it declarative means it is one array to update when a binding changes.\n */\nimport { Panel } from './SettingRow.js';\nimport styles from './SettingsSection.module.css';\n\n/** ⌘ on Apple platforms, Ctrl everywhere else. */\nexport function isApplePlatform(): boolean {\n if (typeof navigator === 'undefined') return true;\n const source = `${navigator.platform ?? ''} ${navigator.userAgent ?? ''}`;\n return /mac|iphone|ipad|ipod/i.test(source);\n}\n\ninterface Shortcut {\n keys: string[];\n action: string;\n}\n\nexport function shortcutGroups(mod: string): Array<{ title: string; items: Shortcut[] }> {\n return [\n {\n title: 'Navigation',\n items: [\n { keys: [mod, '1'], action: 'Chat' },\n { keys: [mod, '2'], action: 'Autonomy' },\n { keys: [mod, '3'], action: 'Approvals' },\n { keys: [mod, '4'], action: 'Usage' },\n { keys: [mod, '5'], action: 'Settings' },\n { keys: [mod, 'K'], action: 'Quick switcher' },\n { keys: [mod, ','], action: 'Settings' },\n ],\n },\n {\n title: 'Chat',\n items: [\n { keys: [mod, 'N'], action: 'New chat' },\n { keys: ['Enter'], action: 'Send message' },\n { keys: ['Shift', 'Enter'], action: 'New line' },\n { keys: ['Esc'], action: 'Stop dictation / close overlay' },\n ],\n },\n ];\n}\n\nexport function ShortcutsPanel() {\n const mod = isApplePlatform() ? '⌘' : 'Ctrl';\n return (\n <Panel title=\"Keyboard\">\n <div className={styles.shortcuts}>\n {shortcutGroups(mod).flatMap((group) =>\n group.items.map((item) => (\n <div key={`${group.title}-${item.action}-${item.keys.join('+')}`} className={styles.shortcut}>\n <span>{item.action}</span>\n <span className={styles.keys}>\n {item.keys.map((key) => (\n <kbd key={key} className={styles.key}>\n {key}\n </kbd>\n ))}\n </span>\n </div>\n )),\n )}\n </div>\n </Panel>\n );\n}\n","/**\n * routes/verse/sections/SettingsSection.tsx — the Settings rail item\n * (VERSE-CONTRACT-V2, owner A). Named export, NO props: the shell\n * lazy-mounts it and it reads everything it needs from the stores.\n *\n * Four panels in one 720px reading column: Appearance (live, no save\n * button), Connection (server, authority state, how to get tokens back),\n * Keyboard, and About. Each row is label + description on the left, control\n * on the right — the same rhythm all the way down, so the page reads as one\n * object rather than four inventions.\n */\nimport { useAppearance } from '../../../data/hooks.js';\nimport { OnboardingPanel } from '../onboarding/OnboardingPanel.js';\nimport { AboutPanel } from './AboutPanel.js';\nimport { AppearancePanel } from './AppearancePanel.js';\nimport { ConnectionPanel } from './ConnectionPanel.js';\nimport { ShortcutsPanel } from './ShortcutsPanel.js';\nimport styles from './SettingsSection.module.css';\n\nexport function SettingsSection() {\n const { appearance, set, reset } = useAppearance();\n\n return (\n <div className={styles.section}>\n <header className={styles.strip} data-app-region=\"drag\">\n <h2 className={styles.stripTitle}>Settings</h2>\n </header>\n <div className={styles.scroll}>\n <div className={styles.column}>\n <AppearancePanel appearance={appearance} onChange={set} onReset={reset} />\n <ConnectionPanel />\n <ShortcutsPanel />\n <OnboardingPanel />\n <AboutPanel />\n </div>\n </div>\n </div>\n );\n}\n"],"names":["Input","label","hint","error","size","mono","prefix","className","id","rest","generatedId","useId","inputId","hintId","errorId","describedBy","jsxs","styles","jsx","Segmented","options","value","onChange","block","aria","groupRef","useRef","move","delta","enabled","o","current","next","option","selected","e","Slider","min","max","valueLabel","valueText","trackImage","sliderId","span","percent","Switch","checked","disabled","control","Panel","title","action","children","SettingRow","description","htmlFor","labelId","stacked","text","Fragment","describe","completedAt","dismissedAt","OnboardingPanel","open","useOnboarding","Button","replayOnboarding","APP_VERSION","version","APP_NAME","AboutPanel","Tag","IconExternalLink","HEX_RE","FN_RE","clamp","unitValue","raw","scale","hslToRgb","h","s","l","hue","c","x","m","rgb","splitTopLevel","parts","depth","ch","p","colorWithPercent","lead","parseColorMix","body","args","first","second","c1","parseColor","c2","p1","p2","total","w1","w2","alpha","channel","k","input","hex","expand","fn","name","sat","light","flatten","color","backdrop","a","relativeLuminance","v","contrastRatio","foreground","background","bgRaw","fgRaw","base","bg","fg","l1","l2","hi","lo","accentHex","lightnessOffset","n","LIGHT_SURFACE","DARK_SURFACE","DARK_L_SHIFT","LINK_STEP","THEME_OPTIONS","IconMonitor","IconSun","IconMoon","DENSITY_OPTIONS","FONT_OPTIONS","RADIUS_OPTIONS","hueTrack","accentReadability","lightLink","darkLink","lightRatio","darkRatio","failing","AppearancePanel","appearance","onReset","accentLabelId","hueId","satId","lightId","motionId","preset","matchingAccentPreset","readability","isDefaultAppearance","theme","ACCENT_PRESETS","IconCheck","ACCENT_LIGHTNESS_RANGE","IconAlert","density","displayFont","radius","reduceMotion","StatusBadge","Meter","formatHoldExpiry","heldUntil","minutes","ConnectionPanel","phase","useAuthPhase","hold","useMutationHold","toast","useToast","confirmOpen","setConfirmOpen","useState","cancelRef","origin","copyOrigin","disconnect","clearReadSession","IconCopy","IconLock","clearMutationToken","IconInfo","Dialog","isApplePlatform","source","shortcutGroups","mod","ShortcutsPanel","group","item","key","SettingsSection","set","reset","useAppearance"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{j as s}from"./index-BkUlX2Se.js";const n="_grid_x7p2y_1",a="_card_x7p2y_10",c="_title_x7p2y_19",i="_stat_x7p2y_25",o="_caption_x7p2y_31",r="_line_x7p2y_37",d="_row_x7p2y_42",_="_cell_x7p2y_51",e={grid:n,card:a,title:c,stat:i,caption:o,line:r,row:d,cell:_};function y({width:t="100%"}){return s.jsx("div",{className:`skeleton ${e.line}`,style:{width:t}})}function x(){return s.jsxs("div",{className:e.card,children:[s.jsx("div",{className:`skeleton ${e.title}`}),s.jsx("div",{className:`skeleton ${e.stat}`}),s.jsx("div",{className:`skeleton ${e.caption}`})]})}function j(){return s.jsxs("div",{className:e.row,children:[s.jsx("div",{className:`skeleton ${e.cell}`,style:{width:"18%"}}),s.jsx("div",{className:`skeleton ${e.cell}`,style:{width:"38%"}}),s.jsx("div",{className:`skeleton ${e.cell}`,style:{width:"14%"}}),s.jsx("div",{className:`skeleton ${e.cell}`,style:{width:"10%"}})]})}function k({count:t=4}){return s.jsx("div",{className:e.grid,children:Array.from({length:t},(m,l)=>s.jsx(x,{},l))})}export{y as S,k as a,j as b};
2
- //# sourceMappingURL=Skeleton-4qq4HuJO.js.map
1
+ import{j as s}from"./index-CpgkRaTi.js";const n="_grid_x7p2y_1",a="_card_x7p2y_10",c="_title_x7p2y_19",i="_stat_x7p2y_25",o="_caption_x7p2y_31",r="_line_x7p2y_37",d="_row_x7p2y_42",_="_cell_x7p2y_51",e={grid:n,card:a,title:c,stat:i,caption:o,line:r,row:d,cell:_};function y({width:t="100%"}){return s.jsx("div",{className:`skeleton ${e.line}`,style:{width:t}})}function x(){return s.jsxs("div",{className:e.card,children:[s.jsx("div",{className:`skeleton ${e.title}`}),s.jsx("div",{className:`skeleton ${e.stat}`}),s.jsx("div",{className:`skeleton ${e.caption}`})]})}function j(){return s.jsxs("div",{className:e.row,children:[s.jsx("div",{className:`skeleton ${e.cell}`,style:{width:"18%"}}),s.jsx("div",{className:`skeleton ${e.cell}`,style:{width:"38%"}}),s.jsx("div",{className:`skeleton ${e.cell}`,style:{width:"14%"}}),s.jsx("div",{className:`skeleton ${e.cell}`,style:{width:"10%"}})]})}function k({count:t=4}){return s.jsx("div",{className:e.grid,children:Array.from({length:t},(m,l)=>s.jsx(x,{},l))})}export{y as S,k as a,j as b};
2
+ //# sourceMappingURL=Skeleton-YkcOpgFb.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Skeleton-4qq4HuJO.js","sources":["../../../../../../src/web-ui/components/primitives/Skeleton.tsx"],"sourcesContent":["/**\n * components/primitives/Skeleton.tsx — loading placeholders. Used ONLY for\n * `status === 'loading'` (no data at all yet). A resource that already has\n * data and is merely refreshing should show <RefreshIndicator/> instead —\n * never re-blank a populated view (see DESIGN.md \"no blank screens\").\n */\nimport styles from './Skeleton.module.css';\n\nexport function SkeletonLine({ width = '100%' }: { width?: string }) {\n return <div className={`skeleton ${styles.line}`} style={{ width }} />;\n}\n\nexport function SkeletonCard() {\n return (\n <div className={styles.card}>\n <div className={`skeleton ${styles.title}`} />\n <div className={`skeleton ${styles.stat}`} />\n <div className={`skeleton ${styles.caption}`} />\n </div>\n );\n}\n\nexport function SkeletonRow() {\n return (\n <div className={styles.row}>\n <div className={`skeleton ${styles.cell}`} style={{ width: '18%' }} />\n <div className={`skeleton ${styles.cell}`} style={{ width: '38%' }} />\n <div className={`skeleton ${styles.cell}`} style={{ width: '14%' }} />\n <div className={`skeleton ${styles.cell}`} style={{ width: '10%' }} />\n </div>\n );\n}\n\nexport function SkeletonCardGrid({ count = 4 }: { count?: number }) {\n return (\n <div className={styles.grid}>\n {Array.from({ length: count }, (_, i) => (\n <SkeletonCard key={i} />\n ))}\n </div>\n );\n}\n"],"names":["SkeletonLine","width","jsx","styles","SkeletonCard","jsxs","SkeletonRow","SkeletonCardGrid","count","_","i"],"mappings":"uQAQO,SAASA,EAAa,CAAE,MAAAC,EAAQ,QAA8B,CACnE,OAAOC,MAAC,MAAA,CAAI,UAAW,YAAYC,EAAO,IAAI,GAAI,MAAO,CAAE,MAAAF,CAAA,CAAM,CAAG,CACtE,CAEO,SAASG,GAAe,CAC7B,OACEC,EAAAA,KAAC,MAAA,CAAI,UAAWF,EAAO,KACrB,SAAA,CAAAD,MAAC,MAAA,CAAI,UAAW,YAAYC,EAAO,KAAK,GAAI,QAC3C,MAAA,CAAI,UAAW,YAAYA,EAAO,IAAI,GAAI,QAC1C,MAAA,CAAI,UAAW,YAAYA,EAAO,OAAO,EAAA,CAAI,CAAA,EAChD,CAEJ,CAEO,SAASG,GAAc,CAC5B,OACED,EAAAA,KAAC,MAAA,CAAI,UAAWF,EAAO,IACrB,SAAA,CAAAD,EAAAA,IAAC,MAAA,CAAI,UAAW,YAAYC,EAAO,IAAI,GAAI,MAAO,CAAE,MAAO,KAAA,CAAM,CAAG,EACpED,EAAAA,IAAC,MAAA,CAAI,UAAW,YAAYC,EAAO,IAAI,GAAI,MAAO,CAAE,MAAO,KAAA,CAAM,CAAG,EACpED,EAAAA,IAAC,MAAA,CAAI,UAAW,YAAYC,EAAO,IAAI,GAAI,MAAO,CAAE,MAAO,KAAA,CAAM,CAAG,EACpED,EAAAA,IAAC,MAAA,CAAI,UAAW,YAAYC,EAAO,IAAI,GAAI,MAAO,CAAE,MAAO,KAAA,CAAM,CAAG,CAAA,EACtE,CAEJ,CAEO,SAASI,EAAiB,CAAE,MAAAC,EAAQ,GAAyB,CAClE,aACG,MAAA,CAAI,UAAWL,EAAO,KACpB,SAAA,MAAM,KAAK,CAAE,OAAQK,CAAA,EAAS,CAACC,EAAGC,UAChCN,EAAA,CAAA,EAAkBM,CAAG,CACvB,EACH,CAEJ"}
1
+ {"version":3,"file":"Skeleton-YkcOpgFb.js","sources":["../../../../../../src/web-ui/components/primitives/Skeleton.tsx"],"sourcesContent":["/**\n * components/primitives/Skeleton.tsx — loading placeholders. Used ONLY for\n * `status === 'loading'` (no data at all yet). A resource that already has\n * data and is merely refreshing should show <RefreshIndicator/> instead —\n * never re-blank a populated view (see DESIGN.md \"no blank screens\").\n */\nimport styles from './Skeleton.module.css';\n\nexport function SkeletonLine({ width = '100%' }: { width?: string }) {\n return <div className={`skeleton ${styles.line}`} style={{ width }} />;\n}\n\nexport function SkeletonCard() {\n return (\n <div className={styles.card}>\n <div className={`skeleton ${styles.title}`} />\n <div className={`skeleton ${styles.stat}`} />\n <div className={`skeleton ${styles.caption}`} />\n </div>\n );\n}\n\nexport function SkeletonRow() {\n return (\n <div className={styles.row}>\n <div className={`skeleton ${styles.cell}`} style={{ width: '18%' }} />\n <div className={`skeleton ${styles.cell}`} style={{ width: '38%' }} />\n <div className={`skeleton ${styles.cell}`} style={{ width: '14%' }} />\n <div className={`skeleton ${styles.cell}`} style={{ width: '10%' }} />\n </div>\n );\n}\n\nexport function SkeletonCardGrid({ count = 4 }: { count?: number }) {\n return (\n <div className={styles.grid}>\n {Array.from({ length: count }, (_, i) => (\n <SkeletonCard key={i} />\n ))}\n </div>\n );\n}\n"],"names":["SkeletonLine","width","jsx","styles","SkeletonCard","jsxs","SkeletonRow","SkeletonCardGrid","count","_","i"],"mappings":"uQAQO,SAASA,EAAa,CAAE,MAAAC,EAAQ,QAA8B,CACnE,OAAOC,MAAC,MAAA,CAAI,UAAW,YAAYC,EAAO,IAAI,GAAI,MAAO,CAAE,MAAAF,CAAA,CAAM,CAAG,CACtE,CAEO,SAASG,GAAe,CAC7B,OACEC,EAAAA,KAAC,MAAA,CAAI,UAAWF,EAAO,KACrB,SAAA,CAAAD,MAAC,MAAA,CAAI,UAAW,YAAYC,EAAO,KAAK,GAAI,QAC3C,MAAA,CAAI,UAAW,YAAYA,EAAO,IAAI,GAAI,QAC1C,MAAA,CAAI,UAAW,YAAYA,EAAO,OAAO,EAAA,CAAI,CAAA,EAChD,CAEJ,CAEO,SAASG,GAAc,CAC5B,OACED,EAAAA,KAAC,MAAA,CAAI,UAAWF,EAAO,IACrB,SAAA,CAAAD,EAAAA,IAAC,MAAA,CAAI,UAAW,YAAYC,EAAO,IAAI,GAAI,MAAO,CAAE,MAAO,KAAA,CAAM,CAAG,EACpED,EAAAA,IAAC,MAAA,CAAI,UAAW,YAAYC,EAAO,IAAI,GAAI,MAAO,CAAE,MAAO,KAAA,CAAM,CAAG,EACpED,EAAAA,IAAC,MAAA,CAAI,UAAW,YAAYC,EAAO,IAAI,GAAI,MAAO,CAAE,MAAO,KAAA,CAAM,CAAG,EACpED,EAAAA,IAAC,MAAA,CAAI,UAAW,YAAYC,EAAO,IAAI,GAAI,MAAO,CAAE,MAAO,KAAA,CAAM,CAAG,CAAA,EACtE,CAEJ,CAEO,SAASI,EAAiB,CAAE,MAAAC,EAAQ,GAAyB,CAClE,aACG,MAAA,CAAI,UAAWL,EAAO,KACpB,SAAA,MAAM,KAAK,CAAE,OAAQK,CAAA,EAAS,CAACC,EAAGC,UAChCN,EAAA,CAAA,EAAkBM,CAAG,CACvB,EACH,CAEJ"}
@@ -1,2 +1,2 @@
1
- import{j as r}from"./index-BkUlX2Se.js";const u="_badge_ytqgz_4",c="_dot_ytqgz_17",o="_neutral_ytqgz_24",g="_info_ytqgz_32",d="_running_ytqgz_40",i="_pulse_ytqgz_1",_="_success_ytqgz_49",l="_warning_ytqgz_57",p="_danger_ytqgz_65",w="_unknown_ytqgz_73",y="_phaseDot_ytqgz_82",e={badge:u,dot:c,neutral:o,info:g,running:d,pulse:i,success:_,warning:l,danger:p,unknown:w,phaseDot:y},q={pending:"neutral",queued:"neutral",waiting:"neutral",running:"running",active:"running",in_progress:"running",building:"running",applying:"running",done:"success",success:"success",succeeded:"success",applied:"success",merged:"success",ready:"success",approved:"success",ship:"success",review:"warning",degraded:"warning",paused:"warning",noise:"neutral",failed:"danger",error:"danger",errored:"danger",rejected:"danger",harmful:"danger",cancelled:"neutral",canceled:"neutral",unknown:"unknown"};function h(n){return n?q[n.toLowerCase()]??"neutral":"unknown"}function f({status:n,tone:s,children:a}){const t=s??h(n);return r.jsxs("span",{className:`${e.badge} ${e[t]}`,children:[r.jsx("span",{className:e.dot,"aria-hidden":"true"}),a??n]})}function m({index:n}){const s=(n%6+6)%6;return r.jsx("span",{className:e.phaseDot,style:{background:`var(--phase-${s+1})`},"aria-hidden":"true"})}export{m as P,f as S,h as s};
2
- //# sourceMappingURL=StatusBadge-BbEdqEGn.js.map
1
+ import{j as r}from"./index-CpgkRaTi.js";const u="_badge_ytqgz_4",c="_dot_ytqgz_17",o="_neutral_ytqgz_24",g="_info_ytqgz_32",d="_running_ytqgz_40",i="_pulse_ytqgz_1",_="_success_ytqgz_49",l="_warning_ytqgz_57",p="_danger_ytqgz_65",w="_unknown_ytqgz_73",y="_phaseDot_ytqgz_82",e={badge:u,dot:c,neutral:o,info:g,running:d,pulse:i,success:_,warning:l,danger:p,unknown:w,phaseDot:y},q={pending:"neutral",queued:"neutral",waiting:"neutral",running:"running",active:"running",in_progress:"running",building:"running",applying:"running",done:"success",success:"success",succeeded:"success",applied:"success",merged:"success",ready:"success",approved:"success",ship:"success",review:"warning",degraded:"warning",paused:"warning",noise:"neutral",failed:"danger",error:"danger",errored:"danger",rejected:"danger",harmful:"danger",cancelled:"neutral",canceled:"neutral",unknown:"unknown"};function h(n){return n?q[n.toLowerCase()]??"neutral":"unknown"}function f({status:n,tone:s,children:a}){const t=s??h(n);return r.jsxs("span",{className:`${e.badge} ${e[t]}`,children:[r.jsx("span",{className:e.dot,"aria-hidden":"true"}),a??n]})}function m({index:n}){const s=(n%6+6)%6;return r.jsx("span",{className:e.phaseDot,style:{background:`var(--phase-${s+1})`},"aria-hidden":"true"})}export{m as P,f as S,h as s};
2
+ //# sourceMappingURL=StatusBadge-DJw0LSPg.js.map