pi-mega-compact 0.13.5 → 0.13.7
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.
- package/dist/extensions/dashboard-server/api-contracts/endpoints/registry.js +50 -0
- package/dist/extensions/dashboard-server/api-contracts/rag-metrics.js +1 -0
- package/dist/extensions/dashboard-server/api-contracts/rag-settings.js +3 -3
- package/dist/extensions/dashboard-server/api-contracts/wiki.js +1 -0
- package/dist/extensions/dashboard-server/index-reader.js +3 -1
- package/dist/extensions/dashboard-server/resolve-snapshot.js +81 -0
- package/dist/extensions/dashboard-server/routes-core.js +8 -3
- package/dist/extensions/dashboard-server/routes-rag-metrics.js +60 -0
- package/dist/extensions/dashboard-server/routes-rag-settings-helpers.js +167 -0
- package/dist/extensions/dashboard-server/routes-rag-settings.js +136 -77
- package/dist/extensions/dashboard-server/routes-repo.js +5 -1
- package/dist/extensions/dashboard-server/routes-sessions.js +6 -3
- package/dist/extensions/dashboard-server/routes-wiki-helpers.js +97 -0
- package/dist/extensions/dashboard-server/routes-wiki.js +330 -0
- package/dist/extensions/dashboard-server/routes.js +2 -0
- package/dist/extensions/dashboard-server/server.js +17 -3
- package/dist/extensions/mega-events/context-handler/afterCompact.js +35 -2
- package/dist/extensions/mega-pipeline/recall.js +31 -0
- package/dist/extensions/mega-runtime/capture-model.js +5 -2
- package/dist/extensions/mega-turn-store.js +2 -1
- package/dist/src/config/turns.js +10 -0
- package/dist/src/config.js +2 -0
- package/dist/src/pricing.js +8 -0
- package/dist/src/recall/async.js +10 -1
- package/dist/src/recall/format.js +10 -1
- package/dist/src/recall/hydeTelemetry.js +22 -0
- package/dist/src/recall/sync.js +28 -2
- package/dist/src/store/turns/hydeStore.js +32 -0
- package/dist/src/store/turns/index.js +1 -0
- package/dist/src/store/turns/schema.js +102 -1
- package/dist/src/store/turns/sqlite-store/rows.js +23 -0
- package/dist/src/store/turns/sqlite-store/write.js +7 -3
- package/dist/src/topics/durability.js +187 -0
- package/dist/src/topics/index.js +2 -1
- package/dist/src/topics/store.js +28 -9
- package/dist/src/wiki/curation-helpers.js +71 -0
- package/dist/src/wiki/curation.js +147 -0
- package/dist/src/wiki/incremental.js +126 -0
- package/dist/src/wiki/index.js +5 -0
- package/extensions/dashboard-client/dist/assets/AreaChart-j2VOSRp6.js +70 -0
- package/extensions/dashboard-client/dist/assets/{SessionsTab-C30AwyoF.js.map → AreaChart-j2VOSRp6.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/CacheTab-Dr1HeMfc.js +2 -0
- package/extensions/dashboard-client/dist/assets/CacheTab-Dr1HeMfc.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/EventsTab-DRG2k7FS.js +2 -0
- package/extensions/dashboard-client/dist/assets/EventsTab-DRG2k7FS.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/HealthTab-DGE9PpW3.js +2 -0
- package/extensions/dashboard-client/dist/assets/HealthTab-DGE9PpW3.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/MaintenanceTab-DeYRhF4q.js +2 -0
- package/extensions/dashboard-client/dist/assets/MaintenanceTab-DeYRhF4q.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/MemoryMapTab-DSnSO3nG.js +2 -0
- package/extensions/dashboard-client/dist/assets/MemoryMapTab-DSnSO3nG.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/MetricsTab-RIzNc1Uj.js +2 -0
- package/extensions/dashboard-client/dist/assets/MetricsTab-RIzNc1Uj.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/OverviewTab-_1BJ4Bmh.js +2 -0
- package/extensions/dashboard-client/dist/assets/OverviewTab-_1BJ4Bmh.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/ReposTab-DkU7ywZB.js +2 -0
- package/extensions/dashboard-client/dist/assets/ReposTab-DkU7ywZB.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/SessionsTab-Bq_F_aOk.js +2 -0
- package/extensions/dashboard-client/dist/assets/SessionsTab-Bq_F_aOk.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/SetupTab-BkBD2Y97.js +2 -0
- package/extensions/dashboard-client/dist/assets/SetupTab-BkBD2Y97.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/TimeSavedCard-BXzFKU7C.js +2 -0
- package/extensions/dashboard-client/dist/assets/TimeSavedCard-BXzFKU7C.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/TurnsTab-Bjpp3vBH.js +5 -0
- package/extensions/dashboard-client/dist/assets/TurnsTab-Bjpp3vBH.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/WikiTab-dBN2EA5G.js +2 -0
- package/extensions/dashboard-client/dist/assets/WikiTab-dBN2EA5G.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/button-Bt0b5QVp.js +2 -0
- package/extensions/dashboard-client/dist/assets/button-Bt0b5QVp.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/card-D5CafXtg.js +2 -0
- package/extensions/dashboard-client/dist/assets/card-D5CafXtg.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/index-CUA6EDRF.css +1 -0
- package/extensions/dashboard-client/dist/assets/index-GPHRnEN7.js +137 -0
- package/extensions/dashboard-client/dist/assets/index-GPHRnEN7.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/pricing-DkYp8-vi.js +2 -0
- package/extensions/dashboard-client/dist/assets/pricing-DkYp8-vi.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/switch-CY5Gwj1o.js +2 -0
- package/extensions/dashboard-client/dist/assets/switch-CY5Gwj1o.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/toggle-C9HpkIfH.js +2 -0
- package/extensions/dashboard-client/dist/assets/toggle-C9HpkIfH.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/{useSSE-p1pOI_-P.js → useSSE-2JFrLDlE.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{useSSE-p1pOI_-P.js.map → useSSE-2JFrLDlE.js.map} +1 -1
- package/extensions/dashboard-client/dist/index.html +2 -2
- package/extensions/dashboard-client/package-lock.json +1995 -191
- package/extensions/dashboard-client/package.json +12 -1
- package/extensions/dashboard-client/postcss.config.js +6 -0
- package/extensions/dashboard-client/src/App.tsx +127 -88
- package/extensions/dashboard-client/src/api/client.ts +109 -10
- package/extensions/dashboard-client/src/components/ActiveReposTable.tsx +15 -7
- package/extensions/dashboard-client/src/components/ActiveSessionsTable.tsx +67 -55
- package/extensions/dashboard-client/src/components/CacheHitRateTrendCard.tsx +17 -13
- package/extensions/dashboard-client/src/components/CacheHitsCard.tsx +35 -30
- package/extensions/dashboard-client/src/components/CacheStatusPerModel.tsx +33 -28
- package/extensions/dashboard-client/src/components/EventCategoryFilter.tsx +5 -6
- package/extensions/dashboard-client/src/components/EventStream.tsx +17 -13
- package/extensions/dashboard-client/src/components/HydeDetailPanel.tsx +173 -0
- package/extensions/dashboard-client/src/components/LegendCard.tsx +16 -9
- package/extensions/dashboard-client/src/components/PerfCards.tsx +28 -20
- package/extensions/dashboard-client/src/components/PerfChart.tsx +9 -6
- package/extensions/dashboard-client/src/components/ProviderCacheCard.tsx +15 -7
- package/extensions/dashboard-client/src/components/RagDashboard.tsx +253 -0
- package/extensions/dashboard-client/src/components/RepoAllSessionsCard.tsx +15 -10
- package/extensions/dashboard-client/src/components/RepoContextStack.tsx +24 -16
- package/extensions/dashboard-client/src/components/RepoDetailModal.tsx +52 -49
- package/extensions/dashboard-client/src/components/RepoTable.tsx +26 -17
- package/extensions/dashboard-client/src/components/SessionContextGauges.tsx +11 -14
- package/extensions/dashboard-client/src/components/SessionInfo.tsx +20 -15
- package/extensions/dashboard-client/src/components/SessionsMemoryChart.tsx +8 -5
- package/extensions/dashboard-client/src/components/SummaryTiles.tsx +26 -17
- package/extensions/dashboard-client/src/components/TabBar.tsx +1 -3
- package/extensions/dashboard-client/src/components/layout/AppShell.tsx +42 -0
- package/extensions/dashboard-client/src/components/layout/BottomBar.tsx +88 -0
- package/extensions/dashboard-client/src/components/layout/Sidebar.tsx +83 -0
- package/extensions/dashboard-client/src/components/ui/badge.tsx +30 -0
- package/extensions/dashboard-client/src/components/ui/button.tsx +44 -0
- package/extensions/dashboard-client/src/components/ui/card.tsx +32 -0
- package/extensions/dashboard-client/src/components/ui/select.tsx +64 -0
- package/extensions/dashboard-client/src/components/ui/switch.tsx +26 -0
- package/extensions/dashboard-client/src/components/ui/tabs.tsx +36 -0
- package/extensions/dashboard-client/src/components/ui/toggle.tsx +28 -0
- package/extensions/dashboard-client/src/components/ui/tooltip.tsx +27 -0
- package/extensions/dashboard-client/src/config.ts +10 -0
- package/extensions/dashboard-client/src/main.tsx +2 -2
- package/extensions/dashboard-client/src/memory-map-layout.ts +1 -2
- package/extensions/dashboard-client/src/styles/index.css +79 -0
- package/extensions/dashboard-client/src/tabs/CacheTab.tsx +33 -26
- package/extensions/dashboard-client/src/tabs/EventsTab.tsx +22 -7
- package/extensions/dashboard-client/src/tabs/HealthTab.tsx +77 -46
- package/extensions/dashboard-client/src/tabs/MaintenanceTab/ActionsCard.tsx +60 -50
- package/extensions/dashboard-client/src/tabs/MaintenanceTab/DbStatsCard.tsx +61 -35
- package/extensions/dashboard-client/src/tabs/MaintenanceTab/DebugBundleCard.tsx +34 -23
- package/extensions/dashboard-client/src/tabs/MaintenanceTab/HealthMitigationCard.tsx +62 -43
- package/extensions/dashboard-client/src/tabs/MaintenanceTab/SchemaHealthCard.tsx +53 -32
- package/extensions/dashboard-client/src/tabs/MaintenanceTab.tsx +2 -2
- package/extensions/dashboard-client/src/tabs/MemoryMapTab/MemoryMapView.tsx +29 -46
- package/extensions/dashboard-client/src/tabs/MemoryMapTab/RaptorTreeView.tsx +10 -34
- package/extensions/dashboard-client/src/tabs/MemoryMapTab.tsx +14 -34
- package/extensions/dashboard-client/src/tabs/MetricsTab.tsx +5 -2
- package/extensions/dashboard-client/src/tabs/OverviewTab.tsx +11 -5
- package/extensions/dashboard-client/src/tabs/ReposTab.tsx +5 -5
- package/extensions/dashboard-client/src/tabs/SessionsTab.tsx +47 -33
- package/extensions/dashboard-client/src/tabs/SetupTab/EmbedderSetup.tsx +6 -2
- package/extensions/dashboard-client/src/tabs/SetupTab/RagHealthCard.tsx +78 -0
- package/extensions/dashboard-client/src/tabs/SetupTab/SettingsPanel.tsx +198 -0
- package/extensions/dashboard-client/src/tabs/SetupTab/SettingsSection.tsx +50 -0
- package/extensions/dashboard-client/src/tabs/SetupTab.tsx +21 -59
- package/extensions/dashboard-client/src/tabs/TopicsTab.tsx +75 -40
- package/extensions/dashboard-client/src/tabs/TurnsTab.tsx +150 -112
- package/extensions/dashboard-client/src/tabs/WikiTab/TopicEvolutionGraph.tsx +274 -0
- package/extensions/dashboard-client/src/tabs/WikiTab/TopicEvolutionView.tsx +71 -0
- package/extensions/dashboard-client/src/tabs/WikiTab/TopicTimeline.tsx +103 -0
- package/extensions/dashboard-client/src/tabs/WikiTab/WikiPage.tsx +213 -0
- package/extensions/dashboard-client/src/tabs/WikiTab/WikiPageControls.tsx +188 -0
- package/extensions/dashboard-client/src/tabs/WikiTab.tsx +222 -0
- package/extensions/dashboard-client/src/tabs/registry.ts +57 -0
- package/extensions/dashboard-client/src/utils/cn.ts +7 -0
- package/extensions/dashboard-client/tailwind.config.js +46 -0
- package/extensions/dashboard-server/api-contracts/core.ts +59 -0
- package/extensions/dashboard-server/api-contracts/endpoints/registry.ts +79 -0
- package/extensions/dashboard-server/api-contracts/index.ts +48 -2
- package/extensions/dashboard-server/api-contracts/rag-metrics.ts +22 -0
- package/extensions/dashboard-server/api-contracts/rag-settings.ts +30 -20
- package/extensions/dashboard-server/api-contracts/wiki.ts +138 -0
- package/extensions/dashboard-server/index-reader.ts +3 -1
- package/extensions/dashboard-server/resolve-snapshot.ts +98 -0
- package/extensions/dashboard-server/routes-core.ts +8 -3
- package/extensions/dashboard-server/routes-rag-metrics.ts +82 -0
- package/extensions/dashboard-server/routes-rag-settings-helpers.ts +314 -0
- package/extensions/dashboard-server/routes-rag-settings.ts +147 -97
- package/extensions/dashboard-server/routes-repo.ts +5 -1
- package/extensions/dashboard-server/routes-sessions.ts +6 -3
- package/extensions/dashboard-server/routes-wiki-helpers.ts +126 -0
- package/extensions/dashboard-server/routes-wiki.ts +376 -0
- package/extensions/dashboard-server/routes.ts +2 -0
- package/extensions/dashboard-server/server.ts +18 -2
- package/extensions/mega-events/context-handler/afterCompact.ts +44 -1
- package/extensions/mega-pipeline/recall.ts +31 -0
- package/extensions/mega-runtime/capture-model.ts +5 -2
- package/extensions/mega-turn-store.ts +13 -0
- package/package.json +1 -1
- package/src/config/turns.ts +17 -0
- package/src/config.ts +3 -0
- package/src/pricing.ts +8 -0
- package/src/recall/async.ts +10 -1
- package/src/recall/format.ts +15 -2
- package/src/recall/hydeTelemetry.ts +44 -0
- package/src/recall/sync.ts +34 -2
- package/src/recall/types.ts +36 -0
- package/src/store/turns/hydeStore.ts +82 -0
- package/src/store/turns/index.ts +4 -0
- package/src/store/turns/schema.ts +126 -1
- package/src/store/turns/sqlite-store/rows.ts +25 -0
- package/src/store/turns/sqlite-store/write.ts +20 -2
- package/src/store/turns/types.ts +33 -0
- package/src/topics/durability.ts +231 -0
- package/src/topics/index.ts +7 -1
- package/src/topics/store.ts +35 -9
- package/src/wiki/curation-helpers.ts +140 -0
- package/src/wiki/curation.ts +217 -0
- package/src/wiki/incremental.ts +164 -0
- package/src/wiki/index.ts +13 -0
- package/extensions/dashboard-client/dist/assets/CacheTab-Cqnc7lMg.js +0 -2
- package/extensions/dashboard-client/dist/assets/CacheTab-Cqnc7lMg.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/EventsTab-tYk3VFAp.js +0 -2
- package/extensions/dashboard-client/dist/assets/EventsTab-tYk3VFAp.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/HealthTab-D2_kjgxw.js +0 -2
- package/extensions/dashboard-client/dist/assets/HealthTab-D2_kjgxw.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/MaintenanceTab-Bc-uPYrz.js +0 -2
- package/extensions/dashboard-client/dist/assets/MaintenanceTab-Bc-uPYrz.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/MemoryMapTab-D1V9g_NC.js +0 -2
- package/extensions/dashboard-client/dist/assets/MemoryMapTab-D1V9g_NC.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/MetricsTab-DT_XfL96.js +0 -2
- package/extensions/dashboard-client/dist/assets/MetricsTab-DT_XfL96.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/OverviewTab-BY6KZCme.js +0 -2
- package/extensions/dashboard-client/dist/assets/OverviewTab-BY6KZCme.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/ReposTab-CeS-tpDM.js +0 -2
- package/extensions/dashboard-client/dist/assets/ReposTab-CeS-tpDM.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/SessionsTab-C30AwyoF.js +0 -70
- package/extensions/dashboard-client/dist/assets/SetupTab-BJUHOVK2.js +0 -2
- package/extensions/dashboard-client/dist/assets/SetupTab-BJUHOVK2.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/TimeSavedCard-p55K1tFP.js +0 -2
- package/extensions/dashboard-client/dist/assets/TimeSavedCard-p55K1tFP.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/TopicsTab-D8FqyAbK.js +0 -2
- package/extensions/dashboard-client/dist/assets/TopicsTab-D8FqyAbK.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/TurnsTab-ju-nXDys.js +0 -2
- package/extensions/dashboard-client/dist/assets/TurnsTab-ju-nXDys.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/index-BEj1Zahy.js +0 -42
- package/extensions/dashboard-client/dist/assets/index-BEj1Zahy.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/index-CUNn22iV.css +0 -1
- package/extensions/dashboard-client/dist/assets/pricing-CvE4NllQ.js +0 -2
- package/extensions/dashboard-client/dist/assets/pricing-CvE4NllQ.js.map +0 -1
- package/extensions/dashboard-client/src/styles/metrics-extra.css +0 -69
- package/extensions/dashboard-client/src/styles/turns.css +0 -142
- package/extensions/dashboard-client/src/tabs/SetupTab/RagSettingsCard.tsx +0 -160
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{r as c,j as e,A as H,D as K,E as U,u as w,F as Y,G as Q,H as z,B as y,I as X}from"./index-GPHRnEN7.js";import{B as v}from"./button-Bt0b5QVp.js";import{T as A}from"./toggle-C9HpkIfH.js";import{C as N,c as k}from"./card-D5CafXtg.js";import{u as J}from"./useSSE-2JFrLDlE.js";function Z(t,o){const m=t.length>14?t.slice(0,14)+"…":t;return o?`${m} (${o})`:m}function ee({topicId:t,others:o,members:m,onMutated:i}){const[n,a]=c.useState(null),[d,h]=c.useState(""),[l,u]=c.useState(""),[r,s]=c.useState([]),[p,b]=c.useState(!1),[g,f]=c.useState(null);function j(x){a(x),f(null),h(""),u(""),s([])}async function q(){b(!0),f(null);try{if(n==="rename")await H(t,d);else if(n==="merge"){if(!l){f("Pick a target topic."),b(!1);return}await K(t,l)}else if(n==="split"){if(r.length===0){f("Pick at least one memory."),b(!1);return}await U(t,r)}a(null),i()}catch(x){f(x instanceof Error?x.message:String(x))}finally{b(!1)}}return e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"flex gap-2",children:[e.jsx(v,{variant:"outline",size:"sm",onClick:()=>j("rename"),children:"Rename"}),e.jsx(v,{variant:"outline",size:"sm",onClick:()=>j("merge"),children:"Merge into…"}),e.jsx(v,{variant:"outline",size:"sm",onClick:()=>j("split"),children:"Split"})]}),n&&e.jsx("div",{className:"fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4",onClick:()=>a(null),children:e.jsxs("div",{className:"w-full max-w-md rounded-lg border border-border bg-bg-card p-5 shadow-xl",role:"dialog","aria-modal":"true","aria-label":n,onClick:x=>x.stopPropagation(),children:[e.jsx("h3",{className:"mb-3 font-heading text-base font-semibold text-foreground",children:n==="rename"?"Rename topic":n==="merge"?"Merge into…":"Split topic"}),n==="rename"&&e.jsx("input",{type:"text",value:d,placeholder:"New label (empty = back to auto)","aria-label":"New topic label",autoFocus:!0,onChange:x=>h(x.target.value),className:"w-full rounded-md border border-border bg-bg-elevated/50 px-3 py-2 text-sm outline-none transition-colors focus:border-primary"}),n==="merge"&&e.jsxs("select",{value:l,"aria-label":"Target topic",onChange:x=>u(x.target.value),className:"w-full rounded-md border border-border bg-bg-elevated/50 px-3 py-2 text-sm outline-none transition-colors focus:border-primary",children:[e.jsx("option",{value:"",children:"Pick a target topic…"}),o.map(x=>e.jsx("option",{value:x.id,children:x.label},x.id))]}),n==="split"&&e.jsx("div",{className:"max-h-56 overflow-auto rounded-md border border-border/60",children:m.map(x=>e.jsxs("label",{className:"flex cursor-pointer items-center gap-2 border-b border-border/40 px-3 py-2 text-sm last:border-0 hover:bg-bg-elevated/40",children:[e.jsx("input",{type:"checkbox",checked:r.includes(x.memoryId),onChange:G=>{s(I=>G.target.checked?[...I,x.memoryId]:I.filter(V=>V!==x.memoryId))},className:"accent-primary"}),e.jsx("span",{className:"font-mono text-xs text-muted-foreground",children:Z(x.memoryId,x.method)})]},x.memoryId))}),g&&e.jsx("p",{className:"mt-3 text-sm text-danger",children:g}),e.jsxs("div",{className:"mt-4 flex justify-end gap-2",children:[e.jsx(v,{variant:"ghost",size:"sm",onClick:()=>a(null),children:"Cancel"}),e.jsx(v,{size:"sm",onClick:q,disabled:p,children:p?"…":"Confirm"})]})]})})]})}const L=720,M=56,T=10,R=3;function C(t){return t?new Date(t).toLocaleDateString():"—"}function te({topicId:t}){const{data:o,error:m}=w(c.useCallback(()=>Y(t),[t]),{});if(m)return e.jsx("div",{className:"rounded-lg border border-border bg-bg-card p-4 text-sm text-muted-foreground",children:"Timeline unavailable."});if(!o)return e.jsx("div",{className:"rounded-lg border border-border bg-bg-card p-4 text-sm text-muted-foreground",children:"Loading timeline…"});const{buckets:i,total:n}=o,a=Math.max(...i.map(l=>l.count),1),d=i.length*(T+R),h=Math.min(1,(L-24)/Math.max(d,1));return e.jsxs("div",{className:"rounded-lg border border-border bg-bg-card p-4",children:[e.jsxs("h3",{className:"mb-2 font-heading text-sm font-semibold text-muted-foreground",children:["Memory timeline"," ",e.jsxs("span",{className:"font-normal text-xs",children:["(",n," memory",n!==1?"ies":"y"," · daily buckets)"]})]}),i.length===0?e.jsx("p",{className:"text-sm text-muted-foreground",children:"No timeline data yet."}):e.jsxs(e.Fragment,{children:[e.jsx("svg",{width:"100%",height:M,viewBox:`0 0 ${Math.max(L,d*h)} ${M}`,role:"img","aria-label":"Memory additions over time",children:i.map((l,u)=>{const r=u*(T+R)*h,s=Math.max(3,l.count/a*(M-20));return e.jsx("rect",{x:r,y:M-6-s,width:Math.max(2,T*h),height:s,rx:2,fill:"hsl(var(--primary))",opacity:.85,children:e.jsx("title",{children:`${C(l.bucket)}: ${l.count}`})},`${l.bucket}-${u}`)})}),e.jsxs("p",{className:"mt-1 text-xs text-muted-foreground",children:["First display: ",C(i[0].bucket)," · last:",C(i[i.length-1].bucket)]})]})]})}function B(t){return t?new Date(t).toLocaleString():"—"}const re={"kmeans+tfidf":"kmeans",merge:"merge",split:"split",manual:"manual"};function se({topicId:t,onBack:o}){const[m,i]=c.useState(0),n=c.useCallback(()=>i(s=>s+1),[]),{data:a,error:d,loading:h}=w(c.useCallback(()=>Q(t),[t,m]),{}),{data:l}=w(c.useCallback(()=>z(),[]),{}),u=c.useMemo(()=>{const s=new Map;for(const p of l?.topics??[])s.set(p.id,p.label);return s},[l]);if(d&&!a)return e.jsxs("div",{className:"rounded-lg border border-border bg-bg-card p-6 text-sm text-danger",children:["Error loading topic: ",d.message]});if(h&&!a)return e.jsx("div",{className:"rounded-lg border border-border bg-bg-card p-6 text-sm text-muted-foreground",children:"Loading topic…"});if(!a)return e.jsx("div",{className:"rounded-lg border border-border bg-bg-card p-6 text-sm text-muted-foreground",children:"No topic data available."});const r=(l?.topics??[]).filter(s=>s.id!==t).map(s=>({id:s.id,label:s.label}));return e.jsxs("div",{className:"flex flex-col gap-4",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(v,{variant:"outline",size:"sm",onClick:o,children:"← Wiki"}),e.jsx("h2",{className:"font-heading text-lg font-semibold",children:a.topic.label}),a.topic.edited&&e.jsx(y,{variant:"outline",children:"edited"}),e.jsxs(y,{variant:"default",children:[a.provenance.length," memories"]})]}),e.jsx(ee,{topicId:t,others:r,members:a.provenance,onMutated:n})]}),a.summary&&e.jsx(N,{children:e.jsxs(k,{children:[e.jsx("h3",{className:"mb-1 font-heading text-sm font-semibold text-muted-foreground",children:"Summary"}),e.jsx("p",{className:"text-sm leading-relaxed text-foreground/90",children:a.summary})]})}),a.keyMemories.length>0&&e.jsx(N,{children:e.jsxs(k,{children:[e.jsx("h3",{className:"mb-2 font-heading text-sm font-semibold text-muted-foreground",children:"Key memories"}),e.jsx("ul",{className:"flex flex-col gap-2",children:a.keyMemories.map(s=>e.jsxs("li",{className:"rounded-md border border-border/60 bg-bg-elevated/40 p-3 text-sm",children:[e.jsx("p",{className:"line-clamp-3 text-foreground/90",children:s.content}),e.jsxs("p",{className:"mt-1 text-xs text-muted-foreground",children:[s.memoryId," · ",B(s.timestamp)]})]},s.memoryId))})]})}),e.jsx(te,{topicId:t}),a.provenance.length>0&&e.jsx(N,{children:e.jsxs(k,{children:[e.jsx("h3",{className:"mb-2 font-heading text-sm font-semibold text-muted-foreground",children:"Provenance"}),e.jsx("div",{className:"max-h-72 overflow-auto rounded-md border border-border/60",children:e.jsxs("table",{className:"w-full text-sm",children:[e.jsx("thead",{className:"sticky top-0 bg-bg-card",children:e.jsxs("tr",{className:"border-b border-border text-left text-xs uppercase text-muted-foreground",children:[e.jsx("th",{className:"px-3 py-2 font-medium",children:"Memory"}),e.jsx("th",{className:"px-3 py-2 font-medium",children:"Session"}),e.jsx("th",{className:"px-3 py-2 font-medium",children:"Assigned"}),e.jsx("th",{className:"px-3 py-2 font-medium",children:"Method"})]})}),e.jsx("tbody",{children:a.provenance.map(s=>e.jsxs("tr",{className:"border-b border-border/40 last:border-0",children:[e.jsx("td",{className:"px-3 py-1.5 font-mono text-xs",children:s.memoryId}),e.jsx("td",{className:"px-3 py-1.5 text-xs text-muted-foreground",children:s.sessionId||"unknown"}),e.jsx("td",{className:"px-3 py-1.5 text-xs text-muted-foreground",children:B(s.assignedAt)}),e.jsx("td",{className:"px-3 py-1.5",children:e.jsx(y,{variant:"outline",children:re[s.method]??s.method})})]},s.memoryId))})]})})]})}),a.relatedTopicIds.length>0&&e.jsx(N,{children:e.jsxs(k,{children:[e.jsx("h3",{className:"mb-2 font-heading text-sm font-semibold text-muted-foreground",children:"Related topics"}),e.jsx("div",{className:"flex flex-wrap gap-2",children:a.relatedTopicIds.map(s=>e.jsx(y,{variant:"accent",children:u.get(s)??s},s))})]})})]})}const O=900,E=560,F=6e4,D=.012,W=.012,$=.8,S=2,ne=.02,oe=250;function ae(t){return t==="merge"?"#f59e0b":"#22c55e"}function le(t){return t.map((o,m)=>{const i=2*Math.PI*m/Math.max(t.length,1);return{id:o.id,label:o.label,memoryCount:o.memoryCount,pos:{x:Math.cos(i)*220+O/2,y:Math.sin(i)*220+E/2},vx:0,vy:0}})}function ie(t){const{nodes:o,edges:m}=t;for(let i=0;i<o.length;i++){const n=o[i];let a=0,d=0;for(let l=0;l<o.length;l++){if(i===l)continue;const u=n.pos.x-o[l].pos.x,r=n.pos.y-o[l].pos.y,s=u*u+r*r||1,p=Math.sqrt(s);a+=u/p*(F/s),d+=r/p*(F/s)}for(const l of m){let u;if(l.source===i)u=l.target;else if(l.target===i)u=l.source;else continue;const r=o[u].pos.x-n.pos.x,s=o[u].pos.y-n.pos.y;a+=r*D,d+=s*D}a-=n.pos.x*W,d-=n.pos.y*W,n.vx=(n.vx+a)*$,n.vy=(n.vy+d)*$;const h=Math.sqrt(n.vx*n.vx+n.vy*n.vy);h>S&&(n.vx=n.vx/h*S,n.vy=n.vy/h*S),h>ne&&(n.pos.x+=n.vx,n.pos.y+=n.vy)}}function de({data:t}){const o=c.useRef(null),m=c.useRef(0),[,i]=c.useState(0),[n,a]=c.useState(0);c.useEffect(()=>{const r=le(t.nodes),s=new Map(r.map((g,f)=>[g.id,f])),p=t.edges.map(g=>{const f=s.get(g.source),j=s.get(g.target);return f===void 0||j===void 0||f===j?null:{source:f,target:j,kind:g.kind}}).filter(g=>g!==null),b=new Map;for(const g of t.edges)b.set(g.source,Math.max(b.get(g.source)??0,g.at)),b.set(g.target,Math.max(b.get(g.target)??0,g.at));return o.current={nodes:r,edges:p,timeByActivity:b},i(1),()=>cancelAnimationFrame(m.current)},[t]),c.useEffect(()=>{if(!o.current)return;let r=0;const s=()=>{!o.current||r>=oe||(ie(o.current),r++,i(r),m.current=requestAnimationFrame(s))};return m.current=requestAnimationFrame(s),()=>cancelAnimationFrame(m.current)},[t]);const d=o.current,h=Math.max(t.buckets.length-1,0),l=c.useMemo(()=>{if(t.buckets.length===0)return null;const r=Math.min(n,t.buckets.length-1);return t.buckets[r].bucket},[n,t.buckets]);if(!d||t.nodes.length===0)return e.jsx("div",{className:"rounded-lg border border-border bg-bg-card p-6 text-sm text-muted-foreground",children:"No evolution data yet. Merge or split topics to see connections, then check back after a rebuild."});const u=l==null||!d.timeByActivity?null:new Set([...d.timeByActivity.entries()].filter(([,r])=>r<=l).map(([r])=>r));return e.jsxs("div",{className:"flex flex-col gap-3",children:[t.buckets.length>1&&e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("input",{type:"range",min:0,max:h,value:n,onChange:r=>a(Number(r.target.value)),className:"w-full accent-primary","aria-label":"Scrub through topic activity time"}),e.jsx("span",{className:"whitespace-nowrap text-xs text-muted-foreground",children:l?new Date(l).toLocaleDateString():"all"})]}),e.jsxs("svg",{width:"100%",height:E,viewBox:`0 0 ${O} ${E}`,role:"img","aria-label":"Topic evolution graph",className:"rounded-lg border border-border/60 bg-bg-card",children:[d.edges.map((r,s)=>{const p=d.nodes[r.source],b=d.nodes[r.target];return e.jsx("line",{x1:p.pos.x,y1:p.pos.y,x2:b.pos.x,y2:b.pos.y,stroke:ae(r.kind),strokeWidth:1.5,strokeDasharray:r.kind==="split"?"4 3":void 0,opacity:.5},`edge-${s}`)}),d.nodes.map((r,s)=>{const p=u==null||u.size===0||u.has(r.id),b=Math.min(32,8+r.memoryCount*3);return e.jsxs("g",{opacity:p?1:.15,children:[e.jsx("circle",{cx:r.pos.x,cy:r.pos.y,r:b,fill:"hsl(var(--primary) / 0.18)",stroke:"hsl(var(--primary))",strokeWidth:1.5}),e.jsx("text",{x:r.pos.x,y:r.pos.y+4,textAnchor:"middle",fontSize:"10px",fill:"hsl(var(--foreground))",className:"pointer-events-none",children:r.label.length>16?r.label.slice(0,15)+"…":r.label})]},`node-${s}`)})]}),e.jsxs("div",{className:"flex items-center gap-4 text-xs text-muted-foreground",children:[e.jsxs("span",{className:"flex items-center gap-1.5",children:[e.jsx("span",{className:"inline-block h-0.5 w-6 bg-amber-500"})," merge"]}),e.jsxs("span",{className:"flex items-center gap-1.5",children:[e.jsx("span",{className:"inline-block h-0.5 w-6 border-t border-dashed border-green-500"}),"split"]}),e.jsxs("span",{children:[t.nodes.length," nodes · ",t.edges.length," curation events"]})]})]})}function ce(t){return t.type==="wiki_rebuilt"}function me(){const{data:t,error:o,loading:m,refetch:i}=w(c.useCallback(()=>X(),[]),{pollInterval:6e4}),{events:n}=J(),a=c.useMemo(()=>{const d=n.filter(ce);return d.length===0?null:d[d.length-1].ts},[n]);return c.useEffect(()=>{a!=null&&i()},[a,i]),o&&!t?e.jsxs("div",{className:"rounded-lg border border-border bg-bg-card p-6 text-sm text-danger",children:["Error loading evolution graph: ",o.message]}):m&&!t?e.jsx("div",{className:"rounded-lg border border-border bg-bg-card p-6 text-sm text-muted-foreground",children:"Loading evolution graph…"}):e.jsx(N,{children:e.jsxs(k,{children:[e.jsx("h3",{className:"mb-2 font-heading text-sm font-semibold text-muted-foreground",children:"Topic evolution"}),t?e.jsx(de,{data:t}):e.jsx("p",{className:"text-sm text-muted-foreground",children:"No data yet."})]})})}const ue={label:"accent",merge:"warning",split:"default"};function _(t){return t?new Date(t).toLocaleString():"—"}function P({view:t,onChange:o}){return e.jsxs("div",{className:"flex gap-1",children:[e.jsx(A,{pressed:t==="list",onClick:()=>o("list"),children:"Topics"}),e.jsx(A,{pressed:t==="evolution",onClick:()=>o("evolution"),children:"Evolution"})]})}function xe({entry:t,onOpen:o}){return e.jsxs("tr",{className:"border-b border-border/60 last:border-0 hover:bg-bg-elevated/40",children:[e.jsx("td",{className:"py-2 pr-3",children:e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:"font-medium text-foreground",children:t.label}),t.edited&&e.jsx(y,{variant:"outline",children:"edited"})]})}),e.jsx("td",{className:"py-2 pr-3 text-sm text-muted-foreground",children:t.memoryCount}),e.jsx("td",{className:"py-2 pr-3",children:e.jsx("div",{className:"flex flex-wrap gap-1",children:t.overrideKinds.map(m=>e.jsx(y,{variant:ue[m]??"default",children:m},m))})}),e.jsx("td",{className:"py-2 pr-3 text-xs text-muted-foreground",children:_(t.lastUpdated)}),e.jsx("td",{className:"py-2 text-right",children:e.jsx(v,{variant:"outline",size:"sm",onClick:()=>o(t.id),children:"Open"})})]})}function je(){const{data:t,loading:o,error:m}=w(c.useCallback(()=>z(),[]),{pollInterval:3e4}),[i,n]=c.useState("list"),[a,d]=c.useState(""),[h,l]=c.useState(null),u=c.useMemo(()=>{if(!t)return[];const r=a.trim().toLowerCase();return r?t.topics.filter(s=>s.label.toLowerCase().includes(r)):t.topics},[t,a]);return h?e.jsx(se,{topicId:h,onBack:()=>l(null)}):i==="evolution"?e.jsxs("div",{className:"flex flex-col gap-3",children:[e.jsx(P,{view:i,onChange:n}),e.jsx(me,{})]}):m&&!t?e.jsxs("div",{className:"rounded-lg border border-border bg-bg-card p-6 text-sm text-danger",children:["Error loading wiki: ",m.message]}):o&&!t?e.jsx("div",{className:"rounded-lg border border-border bg-bg-card p-6 text-sm text-muted-foreground",children:"Loading wiki…"}):t?t.totalTopics===0?e.jsxs("div",{className:"rounded-lg border border-border bg-bg-card p-6 text-sm text-muted-foreground",children:[e.jsx("h3",{className:"mb-2 font-heading text-base text-foreground",children:"Wiki"}),e.jsx("p",{children:"No topics yet. Topics are auto-generated after every Nth compaction from real memory embeddings (k-means + TF-IDF)."}),e.jsx("p",{className:"mt-2",children:"Check back after a few more compaction cycles."})]}):e.jsxs("div",{className:"flex flex-col gap-4",children:[e.jsxs("div",{className:"flex flex-wrap items-end justify-between gap-2",children:[e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx(P,{view:i,onChange:n}),e.jsxs("div",{children:[e.jsx("h2",{className:"font-heading text-lg font-semibold",children:"Wiki"}),e.jsxs("p",{className:"text-sm text-muted-foreground",children:[t.totalTopics," topic",t.totalTopics!==1?"s":""," ·"," ",t.totalMemories," assigned memori",t.totalMemories!==1?"es":"y",t.lastRebuildAt!=null&&e.jsxs(e.Fragment,{children:[" · last rebuild ",_(t.lastRebuildAt)]})]})]})]}),e.jsx("input",{type:"search",placeholder:"Filter topics by label…","aria-label":"Filter topics by label",value:a,onChange:r=>d(r.target.value),className:"w-64 rounded-md border border-border bg-bg-elevated/50 px-3 py-2 text-sm outline-none transition-colors focus:border-primary"})]}),e.jsx("div",{className:"overflow-x-auto rounded-lg border border-border bg-bg-card",children:e.jsxs("table",{className:"w-full table-fixed text-sm",children:[e.jsx("thead",{children:e.jsxs("tr",{className:"border-b border-border text-left text-xs uppercase text-muted-foreground",children:[e.jsx("th",{className:"w-1/3 px-4 py-2 font-medium",children:"Label"}),e.jsx("th",{className:"w-16 py-2 font-medium",children:"Memories"}),e.jsx("th",{className:"w-40 py-2 font-medium",children:"Badges"}),e.jsx("th",{className:"w-40 py-2 font-medium",children:"Last updated"}),e.jsx("th",{className:"w-20 py-2"})]})}),e.jsxs("tbody",{children:[u.map(r=>e.jsx(xe,{entry:r,onOpen:l},r.id)),u.length===0&&e.jsx("tr",{children:e.jsxs("td",{colSpan:5,className:"px-4 py-6 text-center text-muted-foreground",children:['No topics match "',a,'".']})})]})]})})]}):e.jsx("div",{className:"rounded-lg border border-border bg-bg-card p-6 text-sm text-muted-foreground",children:"No wiki data available."})}export{je as default};
|
|
2
|
+
//# sourceMappingURL=WikiTab-dBN2EA5G.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WikiTab-dBN2EA5G.js","sources":["../../src/tabs/WikiTab/WikiPageControls.tsx","../../src/tabs/WikiTab/TopicTimeline.tsx","../../src/tabs/WikiTab/WikiPage.tsx","../../src/tabs/WikiTab/TopicEvolutionGraph.tsx","../../src/tabs/WikiTab/TopicEvolutionView.tsx","../../src/tabs/WikiTab.tsx"],"sourcesContent":["/**\n * dashboard-client/src/tabs/WikiTab/WikiPageControls.tsx — rename/merge/split.\n *\n * Controlled dialogs for the three curation mutations. Non-destructive: on\n * success the parent refetches and paints the returned CurationResult; on\n * failure the pre-mutation snapshot stays (no local partial apply).\n *\n * Styling: Tailwind + shadcn (Button). No legacy CSS classes.\n */\n\nimport type React from \"react\";\nimport { useState } from \"react\";\nimport { renameTopic, mergeTopics, splitTopic } from \"../../api/client\";\nimport type { MemoryProvenance } from \"@contracts\";\nimport { Button } from \"../../components/ui/button\";\n\ninterface ControlsProps {\n\ttopicId: string;\n\tothers: Array<{ id: string; label: string }>;\n\tmembers: MemoryProvenance[];\n\tonMutated: () => void;\n}\n\ntype Mode = \"rename\" | \"merge\" | \"split\" | null;\n\nfunction memberSnippet(id: string, method: string): string {\n\tconst base = id.length > 14 ? id.slice(0, 14) + \"…\" : id;\n\treturn method ? `${base} (${method})` : base;\n}\n\nexport default function WikiPageControls({\n\ttopicId,\n\tothers,\n\tmembers,\n\tonMutated,\n}: ControlsProps): React.ReactElement {\n\tconst [mode, setMode] = useState<Mode>(null);\n\tconst [label, setLabel] = useState(\"\");\n\tconst [target, setTarget] = useState(\"\");\n\tconst [picked, setPicked] = useState<string[]>([]);\n\tconst [busy, setBusy] = useState(false);\n\tconst [error, setError] = useState<string | null>(null);\n\n\tfunction open(m: Exclude<Mode, null>): void {\n\t\tsetMode(m);\n\t\tsetError(null);\n\t\tsetLabel(\"\");\n\t\tsetTarget(\"\");\n\t\tsetPicked([]);\n\t}\n\n\tasync function submit(): Promise<void> {\n\t\tsetBusy(true);\n\t\tsetError(null);\n\t\ttry {\n\t\t\tif (mode === \"rename\") {\n\t\t\t\tawait renameTopic(topicId, label);\n\t\t\t} else if (mode === \"merge\") {\n\t\t\t\tif (!target) {\n\t\t\t\t\tsetError(\"Pick a target topic.\");\n\t\t\t\t\tsetBusy(false);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tawait mergeTopics(topicId, target);\n\t\t\t} else if (mode === \"split\") {\n\t\t\t\tif (picked.length === 0) {\n\t\t\t\t\tsetError(\"Pick at least one memory.\");\n\t\t\t\t\tsetBusy(false);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tawait splitTopic(topicId, picked);\n\t\t\t}\n\t\t\tsetMode(null);\n\t\t\tonMutated();\n\t\t} catch (e) {\n\t\t\tsetError(e instanceof Error ? e.message : String(e));\n\t\t} finally {\n\t\t\tsetBusy(false);\n\t\t}\n\t}\n\n\treturn (\n\t\t<>\n\t\t\t<div className=\"flex gap-2\">\n\t\t\t\t<Button variant=\"outline\" size=\"sm\" onClick={() => open(\"rename\")}>\n\t\t\t\t\tRename\n\t\t\t\t</Button>\n\t\t\t\t<Button variant=\"outline\" size=\"sm\" onClick={() => open(\"merge\")}>\n\t\t\t\t\tMerge into…\n\t\t\t\t</Button>\n\t\t\t\t<Button variant=\"outline\" size=\"sm\" onClick={() => open(\"split\")}>\n\t\t\t\t\tSplit\n\t\t\t\t</Button>\n\t\t\t</div>\n\n\t\t\t{mode && (\n\t\t\t\t<div\n\t\t\t\t\tclassName=\"fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4\"\n\t\t\t\t\tonClick={() => setMode(null)}\n\t\t\t\t>\n\t\t\t\t\t<div\n\t\t\t\t\t\tclassName=\"w-full max-w-md rounded-lg border border-border bg-bg-card p-5 shadow-xl\"\n\t\t\t\t\t\trole=\"dialog\"\n\t\t\t\t\t\taria-modal=\"true\"\n\t\t\t\t\t\taria-label={mode}\n\t\t\t\t\t\tonClick={(e) => e.stopPropagation()}\n\t\t\t\t\t>\n\t\t\t\t\t\t<h3 className=\"mb-3 font-heading text-base font-semibold text-foreground\">\n\t\t\t\t\t\t\t{mode === \"rename\"\n\t\t\t\t\t\t\t\t? \"Rename topic\"\n\t\t\t\t\t\t\t\t: mode === \"merge\"\n\t\t\t\t\t\t\t\t\t? \"Merge into…\"\n\t\t\t\t\t\t\t\t\t: \"Split topic\"}\n\t\t\t\t\t\t</h3>\n\n\t\t\t\t\t\t{mode === \"rename\" && (\n\t\t\t\t\t\t\t<input\n\t\t\t\t\t\t\t\ttype=\"text\"\n\t\t\t\t\t\t\t\tvalue={label}\n\t\t\t\t\t\t\t\tplaceholder=\"New label (empty = back to auto)\"\n\t\t\t\t\t\t\t\taria-label=\"New topic label\"\n\t\t\t\t\t\t\t\tautoFocus\n\t\t\t\t\t\t\t\tonChange={(e) => setLabel(e.target.value)}\n\t\t\t\t\t\t\t\tclassName=\"w-full rounded-md border border-border bg-bg-elevated/50 px-3 py-2 text-sm outline-none transition-colors focus:border-primary\"\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t)}\n\n\t\t\t\t\t\t{mode === \"merge\" && (\n\t\t\t\t\t\t\t<select\n\t\t\t\t\t\t\t\tvalue={target}\n\t\t\t\t\t\t\t\taria-label=\"Target topic\"\n\t\t\t\t\t\t\t\tonChange={(e) => setTarget(e.target.value)}\n\t\t\t\t\t\t\t\tclassName=\"w-full rounded-md border border-border bg-bg-elevated/50 px-3 py-2 text-sm outline-none transition-colors focus:border-primary\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<option value=\"\">Pick a target topic…</option>\n\t\t\t\t\t\t\t\t{others.map((o) => (\n\t\t\t\t\t\t\t\t\t<option key={o.id} value={o.id}>\n\t\t\t\t\t\t\t\t\t\t{o.label}\n\t\t\t\t\t\t\t\t\t</option>\n\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t</select>\n\t\t\t\t\t\t)}\n\n\t\t\t\t\t\t{mode === \"split\" && (\n\t\t\t\t\t\t\t<div className=\"max-h-56 overflow-auto rounded-md border border-border/60\">\n\t\t\t\t\t\t\t\t{members.map((m) => (\n\t\t\t\t\t\t\t\t\t<label\n\t\t\t\t\t\t\t\t\t\tkey={m.memoryId}\n\t\t\t\t\t\t\t\t\t\tclassName=\"flex cursor-pointer items-center gap-2 border-b border-border/40 px-3 py-2 text-sm last:border-0 hover:bg-bg-elevated/40\"\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t<input\n\t\t\t\t\t\t\t\t\t\t\ttype=\"checkbox\"\n\t\t\t\t\t\t\t\t\t\t\tchecked={picked.includes(m.memoryId)}\n\t\t\t\t\t\t\t\t\t\t\tonChange={(e) => {\n\t\t\t\t\t\t\t\t\t\t\t\tsetPicked((prev) =>\n\t\t\t\t\t\t\t\t\t\t\t\t\te.target.checked\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t? [...prev, m.memoryId]\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t: prev.filter((x) => x !== m.memoryId),\n\t\t\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t\tclassName=\"accent-primary\"\n\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t<span className=\"font-mono text-xs text-muted-foreground\">\n\t\t\t\t\t\t\t\t\t\t\t{memberSnippet(m.memoryId, m.method)}\n\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t</label>\n\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t)}\n\n\t\t\t\t\t\t{error && (\n\t\t\t\t\t\t\t<p className=\"mt-3 text-sm text-danger\">{error}</p>\n\t\t\t\t\t\t)}\n\n\t\t\t\t\t\t<div className=\"mt-4 flex justify-end gap-2\">\n\t\t\t\t\t\t\t<Button variant=\"ghost\" size=\"sm\" onClick={() => setMode(null)}>\n\t\t\t\t\t\t\t\tCancel\n\t\t\t\t\t\t\t</Button>\n\t\t\t\t\t\t\t<Button size=\"sm\" onClick={submit} disabled={busy}>\n\t\t\t\t\t\t\t\t{busy ? \"…\" : \"Confirm\"}\n\t\t\t\t\t\t\t</Button>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t)}\n\t\t</>\n\t);\n}\n","/**\n * dashboard-client/src/tabs/WikiTab/TopicTimeline.tsx — per-topic timeline.\n *\n * Renders topic memory-addition buckets as a lightweight SVG bar strip (no\n * chart library needed). X = time bucket, bar height = memories added.\n * Fetches GET /api/wiki/topic/:topicId/timeline.\n *\n * Styling: Tailwind + shadcn (Card). No legacy CSS classes.\n */\n\nimport type React from \"react\";\nimport { useCallback } from \"react\";\nimport { useApi } from \"../../hooks/useApi\";\nimport { fetchTopicTimeline } from \"../../api/client\";\nimport type { TopicTimelineResponse } from \"@contracts\";\n\nconst W = 720;\nconst H = 56;\nconst BAR_W = 10;\nconst GAP = 3;\n\ninterface Props {\n\ttopicId: string;\n}\n\nfunction fmtBucket(ts: number): string {\n\tif (!ts) return \"—\";\n\treturn new Date(ts).toLocaleDateString();\n}\n\nexport default function TopicTimeline({ topicId }: Props): React.ReactElement {\n\tconst { data, error } = useApi<TopicTimelineResponse>(\n\t\tuseCallback(() => fetchTopicTimeline(topicId), [topicId]),\n\t\t{},\n\t);\n\n\tif (error) {\n\t\treturn (\n\t\t\t<div className=\"rounded-lg border border-border bg-bg-card p-4 text-sm text-muted-foreground\">\n\t\t\t\tTimeline unavailable.\n\t\t\t</div>\n\t\t);\n\t}\n\tif (!data) {\n\t\treturn (\n\t\t\t<div className=\"rounded-lg border border-border bg-bg-card p-4 text-sm text-muted-foreground\">\n\t\t\t\tLoading timeline…\n\t\t\t</div>\n\t\t);\n\t}\n\n\tconst { buckets, total } = data;\n\tconst max = Math.max(...buckets.map((b) => b.count), 1);\n\tconst totalWidth = buckets.length * (BAR_W + GAP);\n\tconst scale = Math.min(1, (W - 24) / Math.max(totalWidth, 1));\n\n\treturn (\n\t\t<div className=\"rounded-lg border border-border bg-bg-card p-4\">\n\t\t\t<h3 className=\"mb-2 font-heading text-sm font-semibold text-muted-foreground\">\n\t\t\t\tMemory timeline{\" \"}\n\t\t\t\t<span className=\"font-normal text-xs\">\n\t\t\t\t\t({total} memory{total !== 1 ? \"ies\" : \"y\"} · daily buckets)\n\t\t\t\t</span>\n\t\t\t</h3>\n\t\t\t{buckets.length === 0 ? (\n\t\t\t\t<p className=\"text-sm text-muted-foreground\">No timeline data yet.</p>\n\t\t\t) : (\n\t\t\t\t<>\n\t\t\t\t\t<svg\n\t\t\t\t\t\twidth=\"100%\"\n\t\t\t\t\t\theight={H}\n\t\t\t\t\t\tviewBox={`0 0 ${Math.max(W, totalWidth * scale)} ${H}`}\n\t\t\t\t\t\trole=\"img\"\n\t\t\t\t\t\taria-label=\"Memory additions over time\"\n\t\t\t\t\t>\n\t\t\t\t\t\t{buckets.map((b, i) => {\n\t\t\t\t\t\t\tconst x = i * (BAR_W + GAP) * scale;\n\t\t\t\t\t\t\tconst h = Math.max(3, (b.count / max) * (H - 20));\n\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t<rect\n\t\t\t\t\t\t\t\t\tkey={`${b.bucket}-${i}`}\n\t\t\t\t\t\t\t\t\tx={x}\n\t\t\t\t\t\t\t\t\ty={H - 6 - h}\n\t\t\t\t\t\t\t\t\twidth={Math.max(2, BAR_W * scale)}\n\t\t\t\t\t\t\t\t\theight={h}\n\t\t\t\t\t\t\t\t\trx={2}\n\t\t\t\t\t\t\t\t\tfill=\"hsl(var(--primary))\"\n\t\t\t\t\t\t\t\t\topacity={0.85}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<title>{`${fmtBucket(b.bucket)}: ${b.count}`}</title>\n\t\t\t\t\t\t\t\t</rect>\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t})}\n\t\t\t\t\t</svg>\n\t\t\t\t\t<p className=\"mt-1 text-xs text-muted-foreground\">\n\t\t\t\t\t\tFirst display: {fmtBucket(buckets[0].bucket)} · last:\n\t\t\t\t\t\t{fmtBucket(buckets[buckets.length - 1].bucket)}\n\t\t\t\t\t</p>\n\t\t\t\t</>\n\t\t\t)}\n\t\t</div>\n\t);\n}\n","/**\n * dashboard-client/src/tabs/WikiTab/WikiPage.tsx — single wiki topic page.\n *\n * Renders the extractive summary, key member memories, the member provenance\n * table (memory → session/assigned-at/method), related topics (resolved from\n * the wiki index), and the per-topic memory timeline. Mutations\n * (rename/merge/split) delegate to WikiPageControls; on mutation success the\n * page + index are refetched.\n *\n * Styling: Tailwind + shadcn (Card, Badge, Button) — no legacy CSS.\n */\n\nimport type React from \"react\";\nimport { useCallback, useMemo, useState } from \"react\";\nimport { useApi } from \"../../hooks/useApi\";\nimport { fetchWikiTopic, fetchWikiIndex } from \"../../api/client\";\nimport type { WikiPageResponse, WikiIndexResponse } from \"@contracts\";\nimport { Badge } from \"../../components/ui/badge\";\nimport { Button } from \"../../components/ui/button\";\nimport { Card, CardContent } from \"../../components/ui/card\";\nimport WikiPageControls from \"./WikiPageControls\";\nimport TopicTimeline from \"./TopicTimeline\";\n\ninterface WikiPageProps {\n\ttopicId: string;\n\tonBack: () => void;\n}\n\nfunction fmtTs(ms: number): string {\n\tif (!ms) return \"—\";\n\treturn new Date(ms).toLocaleString();\n}\n\nconst METHOD_LABELS: Record<string, string> = {\n\t\"kmeans+tfidf\": \"kmeans\",\n\tmerge: \"merge\",\n\tsplit: \"split\",\n\tmanual: \"manual\",\n};\n\nexport default function WikiPage({\n\ttopicId,\n\tonBack,\n}: WikiPageProps): React.ReactElement {\n\tconst [dirty, setDirty] = useState(0);\n\tconst bump = useCallback(() => setDirty((d) => d + 1), []);\n\n\tconst { data: page, error, loading } = useApi<WikiPageResponse>(\n\t\tuseCallback(() => fetchWikiTopic(topicId), [topicId, dirty]),\n\t\t{},\n\t);\n\tconst { data: index } = useApi<WikiIndexResponse>(\n\t\tuseCallback(() => fetchWikiIndex(), []),\n\t\t{},\n\t);\n\n\tconst labelOf = useMemo(() => {\n\t\tconst map = new Map<string, string>();\n\t\tfor (const t of index?.topics ?? []) map.set(t.id, t.label);\n\t\treturn map;\n\t}, [index]);\n\n\tif (error && !page) {\n\t\treturn (\n\t\t\t<div className=\"rounded-lg border border-border bg-bg-card p-6 text-sm text-danger\">\n\t\t\t\tError loading topic: {error.message}\n\t\t\t</div>\n\t\t);\n\t}\n\tif (loading && !page) {\n\t\treturn (\n\t\t\t<div className=\"rounded-lg border border-border bg-bg-card p-6 text-sm text-muted-foreground\">\n\t\t\t\tLoading topic…\n\t\t\t</div>\n\t\t);\n\t}\n\tif (!page) {\n\t\treturn (\n\t\t\t<div className=\"rounded-lg border border-border bg-bg-card p-6 text-sm text-muted-foreground\">\n\t\t\t\tNo topic data available.\n\t\t\t</div>\n\t\t);\n\t}\n\n\tconst otherTopics = (index?.topics ?? [])\n\t\t.filter((t) => t.id !== topicId)\n\t\t.map((t) => ({ id: t.id, label: t.label }));\n\n\treturn (\n\t\t<div className=\"flex flex-col gap-4\">\n\t\t\t<div className=\"flex items-center justify-between\">\n\t\t\t\t<div className=\"flex items-center gap-2\">\n\t\t\t\t\t<Button variant=\"outline\" size=\"sm\" onClick={onBack}>\n\t\t\t\t\t\t← Wiki\n\t\t\t\t\t</Button>\n\t\t\t\t\t<h2 className=\"font-heading text-lg font-semibold\">\n\t\t\t\t\t\t{page.topic.label}\n\t\t\t\t\t</h2>\n\t\t\t\t\t{page.topic.edited && <Badge variant=\"outline\">edited</Badge>}\n\t\t\t\t\t<Badge variant=\"default\">\n\t\t\t\t\t\t{page.provenance.length} memories\n\t\t\t\t\t</Badge>\n\t\t\t\t</div>\n\t\t\t\t<WikiPageControls\n\t\t\t\t\ttopicId={topicId}\n\t\t\t\t\tothers={otherTopics}\n\t\t\t\t\tmembers={page.provenance}\n\t\t\t\t\tonMutated={bump}\n\t\t\t\t/>\n\t\t\t</div>\n\n\t\t\t{page.summary && (\n\t\t\t\t<Card>\n\t\t\t\t\t<CardContent>\n\t\t\t\t\t\t<h3 className=\"mb-1 font-heading text-sm font-semibold text-muted-foreground\">\n\t\t\t\t\t\t\tSummary\n\t\t\t\t\t\t</h3>\n\t\t\t\t\t\t<p className=\"text-sm leading-relaxed text-foreground/90\">\n\t\t\t\t\t\t\t{page.summary}\n\t\t\t\t\t\t</p>\n\t\t\t\t\t</CardContent>\n\t\t\t\t</Card>\n\t\t\t)}\n\n\t\t\t{page.keyMemories.length > 0 && (\n\t\t\t\t<Card>\n\t\t\t\t\t<CardContent>\n\t\t\t\t\t\t<h3 className=\"mb-2 font-heading text-sm font-semibold text-muted-foreground\">\n\t\t\t\t\t\t\tKey memories\n\t\t\t\t\t\t</h3>\n\t\t\t\t\t\t<ul className=\"flex flex-col gap-2\">\n\t\t\t\t\t\t\t{page.keyMemories.map((m) => (\n\t\t\t\t\t\t\t\t<li\n\t\t\t\t\t\t\t\t\tkey={m.memoryId}\n\t\t\t\t\t\t\t\t\tclassName=\"rounded-md border border-border/60 bg-bg-elevated/40 p-3 text-sm\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<p className=\"line-clamp-3 text-foreground/90\">{m.content}</p>\n\t\t\t\t\t\t\t\t\t<p className=\"mt-1 text-xs text-muted-foreground\">\n\t\t\t\t\t\t\t\t\t\t{m.memoryId} · {fmtTs(m.timestamp)}\n\t\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t</ul>\n\t\t\t\t\t</CardContent>\n\t\t\t\t</Card>\n\t\t\t)}\n\n\t\t\t<TopicTimeline topicId={topicId} />\n\n\t\t\t{page.provenance.length > 0 && (\n\t\t\t\t<Card>\n\t\t\t\t\t<CardContent>\n\t\t\t\t\t\t<h3 className=\"mb-2 font-heading text-sm font-semibold text-muted-foreground\">\n\t\t\t\t\t\t\tProvenance\n\t\t\t\t\t\t</h3>\n\t\t\t\t\t\t<div className=\"max-h-72 overflow-auto rounded-md border border-border/60\">\n\t\t\t\t\t\t\t<table className=\"w-full text-sm\">\n\t\t\t\t\t\t\t\t<thead className=\"sticky top-0 bg-bg-card\">\n\t\t\t\t\t\t\t\t\t<tr className=\"border-b border-border text-left text-xs uppercase text-muted-foreground\">\n\t\t\t\t\t\t\t\t\t\t<th className=\"px-3 py-2 font-medium\">Memory</th>\n\t\t\t\t\t\t\t\t\t\t<th className=\"px-3 py-2 font-medium\">Session</th>\n\t\t\t\t\t\t\t\t\t\t<th className=\"px-3 py-2 font-medium\">Assigned</th>\n\t\t\t\t\t\t\t\t\t\t<th className=\"px-3 py-2 font-medium\">Method</th>\n\t\t\t\t\t\t\t\t\t</tr>\n\t\t\t\t\t\t\t\t</thead>\n\t\t\t\t\t\t\t\t<tbody>\n\t\t\t\t\t\t\t\t\t{page.provenance.map((p) => (\n\t\t\t\t\t\t\t\t\t\t<tr\n\t\t\t\t\t\t\t\t\t\t\tkey={p.memoryId}\n\t\t\t\t\t\t\t\t\t\t\tclassName=\"border-b border-border/40 last:border-0\"\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t<td className=\"px-3 py-1.5 font-mono text-xs\">\n\t\t\t\t\t\t\t\t\t\t\t\t{p.memoryId}\n\t\t\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t\t\t<td className=\"px-3 py-1.5 text-xs text-muted-foreground\">\n\t\t\t\t\t\t\t\t\t\t\t\t{p.sessionId || \"unknown\"}\n\t\t\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t\t\t<td className=\"px-3 py-1.5 text-xs text-muted-foreground\">\n\t\t\t\t\t\t\t\t\t\t\t\t{fmtTs(p.assignedAt)}\n\t\t\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t\t\t<td className=\"px-3 py-1.5\">\n\t\t\t\t\t\t\t\t\t\t\t\t<Badge variant=\"outline\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t{METHOD_LABELS[p.method] ?? p.method}\n\t\t\t\t\t\t\t\t\t\t\t\t</Badge>\n\t\t\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t\t</tr>\n\t\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t\t</tbody>\n\t\t\t\t\t\t\t</table>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</CardContent>\n\t\t\t\t</Card>\n\t\t\t)}\n\n\t\t\t{page.relatedTopicIds.length > 0 && (\n\t\t\t\t<Card>\n\t\t\t\t\t<CardContent>\n\t\t\t\t\t\t<h3 className=\"mb-2 font-heading text-sm font-semibold text-muted-foreground\">\n\t\t\t\t\t\t\tRelated topics\n\t\t\t\t\t\t</h3>\n\t\t\t\t\t\t<div className=\"flex flex-wrap gap-2\">\n\t\t\t\t\t\t\t{page.relatedTopicIds.map((id) => (\n\t\t\t\t\t\t\t\t<Badge key={id} variant=\"accent\">\n\t\t\t\t\t\t\t\t\t{labelOf.get(id) ?? id}\n\t\t\t\t\t\t\t\t</Badge>\n\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</CardContent>\n\t\t\t\t</Card>\n\t\t\t)}\n\t\t</div>\n\t);\n}\n","/**\n * dashboard-client/src/tabs/WikiTab/TopicEvolutionGraph.tsx — D3 evolution.\n *\n * Force-directed graph of wiki topics over time. Nodes are topics (radius scales\n * with memoryCount); edges are merge/split curation events. A bucket scrubber\n * (from the response buckets) dims nodes that had no activity up to the selected\n * time window — a lightweight \"growth over time\" view.\n *\n * Self-contained force simulation (Coulomb repulsion + Hooke attraction +\n * center gravity) — the codebase deliberately avoids external graph libraries\n * (see memory-map-layout.ts). No data is fabricated: only real node/edge/bucket\n * fields from the contract are used. Styling is Tailwind.\n */\n\nimport type React from \"react\";\nimport { useEffect, useMemo, useRef, useState } from \"react\";\nimport type { TopicEvolutionResponse } from \"@contracts\";\n\n// ── Simulation constants ────────────────────────────────────────────────\nconst W = 900;\nconst H = 560;\nconst REPULSION = 60_000;\nconst ATTRACTION = 0.012;\nconst CENTER_GRAVITY = 0.012;\nconst DAMPING = 0.8;\nconst SPEED_LIMIT = 2;\nconst MIN_VELOCITY = 0.02;\nconst MAX_ITERATIONS = 250;\n\ninterface SimNode {\n\tid: string;\n\tlabel: string;\n\tmemoryCount: number;\n\tpos: { x: number; y: number };\n\tvx: number;\n\tvy: number;\n}\n\ninterface SimEdge {\n\tsource: number;\n\ttarget: number;\n\tkind: \"merge\" | \"split\";\n}\n\nfunction edgeColor(kind: \"merge\" | \"split\"): string {\n\treturn kind === \"merge\" ? \"#f59e0b\" : \"#22c55e\"; // amber / green\n}\n\nfunction initialLayout(nodes: TopicEvolutionResponse[\"nodes\"]): SimNode[] {\n\treturn nodes.map((n, i) => {\n\t\tconst angle = (2 * Math.PI * i) / Math.max(nodes.length, 1);\n\t\treturn {\n\t\t\tid: n.id,\n\t\t\tlabel: n.label,\n\t\t\tmemoryCount: n.memoryCount,\n\t\t\tpos: { x: Math.cos(angle) * 220 + W / 2, y: Math.sin(angle) * 220 + H / 2 },\n\t\t\tvx: 0,\n\t\t\tvy: 0,\n\t\t};\n\t});\n}\n\nfunction applyForces(sim: { nodes: SimNode[]; edges: SimEdge[] }): void {\n\tconst { nodes, edges } = sim;\n\tfor (let i = 0; i < nodes.length; i++) {\n\t\tconst n = nodes[i];\n\t\tlet fx = 0;\n\t\tlet fy = 0;\n\t\tfor (let j = 0; j < nodes.length; j++) {\n\t\t\tif (i === j) continue;\n\t\t\tconst dx = n.pos.x - nodes[j].pos.x;\n\t\t\tconst dy = n.pos.y - nodes[j].pos.y;\n\t\t\tconst distSq = dx * dx + dy * dy || 1;\n\t\t\tconst dist = Math.sqrt(distSq);\n\t\t\tfx += (dx / dist) * (REPULSION / distSq);\n\t\t\tfy += (dy / dist) * (REPULSION / distSq);\n\t\t}\n\t\tfor (const e of edges) {\n\t\t\tlet other: number;\n\t\t\tif (e.source === i) other = e.target;\n\t\t\telse if (e.target === i) other = e.source;\n\t\t\telse continue;\n\t\t\tconst dx = nodes[other].pos.x - n.pos.x;\n\t\t\tconst dy = nodes[other].pos.y - n.pos.y;\n\t\t\tfx += dx * ATTRACTION;\n\t\t\tfy += dy * ATTRACTION;\n\t\t}\n\t\tfx -= n.pos.x * CENTER_GRAVITY;\n\t\tfy -= n.pos.y * CENTER_GRAVITY;\n\t\tn.vx = (n.vx + fx) * DAMPING;\n\t\tn.vy = (n.vy + fy) * DAMPING;\n\t\tconst speed = Math.sqrt(n.vx * n.vx + n.vy * n.vy);\n\t\tif (speed > SPEED_LIMIT) {\n\t\t\tn.vx = (n.vx / speed) * SPEED_LIMIT;\n\t\t\tn.vy = (n.vy / speed) * SPEED_LIMIT;\n\t\t}\n\t\tif (speed > MIN_VELOCITY) {\n\t\t\tn.pos.x += n.vx;\n\t\t\tn.pos.y += n.vy;\n\t\t}\n\t}\n}\n\ninterface Props {\n\tdata: TopicEvolutionResponse;\n}\n\nexport default function TopicEvolutionGraph({\n\tdata,\n}: Props): React.ReactElement {\n\tconst simRef = useRef<{\n\t\tnodes: SimNode[];\n\t\tedges: SimEdge[];\n\t\ttimeByActivity: Map<string, number> | null;\n\t} | null>(null);\n\tconst animRef = useRef(0);\n\tconst [, setFrame] = useState(0);\n\tconst [scrub, setScrub] = useState<number>(0);\n\n\t// Initialize simulation from data (re-run when data changes).\n\tuseEffect(() => {\n\t\tconst nodes = initialLayout(data.nodes);\n\t\tconst indexById = new Map(nodes.map((n, i) => [n.id, i]));\n\t\tconst edges: SimEdge[] = data.edges\n\t\t\t.map((e) => {\n\t\t\t\tconst si = indexById.get(e.source);\n\t\t\t\tconst ti = indexById.get(e.target);\n\t\t\t\tif (si === undefined || ti === undefined || si === ti) return null;\n\t\t\t\treturn { source: si, target: ti, kind: e.kind };\n\t\t\t})\n\t\t\t.filter((e): e is SimEdge => e !== null);\n\t\t// Latest activity per node (from merge/split edge timestamps).\n\t\tconst timeByActivity = new Map<string, number>();\n\t\tfor (const e of data.edges) {\n\t\t\ttimeByActivity.set(e.source, Math.max(timeByActivity.get(e.source) ?? 0, e.at));\n\t\t\ttimeByActivity.set(e.target, Math.max(timeByActivity.get(e.target) ?? 0, e.at));\n\t\t}\n\t\tsimRef.current = { nodes, edges, timeByActivity };\n\t\tsetFrame(1);\n\t\treturn () => cancelAnimationFrame(animRef.current);\n\t}, [data]);\n\n\t// Run the force simulation to stable layout.\n\tuseEffect(() => {\n\t\tif (!simRef.current) return;\n\t\tlet iter = 0;\n\t\tconst tick = () => {\n\t\t\tif (!simRef.current || iter >= MAX_ITERATIONS) return;\n\t\t\tapplyForces(simRef.current);\n\t\t\titer++;\n\t\t\tsetFrame(iter);\n\t\t\tanimRef.current = requestAnimationFrame(tick);\n\t\t};\n\t\tanimRef.current = requestAnimationFrame(tick);\n\t\treturn () => cancelAnimationFrame(animRef.current);\n\t}, [data]);\n\n\tconst sim = simRef.current;\n\n\tconst scrubMax = Math.max(data.buckets.length - 1, 0);\n\tconst scrubBucket = useMemo(() => {\n\t\tif (data.buckets.length === 0) return null;\n\t\tconst idx = Math.min(scrub, data.buckets.length - 1);\n\t\treturn data.buckets[idx].bucket;\n\t}, [scrub, data.buckets]);\n\n\tif (!sim || data.nodes.length === 0) {\n\t\treturn (\n\t\t\t<div className=\"rounded-lg border border-border bg-bg-card p-6 text-sm text-muted-foreground\">\n\t\t\t\tNo evolution data yet. Merge or split topics to see connections, then\n\t\t\t\tcheck back after a rebuild.\n\t\t\t</div>\n\t\t);\n\t}\n\n\tconst activeSet =\n\t\tscrubBucket == null || !sim.timeByActivity\n\t\t\t? null\n\t\t\t: new Set(\n\t\t\t\t\t[...sim.timeByActivity.entries()]\n\t\t\t\t\t\t.filter(([, t]) => t <= scrubBucket)\n\t\t\t\t\t\t.map(([id]) => id),\n\t\t\t\t);\n\n\treturn (\n\t\t<div className=\"flex flex-col gap-3\">\n\t\t\t{/* Scrubber */}\n\t\t\t{data.buckets.length > 1 && (\n\t\t\t\t<div className=\"flex items-center gap-3\">\n\t\t\t\t\t<input\n\t\t\t\t\t\ttype=\"range\"\n\t\t\t\t\t\tmin={0}\n\t\t\t\t\t\tmax={scrubMax}\n\t\t\t\t\t\tvalue={scrub}\n\t\t\t\t\t\tonChange={(e) => setScrub(Number(e.target.value))}\n\t\t\t\t\t\tclassName=\"w-full accent-primary\"\n\t\t\t\t\t\taria-label=\"Scrub through topic activity time\"\n\t\t\t\t\t/>\n\t\t\t\t\t<span className=\"whitespace-nowrap text-xs text-muted-foreground\">\n\t\t\t\t\t\t{scrubBucket ? new Date(scrubBucket).toLocaleDateString() : \"all\"}\n\t\t\t\t\t</span>\n\t\t\t\t</div>\n\t\t\t)}\n\n\t\t\t{/* SVG graph */}\n\t\t\t<svg\n\t\t\t\twidth=\"100%\"\n\t\t\t\theight={H}\n\t\t\t\tviewBox={`0 0 ${W} ${H}`}\n\t\t\t\trole=\"img\"\n\t\t\t\taria-label=\"Topic evolution graph\"\n\t\t\t\tclassName=\"rounded-lg border border-border/60 bg-bg-card\"\n\t\t\t>\n\t\t\t\t{sim.edges.map((e, i) => {\n\t\t\t\t\tconst a = sim.nodes[e.source];\n\t\t\t\t\tconst b = sim.nodes[e.target];\n\t\t\t\t\treturn (\n\t\t\t\t\t\t<line\n\t\t\t\t\t\t\tkey={`edge-${i}`}\n\t\t\t\t\t\t\tx1={a.pos.x}\n\t\t\t\t\t\t\ty1={a.pos.y}\n\t\t\t\t\t\t\tx2={b.pos.x}\n\t\t\t\t\t\t\ty2={b.pos.y}\n\t\t\t\t\t\t\tstroke={edgeColor(e.kind)}\n\t\t\t\t\t\t\tstrokeWidth={1.5}\n\t\t\t\t\t\t\tstrokeDasharray={e.kind === \"split\" ? \"4 3\" : undefined}\n\t\t\t\t\t\t\topacity={0.5}\n\t\t\t\t\t\t/>\n\t\t\t\t\t);\n\t\t\t\t})}\n\t\t\t\t{sim.nodes.map((n, i) => {\n\t\t\t\t\tconst active =\n\t\t\t\t\t\tactiveSet == null || activeSet.size === 0 || activeSet.has(n.id);\n\t\t\t\t\tconst r = Math.min(32, 8 + n.memoryCount * 3);\n\t\t\t\t\treturn (\n\t\t\t\t\t\t<g key={`node-${i}`} opacity={active ? 1 : 0.15}>\n\t\t\t\t\t\t\t<circle\n\t\t\t\t\t\t\t\tcx={n.pos.x}\n\t\t\t\t\t\t\t\tcy={n.pos.y}\n\t\t\t\t\t\t\t\tr={r}\n\t\t\t\t\t\t\t\tfill=\"hsl(var(--primary) / 0.18)\"\n\t\t\t\t\t\t\t\tstroke=\"hsl(var(--primary))\"\n\t\t\t\t\t\t\t\tstrokeWidth={1.5}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t<text\n\t\t\t\t\t\t\t\tx={n.pos.x}\n\t\t\t\t\t\t\t\ty={n.pos.y + 4}\n\t\t\t\t\t\t\t\ttextAnchor=\"middle\"\n\t\t\t\t\t\t\t\tfontSize=\"10px\"\n\t\t\t\t\t\t\t\tfill=\"hsl(var(--foreground))\"\n\t\t\t\t\t\t\t\tclassName=\"pointer-events-none\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{n.label.length > 16 ? n.label.slice(0, 15) + \"…\" : n.label}\n\t\t\t\t\t\t\t</text>\n\t\t\t\t\t\t</g>\n\t\t\t\t\t);\n\t\t\t\t})}\n\t\t\t</svg>\n\n\t\t\t<div className=\"flex items-center gap-4 text-xs text-muted-foreground\">\n\t\t\t\t<span className=\"flex items-center gap-1.5\">\n\t\t\t\t\t<span className=\"inline-block h-0.5 w-6 bg-amber-500\" /> merge\n\t\t\t\t</span>\n\t\t\t\t<span className=\"flex items-center gap-1.5\">\n\t\t\t\t\t<span className=\"inline-block h-0.5 w-6 border-t border-dashed border-green-500\" />\n\t\t\t\t\tsplit\n\t\t\t\t</span>\n\t\t\t\t<span>\n\t\t\t\t\t{data.nodes.length} nodes · {data.edges.length} curation events\n\t\t\t\t</span>\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n","/**\n * dashboard-client/src/tabs/WikiTab/TopicEvolutionView.tsx — planet evolution.\n *\n * Thin shell over TopicEvolutionGraph: fetches GET /api/wiki/evolution via\n * useApi and refetches when a `wiki_rebuilt` SSE event lands (emitted by the\n * extension after a topic-model rebuild), so the graph + scrubber stay live\n * between polls. No data is fabricated — only the contract fields are used.\n *\n * Styling: Tailwind + shadcn (Card). No legacy CSS classes.\n */\n\nimport type React from \"react\";\nimport { useCallback, useEffect, useMemo } from \"react\";\nimport { useApi } from \"../../hooks/useApi\";\nimport { useSSE } from \"../../hooks/useSSE\";\nimport { fetchTopicEvolution } from \"../../api/client\";\nimport type { TopicEvolutionResponse, SseEvent } from \"@contracts\";\nimport { Card, CardContent } from \"../../components/ui/card\";\nimport TopicEvolutionGraph from \"./TopicEvolutionGraph\";\n\nfunction isWikiRebuilt(e: SseEvent): e is Extract<SseEvent, { type: \"wiki_rebuilt\" }> {\n\treturn e.type === \"wiki_rebuilt\";\n}\n\nexport default function TopicEvolutionView(): React.ReactElement {\n\tconst { data, error, loading, refetch } = useApi<TopicEvolutionResponse>(\n\t\tuseCallback(() => fetchTopicEvolution(), []),\n\t\t{ pollInterval: 60_000 },\n\t);\n\n\tconst { events } = useSSE();\n\tconst lastRebuiltTs = useMemo(() => {\n\t\tconst rebuilt = events.filter(isWikiRebuilt);\n\t\tif (rebuilt.length === 0) return null;\n\t\treturn rebuilt[rebuilt.length - 1].ts;\n\t}, [events]);\n\n\tuseEffect(() => {\n\t\tif (lastRebuiltTs != null) refetch();\n\t}, [lastRebuiltTs, refetch]);\n\n\tif (error && !data) {\n\t\treturn (\n\t\t\t<div className=\"rounded-lg border border-border bg-bg-card p-6 text-sm text-danger\">\n\t\t\t\tError loading evolution graph: {error.message}\n\t\t\t</div>\n\t\t);\n\t}\n\tif (loading && !data) {\n\t\treturn (\n\t\t\t<div className=\"rounded-lg border border-border bg-bg-card p-6 text-sm text-muted-foreground\">\n\t\t\t\tLoading evolution graph…\n\t\t\t</div>\n\t\t);\n\t}\n\n\treturn (\n\t\t<Card>\n\t\t\t<CardContent>\n\t\t\t\t<h3 className=\"mb-2 font-heading text-sm font-semibold text-muted-foreground\">\n\t\t\t\t\tTopic evolution\n\t\t\t\t</h3>\n\t\t\t\t{data ? (\n\t\t\t\t\t<TopicEvolutionGraph data={data} />\n\t\t\t\t) : (\n\t\t\t\t\t<p className=\"text-sm text-muted-foreground\">No data yet.</p>\n\t\t\t\t)}\n\t\t\t</CardContent>\n\t\t</Card>\n\t);\n}\n","/**\n * dashboard-client/src/tabs/WikiTab.tsx — Wiki Revival (W3): wiki landing list.\n *\n * Replaces TopicsTab in the App registry (TopicsTab.tsx kept, unused). Renders\n * the wiki index: each auto-categorized topic with its resolved label (edited\n * badge when user-renamed), member count, curation badges (label/merge/split),\n * and a click-to-open that pushes a client-side page state to WikiPage.\n *\n * Styling is Tailwind + shadcn (Card, Badge, Button) — no legacy CSS classes.\n */\n\nimport type React from \"react\";\nimport { useCallback, useMemo, useState } from \"react\";\nimport { useApi } from \"../hooks/useApi\";\nimport { fetchWikiIndex } from \"../api/client\";\nimport type { WikiIndexEntry, WikiIndexResponse } from \"@contracts\";\nimport { Badge } from \"../components/ui/badge\";\nimport { Button } from \"../components/ui/button\";\nimport { Toggle } from \"../components/ui/toggle\";\nimport WikiPage from \"./WikiTab/WikiPage\";\nimport TopicEvolutionView from \"./WikiTab/TopicEvolutionView\";\n\ntype WikiView = \"list\" | \"evolution\";\n\nconst KIND_BADGES: Record<string, \"default\" | \"accent\" | \"warning\"> = {\n\tlabel: \"accent\",\n\tmerge: \"warning\",\n\tsplit: \"default\",\n};\n\nfunction fmtTs(ms: number | null): string {\n\tif (!ms) return \"—\";\n\treturn new Date(ms).toLocaleString();\n}\n\nfunction ViewToggle({\n\tview,\n\tonChange,\n}: {\n\tview: WikiView;\n\tonChange: (v: WikiView) => void;\n}): React.ReactElement {\n\treturn (\n\t\t<div className=\"flex gap-1\">\n\t\t\t<Toggle pressed={view === \"list\"} onClick={() => onChange(\"list\")}>\n\t\t\t\tTopics\n\t\t\t</Toggle>\n\t\t\t<Toggle\n\t\t\t\tpressed={view === \"evolution\"}\n\t\t\t\tonClick={() => onChange(\"evolution\")}\n\t\t\t>\n\t\t\t\tEvolution\n\t\t\t</Toggle>\n\t\t</div>\n\t);\n}\n\ninterface RowProps {\n\tentry: WikiIndexEntry;\n\tonOpen: (id: string) => void;\n}\n\nfunction TopicRow({ entry, onOpen }: RowProps): React.ReactElement {\n\treturn (\n\t\t<tr className=\"border-b border-border/60 last:border-0 hover:bg-bg-elevated/40\">\n\t\t\t<td className=\"py-2 pr-3\">\n\t\t\t\t<div className=\"flex items-center gap-2\">\n\t\t\t\t\t<span className=\"font-medium text-foreground\">{entry.label}</span>\n\t\t\t\t\t{entry.edited && <Badge variant=\"outline\">edited</Badge>}\n\t\t\t\t</div>\n\t\t\t</td>\n\t\t\t<td className=\"py-2 pr-3 text-sm text-muted-foreground\">\n\t\t\t\t{entry.memoryCount}\n\t\t\t</td>\n\t\t\t<td className=\"py-2 pr-3\">\n\t\t\t\t<div className=\"flex flex-wrap gap-1\">\n\t\t\t\t\t{entry.overrideKinds.map((k) => (\n\t\t\t\t\t\t<Badge key={k} variant={KIND_BADGES[k] ?? \"default\"}>\n\t\t\t\t\t\t\t{k}\n\t\t\t\t\t\t</Badge>\n\t\t\t\t\t))}\n\t\t\t\t</div>\n\t\t\t</td>\n\t\t\t<td className=\"py-2 pr-3 text-xs text-muted-foreground\">\n\t\t\t\t{fmtTs(entry.lastUpdated)}\n\t\t\t</td>\n\t\t\t<td className=\"py-2 text-right\">\n\t\t\t\t<Button\n\t\t\t\t\tvariant=\"outline\"\n\t\t\t\t\tsize=\"sm\"\n\t\t\t\t\tonClick={() => onOpen(entry.id)}\n\t\t\t\t>\n\t\t\t\t\tOpen\n\t\t\t\t</Button>\n\t\t\t</td>\n\t\t</tr>\n\t);\n}\n\nexport default function WikiTab(): React.ReactElement {\n\tconst { data, loading, error } = useApi<WikiIndexResponse>(\n\t\tuseCallback(() => fetchWikiIndex(), []),\n\t\t{ pollInterval: 30_000 },\n\t);\n\tconst [view, setView] = useState<WikiView>(\"list\");\n\tconst [query, setQuery] = useState(\"\");\n\tconst [openId, setOpenId] = useState<string | null>(null);\n\n\tconst filtered = useMemo(() => {\n\t\tif (!data) return [];\n\t\tconst q = query.trim().toLowerCase();\n\t\tif (!q) return data.topics;\n\t\treturn data.topics.filter((t) =>\n\t\t\tt.label.toLowerCase().includes(q),\n\t\t);\n\t}, [data, query]);\n\n\tif (openId) {\n\t\treturn <WikiPage topicId={openId} onBack={() => setOpenId(null)} />;\n\t}\n\n\tif (view === \"evolution\") {\n\t\treturn (\n\t\t\t<div className=\"flex flex-col gap-3\">\n\t\t\t\t<ViewToggle view={view} onChange={setView} />\n\t\t\t\t<TopicEvolutionView />\n\t\t\t</div>\n\t\t);\n\t}\n\n\tif (error && !data) {\n\t\treturn (\n\t\t\t<div className=\"rounded-lg border border-border bg-bg-card p-6 text-sm text-danger\">\n\t\t\t\tError loading wiki: {error.message}\n\t\t\t</div>\n\t\t);\n\t}\n\tif (loading && !data) {\n\t\treturn (\n\t\t\t<div className=\"rounded-lg border border-border bg-bg-card p-6 text-sm text-muted-foreground\">\n\t\t\t\tLoading wiki…\n\t\t\t</div>\n\t\t);\n\t}\n\tif (!data) {\n\t\treturn (\n\t\t\t<div className=\"rounded-lg border border-border bg-bg-card p-6 text-sm text-muted-foreground\">\n\t\t\t\tNo wiki data available.\n\t\t\t</div>\n\t\t);\n\t}\n\tif (data.totalTopics === 0) {\n\t\treturn (\n\t\t\t<div className=\"rounded-lg border border-border bg-bg-card p-6 text-sm text-muted-foreground\">\n\t\t\t\t<h3 className=\"mb-2 font-heading text-base text-foreground\">Wiki</h3>\n\t\t\t\t<p>\n\t\t\t\t\tNo topics yet. Topics are auto-generated after every Nth compaction\n\t\t\t\t\tfrom real memory embeddings (k-means + TF-IDF).\n\t\t\t\t</p>\n\t\t\t\t<p className=\"mt-2\">Check back after a few more compaction cycles.</p>\n\t\t\t</div>\n\t\t);\n\t}\n\n\treturn (\n\t\t<div className=\"flex flex-col gap-4\">\n\t\t\t<div className=\"flex flex-wrap items-end justify-between gap-2\">\n\t\t\t\t<div className=\"flex items-center gap-3\">\n\t\t\t\t\t<ViewToggle view={view} onChange={setView} />\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<h2 className=\"font-heading text-lg font-semibold\">Wiki</h2>\n\t\t\t\t\t\t<p className=\"text-sm text-muted-foreground\">\n\t\t\t\t\t\t\t{data.totalTopics} topic{data.totalTopics !== 1 ? \"s\" : \"\"} ·{\" \"}\n\t\t\t\t\t\t\t{data.totalMemories} assigned memori\n\t\t\t\t\t\t\t{data.totalMemories !== 1 ? \"es\" : \"y\"}\n\t\t\t\t\t\t\t{data.lastRebuildAt != null && (\n\t\t\t\t\t\t\t\t<> · last rebuild {fmtTs(data.lastRebuildAt)}</>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t</p>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<input\n\t\t\t\t\ttype=\"search\"\n\t\t\t\t\tplaceholder=\"Filter topics by label…\"\n\t\t\t\t\taria-label=\"Filter topics by label\"\n\t\t\t\t\tvalue={query}\n\t\t\t\t\tonChange={(e) => setQuery(e.target.value)}\n\t\t\t\t\tclassName=\"w-64 rounded-md border border-border bg-bg-elevated/50 px-3 py-2 text-sm outline-none transition-colors focus:border-primary\"\n\t\t\t\t/>\n\t\t\t</div>\n\n\t\t\t<div className=\"overflow-x-auto rounded-lg border border-border bg-bg-card\">\n\t\t\t\t<table className=\"w-full table-fixed text-sm\">\n\t\t\t\t\t<thead>\n\t\t\t\t\t\t<tr className=\"border-b border-border text-left text-xs uppercase text-muted-foreground\">\n\t\t\t\t\t\t\t<th className=\"w-1/3 px-4 py-2 font-medium\">Label</th>\n\t\t\t\t\t\t\t<th className=\"w-16 py-2 font-medium\">Memories</th>\n\t\t\t\t\t\t\t<th className=\"w-40 py-2 font-medium\">Badges</th>\n\t\t\t\t\t\t\t<th className=\"w-40 py-2 font-medium\">Last updated</th>\n\t\t\t\t\t\t\t<th className=\"w-20 py-2\" />\n\t\t\t\t\t\t</tr>\n\t\t\t\t\t</thead>\n\t\t\t\t\t<tbody>\n\t\t\t\t\t\t{filtered.map((t) => (\n\t\t\t\t\t\t\t<TopicRow key={t.id} entry={t} onOpen={setOpenId} />\n\t\t\t\t\t\t))}\n\t\t\t\t\t\t{filtered.length === 0 && (\n\t\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t\t<td\n\t\t\t\t\t\t\t\t\tcolSpan={5}\n\t\t\t\t\t\t\t\t\tclassName=\"px-4 py-6 text-center text-muted-foreground\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\tNo topics match \"{query}\".\n\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t</tr>\n\t\t\t\t\t\t)}\n\t\t\t\t\t</tbody>\n\t\t\t\t</table>\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n"],"names":["memberSnippet","id","method","base","WikiPageControls","topicId","others","members","onMutated","mode","setMode","useState","label","setLabel","target","setTarget","picked","setPicked","busy","setBusy","error","setError","open","m","submit","renameTopic","mergeTopics","splitTopic","e","jsxs","Fragment","jsx","Button","o","prev","x","W","H","BAR_W","GAP","fmtBucket","ts","TopicTimeline","data","useApi","useCallback","fetchTopicTimeline","buckets","total","max","b","totalWidth","scale","i","h","fmtTs","ms","METHOD_LABELS","WikiPage","onBack","dirty","setDirty","bump","d","page","loading","fetchWikiTopic","index","fetchWikiIndex","labelOf","useMemo","map","t","otherTopics","Badge","Card","CardContent","p","REPULSION","ATTRACTION","CENTER_GRAVITY","DAMPING","SPEED_LIMIT","MIN_VELOCITY","MAX_ITERATIONS","edgeColor","kind","initialLayout","nodes","n","angle","applyForces","sim","edges","fx","fy","j","dx","dy","distSq","dist","other","speed","TopicEvolutionGraph","simRef","useRef","animRef","setFrame","scrub","setScrub","useEffect","indexById","si","ti","timeByActivity","iter","tick","scrubMax","scrubBucket","idx","activeSet","a","active","r","isWikiRebuilt","TopicEvolutionView","refetch","fetchTopicEvolution","events","useSSE","lastRebuiltTs","rebuilt","KIND_BADGES","ViewToggle","view","onChange","Toggle","TopicRow","entry","onOpen","k","WikiTab","setView","query","setQuery","openId","setOpenId","filtered","q"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{r as s,j as n,k as i,W as d}from"./index-GPHRnEN7.js";const l=d("inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/60 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",{variants:{variant:{default:"bg-primary text-primary-foreground hover:bg-primary/90 glow-primary",outline:"border border-border bg-transparent hover:bg-bg-elevated hover:text-foreground",ghost:"hover:bg-bg-elevated hover:text-foreground",glass:"glass-panel electric-hover"},size:{default:"h-9 px-4 py-2",sm:"h-8 rounded-md px-3 text-xs",lg:"h-10 rounded-md px-8",icon:"h-9 w-9"}},defaultVariants:{variant:"default",size:"default"}}),u=s.forwardRef(({className:e,variant:r,size:t,...a},o)=>n.jsx("button",{ref:o,className:i(l({variant:r,size:t,className:e})),...a}));u.displayName="Button";export{u as B};
|
|
2
|
+
//# sourceMappingURL=button-Bt0b5QVp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"button-Bt0b5QVp.js","sources":["../../src/components/ui/button.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport { cn } from \"../../utils/cn\";\n\nconst buttonVariants = cva(\n \"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/60 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0\",\n {\n variants: {\n variant: {\n default: \"bg-primary text-primary-foreground hover:bg-primary/90 glow-primary\",\n outline: \"border border-border bg-transparent hover:bg-bg-elevated hover:text-foreground\",\n ghost: \"hover:bg-bg-elevated hover:text-foreground\",\n glass: \"glass-panel electric-hover\",\n },\n size: {\n default: \"h-9 px-4 py-2\",\n sm: \"h-8 rounded-md px-3 text-xs\",\n lg: \"h-10 rounded-md px-8\",\n icon: \"h-9 w-9\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"default\",\n },\n },\n);\n\nexport interface ButtonProps\n extends React.ButtonHTMLAttributes<HTMLButtonElement>,\n VariantProps<typeof buttonVariants> {}\n\nconst Button = React.forwardRef<HTMLButtonElement, ButtonProps>(\n ({ className, variant, size, ...props }, ref) => (\n <button\n ref={ref}\n className={cn(buttonVariants({ variant, size, className }))}\n {...props}\n />\n ),\n);\nButton.displayName = \"Button\";\n\nexport { Button, buttonVariants };\n"],"names":["buttonVariants","cva","Button","React.forwardRef","className","variant","size","props","ref","jsx","cn"],"mappings":"6DAIA,MAAMA,EAAiBC,EACrB,2SACA,CACE,SAAU,CACR,QAAS,CACP,QAAS,sEACT,QAAS,iFACT,MAAO,6CACP,MAAO,4BAAA,EAET,KAAM,CACJ,QAAS,gBACT,GAAI,8BACJ,GAAI,uBACJ,KAAM,SAAA,CACR,EAEF,gBAAiB,CACf,QAAS,UACT,KAAM,SAAA,CACR,CAEJ,EAMMC,EAASC,EAAAA,WACb,CAAC,CAAE,UAAAC,EAAW,QAAAC,EAAS,KAAAC,EAAM,GAAGC,CAAA,EAASC,IACvCC,EAAAA,IAAC,SAAA,CACC,IAAAD,EACA,UAAWE,EAAGV,EAAe,CAAE,QAAAK,EAAS,KAAAC,EAAM,UAAAF,CAAA,CAAW,CAAC,EACzD,GAAGG,CAAA,CAAA,CAGV,EACAL,EAAO,YAAc"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{r,j as t,k as d}from"./index-GPHRnEN7.js";const o=r.forwardRef(({className:a,...s},e)=>t.jsx("div",{ref:e,className:d("glass-panel p-4",a),...s}));o.displayName="Card";const n=r.forwardRef(({className:a,...s},e)=>t.jsx("div",{ref:e,className:d("mb-3 flex flex-col space-y-1.5",a),...s}));n.displayName="CardHeader";const l=r.forwardRef(({className:a,...s},e)=>t.jsx("h3",{ref:e,className:d("font-heading text-sm font-semibold leading-none tracking-tight",a),...s}));l.displayName="CardTitle";const i=r.forwardRef(({className:a,...s},e)=>t.jsx("div",{ref:e,className:d("text-sm",a),...s}));i.displayName="CardContent";export{o as C,n as a,l as b,i as c};
|
|
2
|
+
//# sourceMappingURL=card-D5CafXtg.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"card-D5CafXtg.js","sources":["../../src/components/ui/card.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { cn } from \"../../utils/cn\";\n\nconst Card = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(\n ({ className, ...props }, ref) => (\n <div ref={ref} className={cn(\"glass-panel p-4\", className)} {...props} />\n ),\n);\nCard.displayName = \"Card\";\n\nconst CardHeader = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(\n ({ className, ...props }, ref) => (\n <div ref={ref} className={cn(\"mb-3 flex flex-col space-y-1.5\", className)} {...props} />\n ),\n);\nCardHeader.displayName = \"CardHeader\";\n\nconst CardTitle = React.forwardRef<HTMLHeadingElement, React.HTMLAttributes<HTMLHeadingElement>>(\n ({ className, ...props }, ref) => (\n <h3 ref={ref} className={cn(\"font-heading text-sm font-semibold leading-none tracking-tight\", className)} {...props} />\n ),\n);\nCardTitle.displayName = \"CardTitle\";\n\nconst CardContent = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(\n ({ className, ...props }, ref) => (\n <div ref={ref} className={cn(\"text-sm\", className)} {...props} />\n ),\n);\nCardContent.displayName = \"CardContent\";\n\nexport { Card, CardHeader, CardTitle, CardContent };\n"],"names":["Card","React.forwardRef","className","props","ref","jsx","cn","CardHeader","CardTitle","CardContent"],"mappings":"iDAGA,MAAMA,EAAOC,EAAAA,WACX,CAAC,CAAE,UAAAC,EAAW,GAAGC,CAAA,EAASC,IACxBC,EAAAA,IAAC,MAAA,CAAI,IAAAD,EAAU,UAAWE,EAAG,kBAAmBJ,CAAS,EAAI,GAAGC,CAAA,CAAO,CAE3E,EACAH,EAAK,YAAc,OAEnB,MAAMO,EAAaN,EAAAA,WACjB,CAAC,CAAE,UAAAC,EAAW,GAAGC,CAAA,EAASC,IACxBC,EAAAA,IAAC,MAAA,CAAI,IAAAD,EAAU,UAAWE,EAAG,iCAAkCJ,CAAS,EAAI,GAAGC,CAAA,CAAO,CAE1F,EACAI,EAAW,YAAc,aAEzB,MAAMC,EAAYP,EAAAA,WAChB,CAAC,CAAE,UAAAC,EAAW,GAAGC,CAAA,EAASC,IACxBC,EAAAA,IAAC,KAAA,CAAG,IAAAD,EAAU,UAAWE,EAAG,iEAAkEJ,CAAS,EAAI,GAAGC,CAAA,CAAO,CAEzH,EACAK,EAAU,YAAc,YAExB,MAAMC,EAAcR,EAAAA,WAClB,CAAC,CAAE,UAAAC,EAAW,GAAGC,CAAA,EAASC,IACxBC,EAAAA,IAAC,MAAA,CAAI,IAAAD,EAAU,UAAWE,EAAG,UAAWJ,CAAS,EAAI,GAAGC,CAAA,CAAO,CAEnE,EACAM,EAAY,YAAc"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
*,:before,:after{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}:before,:after{--tw-content: ""}html,:host{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:Inter,ui-sans-serif,system-ui,sans-serif;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:JetBrains Mono,ui-monospace,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}:root{--bg: 222 47% 5%;--bg-card: 222 32% 8%;--bg-elevated: 222 28% 12%;--border: 217 33% 17%;--foreground: 210 40% 98%;--muted: 215 20% 65%;--primary: 217 91% 60%;--primary-glow: 217 91% 60%;--success: 142 71% 45%;--warning: 38 92% 50%;--danger: 0 84% 60%;--accent: 280 100% 70%;--radius: .75rem}*{border-color:hsl(var(--border))}html{background-color:hsl(var(--bg));color:hsl(var(--foreground));-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}body{background-color:hsl(var(--bg));font-family:Inter,ui-sans-serif,system-ui,sans-serif;color:hsl(var(--foreground));margin:0}h1,h2,h3,h4,h5,h6{font-family:JetBrains Mono,ui-monospace,monospace}:where(button,[role=tab],a):focus-visible{outline:2px solid hsl(var(--primary) / .6);outline-offset:2px}.container{width:100%;margin-right:auto;margin-left:auto;padding-right:1.5rem;padding-left:1.5rem}@media (min-width: 1600px){.container{max-width:1600px}}.glass-panel{position:relative;border-radius:var(--radius);border-width:1px;border-color:hsl(var(--border));background-color:hsl(var(--bg-card) / .7);--tw-backdrop-blur: blur(12px);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);box-shadow:inset 0 1px hsl(var(--border) / .5),var(--tw-shadow, 0 8px 30px -12px hsl(var(--bg) / .6))}.electric-hover{transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.2s}.electric-hover:hover{--tw-translate-y: -.125rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));border-color:hsl(var(--primary) / .7);box-shadow:0 0 20px -4px hsl(var(--primary-glow) / .45)}.electric-hover:focus-visible{outline:2px solid hsl(var(--primary) / .6);outline-offset:2px}.glow-primary{box-shadow:0 0 20px -4px hsl(var(--primary-glow) / .5)}.text-neon{color:hsl(var(--primary))}.gradient-text{background:linear-gradient(120deg,hsl(var(--primary)),hsl(var(--accent)));-webkit-background-clip:text;background-clip:text;color:transparent}.pointer-events-none{pointer-events:none}.visible{visibility:visible}.collapse{visibility:collapse}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{inset:0}.inset-x-3{left:.75rem;right:.75rem}.bottom-16{bottom:4rem}.bottom-3{bottom:.75rem}.left-2{left:.5rem}.right-2{right:.5rem}.top-0{top:0}.z-40{z-index:40}.z-50{z-index:50}.mx-auto{margin-left:auto;margin-right:auto}.mb-1{margin-bottom:.25rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.ml-2{margin-left:.5rem}.ml-auto{margin-left:auto}.mr-1{margin-right:.25rem}.mr-1\.5{margin-right:.375rem}.mt-0\.5{margin-top:.125rem}.mt-1{margin-top:.25rem}.mt-2{margin-top:.5rem}.mt-3{margin-top:.75rem}.mt-4{margin-top:1rem}.line-clamp-3{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:3}.block{display:block}.inline-block{display:inline-block}.inline{display:inline}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.grid{display:grid}.hidden{display:none}.h-0\.5{height:.125rem}.h-1\.5{height:.375rem}.h-10{height:2.5rem}.h-2{height:.5rem}.h-3\.5{height:.875rem}.h-4{height:1rem}.h-5{height:1.25rem}.h-8{height:2rem}.h-9{height:2.25rem}.h-full{height:100%}.max-h-40{max-height:10rem}.max-h-48{max-height:12rem}.max-h-56{max-height:14rem}.max-h-72{max-height:18rem}.max-h-96{max-height:24rem}.max-h-\[85vh\]{max-height:85vh}.min-h-screen{min-height:100vh}.w-1\.5{width:.375rem}.w-1\/3{width:33.333333%}.w-16{width:4rem}.w-2{width:.5rem}.w-20{width:5rem}.w-24{width:6rem}.w-3\.5{width:.875rem}.w-4{width:1rem}.w-40{width:10rem}.w-5{width:1.25rem}.w-56{width:14rem}.w-6{width:1.5rem}.w-64{width:16rem}.w-9{width:2.25rem}.w-full{width:100%}.min-w-0{min-width:0px}.min-w-\[8rem\]{min-width:8rem}.max-w-3xl{max-width:48rem}.max-w-\[1600px\]{max-width:1600px}.max-w-md{max-width:28rem}.max-w-sm{max-width:24rem}.max-w-xl{max-width:36rem}.flex-1{flex:1 1 0%}.shrink-0{flex-shrink:0}.table-fixed{table-layout:fixed}.border-collapse{border-collapse:collapse}.rotate-180{--tw-rotate: 180deg;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.cursor-pointer{cursor:pointer}.select-none{-webkit-user-select:none;-moz-user-select:none;user-select:none}.list-decimal{list-style-type:decimal}.list-disc{list-style-type:disc}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.flex-row{flex-direction:row}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-start{align-items:flex-start}.items-end{align-items:flex-end}.items-center{align-items:center}.items-baseline{align-items:baseline}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.justify-around{justify-content:space-around}.gap-1{gap:.25rem}.gap-1\.5{gap:.375rem}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.gap-6{gap:1.5rem}.gap-x-4{-moz-column-gap:1rem;column-gap:1rem}.gap-y-0\.5{row-gap:.125rem}.gap-y-1{row-gap:.25rem}.gap-y-2{row-gap:.5rem}.space-y-0>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(0px * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(0px * var(--tw-space-y-reverse))}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.25rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.25rem * var(--tw-space-y-reverse))}.space-y-1\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.375rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.375rem * var(--tw-space-y-reverse))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem * var(--tw-space-y-reverse))}.divide-y>:not([hidden])~:not([hidden]){--tw-divide-y-reverse: 0;border-top-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)));border-bottom-width:calc(1px * var(--tw-divide-y-reverse))}.divide-border>:not([hidden])~:not([hidden]){border-color:hsl(var(--border))}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.whitespace-nowrap{white-space:nowrap}.whitespace-pre-wrap{white-space:pre-wrap}.break-all{word-break:break-all}.rounded{border-radius:.25rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:var(--radius)}.rounded-md{border-radius:calc(var(--radius) - 2px)}.rounded-sm{border-radius:calc(var(--radius) - 4px)}.rounded-xl{border-radius:.75rem}.rounded-t-xl{border-top-left-radius:.75rem;border-top-right-radius:.75rem}.border{border-width:1px}.border-b{border-bottom-width:1px}.border-t{border-top-width:1px}.border-dashed{border-style:dashed}.border-accent\/40{border-color:hsl(var(--accent) / .4)}.border-amber-500\/30{border-color:#f59e0b4d}.border-border{border-color:hsl(var(--border))}.border-border\/40{border-color:hsl(var(--border) / .4)}.border-border\/50{border-color:hsl(var(--border) / .5)}.border-border\/60{border-color:hsl(var(--border) / .6)}.border-danger\/40{border-color:hsl(var(--danger) / .4)}.border-green-500{--tw-border-opacity: 1;border-color:rgb(34 197 94 / var(--tw-border-opacity, 1))}.border-primary\/40{border-color:hsl(var(--primary) / .4)}.border-primary\/50{border-color:hsl(var(--primary) / .5)}.border-red-500\/50{border-color:#ef444480}.border-success\/40{border-color:hsl(var(--success) / .4)}.border-transparent{border-color:transparent}.border-warning\/40{border-color:hsl(var(--warning) / .4)}.bg-accent\/15{background-color:hsl(var(--accent) / .15)}.bg-amber-500{--tw-bg-opacity: 1;background-color:rgb(245 158 11 / var(--tw-bg-opacity, 1))}.bg-amber-500\/5{background-color:#f59e0b0d}.bg-background{background-color:hsl(var(--bg))}.bg-bg-card{background-color:hsl(var(--bg-card))}.bg-bg-elevated{background-color:hsl(var(--bg-elevated))}.bg-bg-elevated\/20{background-color:hsl(var(--bg-elevated) / .2)}.bg-bg-elevated\/40{background-color:hsl(var(--bg-elevated) / .4)}.bg-bg-elevated\/50{background-color:hsl(var(--bg-elevated) / .5)}.bg-bg-elevated\/60{background-color:hsl(var(--bg-elevated) / .6)}.bg-black\/50{background-color:#00000080}.bg-black\/60{background-color:#0009}.bg-current{background-color:currentColor}.bg-danger{background-color:hsl(var(--danger))}.bg-danger\/15{background-color:hsl(var(--danger) / .15)}.bg-foreground,.bg-muted-foreground{background-color:hsl(var(--foreground))}.bg-primary{background-color:hsl(var(--primary))}.bg-primary\/10{background-color:hsl(var(--primary) / .1)}.bg-primary\/15{background-color:hsl(var(--primary) / .15)}.bg-success{background-color:hsl(var(--success))}.bg-success\/15{background-color:hsl(var(--success) / .15)}.bg-transparent{background-color:transparent}.bg-warning\/10{background-color:hsl(var(--warning) / .1)}.bg-warning\/15{background-color:hsl(var(--warning) / .15)}.p-1{padding:.25rem}.p-2{padding:.5rem}.p-3{padding:.75rem}.p-4{padding:1rem}.p-5{padding:1.25rem}.p-6{padding:1.5rem}.p-8{padding:2rem}.px-1\.5{padding-left:.375rem;padding-right:.375rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-2\.5{padding-left:.625rem;padding-right:.625rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-8{padding-left:2rem;padding-right:2rem}.py-0\.5{padding-top:.125rem;padding-bottom:.125rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-1\.5{padding-top:.375rem;padding-bottom:.375rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-2\.5{padding-top:.625rem;padding-bottom:.625rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-4{padding-top:1rem;padding-bottom:1rem}.py-6{padding-top:1.5rem;padding-bottom:1.5rem}.pb-2{padding-bottom:.5rem}.pb-20{padding-bottom:5rem}.pl-5{padding-left:1.25rem}.pl-8{padding-left:2rem}.pr-2{padding-right:.5rem}.pr-3{padding-right:.75rem}.pt-2{padding-top:.5rem}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.align-top{vertical-align:top}.font-heading,.font-mono{font-family:JetBrains Mono,ui-monospace,monospace}.text-2xl{font-size:1.5rem;line-height:2rem}.text-\[10px\]{font-size:10px}.text-\[11px\]{font-size:11px}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-medium{font-weight:500}.font-normal{font-weight:400}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.leading-none{line-height:1}.leading-relaxed{line-height:1.625}.tracking-tight{letter-spacing:-.025em}.tracking-wide{letter-spacing:.025em}.tracking-widest{letter-spacing:.1em}.text-accent{color:hsl(var(--accent))}.text-amber-400{--tw-text-opacity: 1;color:rgb(251 191 36 / var(--tw-text-opacity, 1))}.text-danger{color:hsl(var(--danger))}.text-emerald-400{--tw-text-opacity: 1;color:rgb(52 211 153 / var(--tw-text-opacity, 1))}.text-foreground{color:hsl(var(--foreground))}.text-foreground\/90{color:hsl(var(--foreground) / .9)}.text-muted{color:hsl(var(--muted))}.text-muted-foreground{color:hsl(var(--foreground))}.text-muted-foreground\/60{color:hsl(var(--foreground) / .6)}.text-primary-foreground{--tw-text-opacity: 1;color:hsl(222 47% 5% / var(--tw-text-opacity, 1))}.text-red-400{--tw-text-opacity: 1;color:rgb(248 113 113 / var(--tw-text-opacity, 1))}.text-success{color:hsl(var(--success))}.text-warning{color:hsl(var(--warning))}.text-white{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.underline{text-decoration-line:underline}.accent-primary{accent-color:hsl(var(--primary))}.shadow-lg{--tw-shadow: 0 10px 15px -3px rgb(0 0 0 / .1), 0 4px 6px -4px rgb(0 0 0 / .1);--tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-panel{--tw-shadow: 0 8px 30px -12px hsl(var(--bg) / .6);--tw-shadow-colored: 0 8px 30px -12px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-xl{--tw-shadow: 0 20px 25px -5px rgb(0 0 0 / .1), 0 8px 10px -6px rgb(0 0 0 / .1);--tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), 0 8px 10px -6px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.outline-none{outline:2px solid transparent;outline-offset:2px}.outline{outline-style:solid}.ring{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-all{transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-transform{transition-property:transform;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.focus\:text-neon:focus{color:hsl(var(--primary))}.data-\[state\=active\]\:text-neon[data-state=active]{color:hsl(var(--primary))}.placeholder\:text-muted-foreground::-moz-placeholder{color:hsl(var(--foreground))}.placeholder\:text-muted-foreground::placeholder{color:hsl(var(--foreground))}.last\:border-0:last-child{border-width:0px}.hover\:bg-bg-elevated:hover{background-color:hsl(var(--bg-elevated))}.hover\:bg-bg-elevated\/40:hover{background-color:hsl(var(--bg-elevated) / .4)}.hover\:bg-primary\/90:hover{background-color:hsl(var(--primary) / .9)}.hover\:bg-red-500\/10:hover{background-color:#ef44441a}.hover\:text-foreground:hover{color:hsl(var(--foreground))}.hover\:text-red-300:hover{--tw-text-opacity: 1;color:rgb(252 165 165 / var(--tw-text-opacity, 1))}.focus\:border-primary:focus{border-color:hsl(var(--primary))}.focus\:bg-primary\/15:focus{background-color:hsl(var(--primary) / .15)}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.focus\:ring-2:focus{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus\:ring-primary\/60:focus{--tw-ring-color: hsl(var(--primary) / .6)}.focus-visible\:outline-none:focus-visible{outline:2px solid transparent;outline-offset:2px}.focus-visible\:ring-2:focus-visible{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus-visible\:ring-primary\/60:focus-visible{--tw-ring-color: hsl(var(--primary) / .6)}.disabled\:pointer-events-none:disabled{pointer-events:none}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-50:disabled{opacity:.5}.data-\[disabled\]\:pointer-events-none[data-disabled]{pointer-events:none}.data-\[state\=checked\]\:translate-x-4[data-state=checked]{--tw-translate-x: 1rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.data-\[state\=unchecked\]\:translate-x-0\.5[data-state=unchecked]{--tw-translate-x: .125rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.data-\[state\=active\]\:bg-primary\/15[data-state=active]{background-color:hsl(var(--primary) / .15)}.data-\[state\=checked\]\:bg-primary[data-state=checked]{background-color:hsl(var(--primary))}.data-\[state\=unchecked\]\:bg-bg-elevated[data-state=unchecked]{background-color:hsl(var(--bg-elevated))}.data-\[disabled\]\:opacity-50[data-disabled]{opacity:.5}@media (min-width: 640px){.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.sm\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}}@media (min-width: 768px){.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.md\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}}@media (min-width: 1024px){.lg\:flex{display:flex}.lg\:hidden{display:none}.lg\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.lg\:grid-cols-5{grid-template-columns:repeat(5,minmax(0,1fr))}.lg\:pb-4{padding-bottom:1rem}}@media (min-width: 1280px){.xl\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.xl\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}}.\[\&_svg\]\:pointer-events-none svg{pointer-events:none}.\[\&_svg\]\:size-4 svg{width:1rem;height:1rem}.\[\&_svg\]\:shrink-0 svg{flex-shrink:0}:root{--bg: #0d1117;--panel: #161b22;--border: #30363d;--text: #e6edf3;--muted: #8b949e;--accent: #58a6ff;--ok: #3fb950;--warn: #d29922;--err: #f85149;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif;font-size:clamp(13px,.9vw,16px)}*{box-sizing:border-box}body{margin:0;background:var(--bg);color:var(--text)}.dashboard-app{max-width:min(1600px,96vw);margin:0 auto;padding:clamp(8px,2vw,24px)}.card-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,320px),1fr));gap:clamp(8px,1.5vw,16px)}.dashboard-header h1{font-size:clamp(16px,1.4vw,22px);font-weight:600;margin:0 0 clamp(8px,1vw,16px)}.dashboard-header .tier,.dashboard-header .version-pill{display:inline-block;margin-left:8px;padding:2px 8px;font-size:clamp(10px,.8vw,12px);border-radius:10px;background:var(--panel);border:1px solid var(--border);color:var(--muted)}.dashboard-header .tier{color:var(--accent)}.tab-bar{display:flex;gap:4px;border-bottom:1px solid var(--border);margin-bottom:clamp(8px,1vw,16px);overflow-x:auto;flex-wrap:nowrap}.tab-bar button{background:none;border:none;color:var(--muted);padding:8px 14px;cursor:pointer;font-size:clamp(12px,.85vw,14px);border-bottom:2px solid transparent;white-space:nowrap}.tab-bar button.active{color:var(--text);border-bottom-color:var(--accent)}.tab-bar button:hover{color:var(--text)}.tab-bar .advanced-toggle{background:none;border:none;color:var(--muted);padding:8px 14px;cursor:pointer;font-size:clamp(12px,.85vw,14px);border-bottom:2px solid transparent;white-space:nowrap;margin-left:6px}.tab-bar .advanced-toggle:hover{color:var(--text)}.tab-bar .advanced-toggle[aria-expanded=true]{color:var(--text);border-bottom-color:var(--border)}.tab-bar .advanced-tabs{display:flex;gap:4px;flex-basis:100%;border-top:1px dashed var(--border);padding-top:6px;margin-top:-1px}.dashboard-content{min-height:400px}.loading-spinner{display:flex;align-items:center;justify-content:center;padding:48px;color:var(--muted)}.error-fallback{padding:24px;border:1px solid var(--err);border-radius:8px;background:#f8514914}.error-fallback button{margin-top:12px;padding:6px 14px;background:var(--panel);border:1px solid var(--border);color:var(--text);border-radius:6px;cursor:pointer}.tab-stub{padding:32px;color:var(--muted);border:1px dashed var(--border);border-radius:8px;text-align:center}.repos{width:100%;border-collapse:collapse;font-size:clamp(12px,.8vw,14px)}.repos th,.repos td{padding:6px 10px;border-bottom:1px solid var(--border-soft, var(--border));text-align:left}.repos th{background:var(--bg);position:sticky;top:0}.table-wrap{overflow-x:auto}@media (max-width: 640px){.card-grid{grid-template-columns:1fr}.tab-bar button{padding:6px 10px;font-size:12px}}@media (min-width: 641px) and (max-width: 1024px){.card-grid{grid-template-columns:repeat(2,1fr)}}@media (min-width: 1025px){.card-grid{grid-template-columns:repeat(auto-fit,minmax(320px,1fr))}}@media (min-width: 1601px){.dashboard-app{max-width:min(1800px,96vw)}.card-grid{grid-template-columns:repeat(4,1fr)}}.overview-tab{display:flex;flex-direction:column;gap:12px}.overview-header{display:flex;align-items:center;gap:12px}.tier-pill{padding:2px 10px;font-size:12px;border-radius:10px;background:var(--panel);border:1px solid var(--border);color:var(--accent)}.updated{color:var(--muted);font-size:12px}.card-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:12px}.card{padding:14px 16px;background:var(--panel);border:1px solid var(--border);border-radius:8px}.card h3{margin:0 0 10px;font-size:13px;color:var(--muted);font-weight:600}.gauge-bar{height:10px;background:var(--bg);border-radius:5px;overflow:hidden;border:1px solid var(--border)}.gauge-fill{height:100%;transition:width .4s ease}.gauge-green .gauge-fill{background:var(--ok)}.gauge-yellow .gauge-fill{background:var(--warn)}.gauge-red .gauge-fill{background:var(--err)}.gauge-label{margin:8px 0 0;font-size:12px;color:var(--muted)}.stat-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:8px}.stat{display:flex;flex-direction:column;gap:2px}.stat-label{font-size:11px;color:var(--muted);text-transform:uppercase}.stat-value{font-size:16px;font-weight:600}.stat-highlight .stat-value{color:var(--ok)}.bullet-row{display:flex;gap:14px;margin-bottom:8px}.bullet{display:flex;align-items:center;gap:6px;font-size:13px}.bullet-dot{width:8px;height:8px;border-radius:50%;background:var(--muted)}.bullet-on .bullet-dot{background:var(--ok);box-shadow:0 0 6px var(--ok)}.bullet-off .bullet-dot{background:var(--border)}.bullet-on .bullet-label{color:var(--text)}.bullet-off .bullet-label{color:var(--muted)}.trigger-detail{margin:4px 0;font-size:12px;color:var(--muted)}.state-badge{display:inline-block;padding:2px 10px;font-size:12px;border-radius:10px;background:var(--bg);border:1px solid var(--border)}.state-idle,.state-none{color:var(--muted)}.state-compacting{color:var(--warn);border-color:var(--warn)}.persisted-tag{margin-left:8px;font-size:11px;color:var(--ok)}.events-tab{display:flex;flex-direction:column;gap:10px}.events-header{display:flex;align-items:center;gap:14px}.sse-status{display:inline-flex;align-items:center;gap:6px;font-size:12px;color:var(--muted)}.sse-dot{width:8px;height:8px;border-radius:50%;background:var(--muted)}.sse-connected .sse-dot{background:var(--ok);box-shadow:0 0 6px var(--ok)}.sse-connecting .sse-dot{background:var(--warn)}.sse-disconnected .sse-dot,.sse-error .sse-dot{background:var(--err)}.event-count{color:var(--muted);font-size:12px}.event-filters{display:flex;flex-wrap:wrap;gap:6px;align-items:center;margin-bottom:8px}.filter-chip{padding:3px 10px;font-size:11px;border:1px solid var(--border);background:var(--bg);color:var(--muted);border-radius:12px;cursor:pointer}.filter-chip.active{color:var(--text);border-color:var(--accent);background:var(--panel)}.event-list{list-style:none;margin:0;padding:0;max-height:60vh;overflow-y:auto}.event-row{display:grid;grid-template-columns:70px 150px 1fr;gap:8px;padding:6px 10px;border-bottom:1px solid var(--border);font-size:12px;cursor:pointer}.event-row:hover{background:var(--panel)}.ev-time{color:var(--muted)}.ev-type{font-size:11px;padding:1px 6px;border-radius:8px;background:var(--bg);border:1px solid var(--border);color:var(--muted);text-align:center}.ev-compact .ev-type{color:var(--accent);border-color:var(--accent)}.ev-trigger .ev-type{color:var(--warn);border-color:var(--warn)}.ev-tier .ev-type{color:var(--muted)}.ev-checkpoint .ev-type{color:var(--ok);border-color:var(--ok)}.ev-recall .ev-type{color:#d2a8ff;border-color:#d2a8ff}.ev-config .ev-type{color:var(--text)}.ev-crew .ev-type{color:#79c0ff;border-color:#79c0ff}.ev-game .ev-type{color:var(--warn)}.ev-summary{color:var(--text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ev-detail{grid-column:1 / -1;margin:6px 0 0;padding:8px;background:var(--bg);border-radius:4px;font-size:11px;color:var(--muted);white-space:pre-wrap}.event-empty{padding:24px;color:var(--muted);text-align:center}@media (max-width: 768px){.card-grid{grid-template-columns:1fr}.event-row{grid-template-columns:60px 110px 1fr;font-size:11px}}.summary-tiles{display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));gap:10px;margin-bottom:16px}.tile{display:flex;flex-direction:column;gap:4px;padding:12px 14px;background:var(--panel);border:1px solid var(--border);border-radius:8px}.tile-label{font-size:11px;color:var(--muted);text-transform:uppercase}.tile-value{font-size:20px;font-weight:600}.tile-highlight .tile-value{color:var(--ok)}.repo-table-wrap{overflow-x:auto}.repo-search{width:100%;padding:8px 10px;margin-bottom:10px;background:var(--panel);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:13px}.repo-table{width:100%;border-collapse:collapse;font-size:13px}.repo-table th{text-align:left;padding:6px 10px;border-bottom:1px solid var(--border)}.repo-table td{padding:8px 10px;border-bottom:1px solid var(--border)}.repo-table tr{cursor:pointer}.repo-table tbody tr:hover{background:var(--panel)}.sort-header{background:none;border:none;color:var(--muted);font-size:12px;font-weight:600;cursor:pointer;padding:0}.sort-header.active-asc,.sort-header.active-desc{color:var(--text)}.sort-arrow{color:var(--accent)}.repo-name{font-weight:600}.repo-model{color:var(--muted)}.modal-backdrop{position:fixed;inset:0;background:#0009;display:flex;align-items:center;justify-content:center;z-index:100}.modal-card{background:var(--panel);border:1px solid var(--border);border-radius:10px;padding:20px 24px;max-width:560px;width:90%;max-height:80vh;overflow-y:auto}.modal-header{display:flex;justify-content:space-between;align-items:center}.modal-header h2{margin:0;font-size:18px}.modal-close{background:none;border:none;color:var(--muted);font-size:22px;cursor:pointer;padding:0 4px}.modal-close:hover{color:var(--text)}.modal-path{font-size:11px;color:var(--muted);margin:4px 0 12px;word-break:break-all}.modal-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:10px;margin-bottom:16px}.modal-stat{display:flex;flex-direction:column;gap:2px}.modal-label{font-size:11px;color:var(--muted);text-transform:uppercase}.modal-value{font-size:16px;font-weight:600}.modal-highlight .modal-value{color:var(--ok)}.modal-card h3{font-size:13px;color:var(--muted);margin:16px 0 6px}.modal-dl{display:grid;grid-template-columns:130px 1fr;gap:4px 12px;margin:0}.modal-dl dt{color:var(--muted);font-size:12px}.modal-dl dd{margin:0;font-size:13px}.model-badge{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,160px),1fr));gap:8px;padding:12px 14px;background:var(--panel);border:1px solid var(--border);border-radius:8px;margin-bottom:12px}.model-field{display:flex;flex-direction:column;gap:2px}.model-field-label{font-size:11px;color:var(--muted);text-transform:uppercase}.model-field-value{font-size:14px;font-weight:600}.perf-chart{display:flex;flex-direction:column;gap:12px}.perf-header{display:flex;justify-content:space-between;align-items:center}.perf-header h3{margin:0;font-size:13px;color:var(--muted)}.perf-window{font-size:11px;color:var(--muted)}.perf-grid,.perf-resources{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:10px}.perf-resources{padding-top:10px;border-top:1px solid var(--border)}.perf-metric{display:flex;flex-direction:column;gap:4px;padding:10px 12px;background:var(--panel);border:1px solid var(--border);border-radius:6px}.perf-label{font-size:11px;color:var(--muted)}.perf-value{font-size:15px;font-weight:600}.perf-bar-track{height:6px;background:var(--bg);border-radius:3px;overflow:hidden}.perf-bar-fill{height:100%;transition:width .4s ease}.perf-blue .perf-bar-fill{background:var(--accent)}.perf-purple .perf-bar-fill{background:#d2a8ff}.perf-green .perf-bar-fill{background:var(--ok)}.perf-yellow .perf-bar-fill{background:var(--warn)}.perf-diag{display:flex;flex-wrap:wrap;gap:14px;padding-top:10px;border-top:1px solid var(--border)}@media (max-width: 768px){.modal-grid,.model-badge{grid-template-columns:1fr 1fr}}.section-header{font-size:13px;text-transform:uppercase;letter-spacing:.5px;color:var(--muted);margin:20px 0 10px;font-weight:600}.table-scroll{overflow-x:auto;-webkit-overflow-scrolling:touch}.active-repos-table,.savings-table{width:100%;border-collapse:collapse;font-size:13px}.active-repos-table th,.savings-table th{text-align:left;padding:6px 10px;border-bottom:1px solid var(--border);white-space:nowrap}.active-repos-table th.num,.savings-table th.num{text-align:right}.active-repos-table td,.savings-table td{padding:6px 10px;border-bottom:1px solid var(--border);white-space:nowrap}.active-repos-table td.num,.savings-table td.num{text-align:right;font-family:monospace}.active-repos-table tbody tr:hover,.savings-table tbody tr:hover{background:var(--panel)}.savings-table .repo-model{font-weight:600}.repo-empty{text-align:center;color:var(--muted);padding:24px}.active-repos-section{margin-bottom:8px}.savings-by-model{margin-bottom:16px}@media (max-width: 640px){.active-repos-table{min-width:900px}.savings-table{min-width:1200px}}@media (min-width: 641px) and (max-width: 1024px){.savings-table{min-width:1000px}}.overview-card-grid{grid-template-columns:repeat(auto-fit,minmax(min(100%,320px),1fr))}.ov-stat-row{display:flex;justify-content:space-between;align-items:baseline;padding:4px 0;border-bottom:1px solid var(--border);font-size:clamp(13px,1vw,17px)}.ov-stat-label{color:var(--muted);font-size:12px;cursor:help}.ov-stat-value{font-weight:600;color:var(--text);font-family:monospace}.ov-stat-value-green{color:var(--ok)}.ov-stat-value-yellow{color:var(--warn)}.ov-stat-value-red{color:var(--err)}.ov-value-ok{color:var(--ok)!important}.ov-compression-meter{margin-top:10px}.meter-track{height:clamp(6px,.6vw,10px);background:var(--bg);border-radius:5px;overflow:hidden;border:1px solid var(--border)}.meter-fill{height:100%;transition:width .4s ease;border-radius:4px}.meter-green{background:var(--ok)}.meter-yellow{background:var(--warn)}.meter-red{background:var(--err)}.meter-sub{display:block;margin-top:4px;font-size:11px;color:var(--muted)}.bullet-na .bullet-dot{background:var(--warn);box-shadow:0 0 6px var(--warn)}.bullet-na .bullet-label{color:var(--warn)}.trigger-state-text{margin:6px 0 0;font-size:12px;color:var(--muted)}.data-safety-card .safe-note{margin:10px 0 0;padding:8px;font-size:11px;color:var(--muted);background:#3fb9500f;border-radius:6px;border:1px solid rgba(63,185,80,.2)}.model-cost-card .ov-cost-usd{font-size:clamp(16px,1.4vw,22px);font-weight:700;color:#a371f7;margin-bottom:2px}.model-cost-card .ov-cost-sub{font-size:12px;color:var(--muted);margin-bottom:8px}.crew-card .ov-stat-value{font-family:inherit}.legend-card{grid-column:1 / -1}.legend-card details{cursor:pointer}.legend-card summary{font-size:13px;color:var(--muted);font-weight:600;margin-bottom:4px}.legend-list{margin:8px 0;padding-left:20px;font-size:12px;color:var(--muted);line-height:1.6}.legend-list li{margin-bottom:4px}.legend-list b{color:var(--text)}.legend-note{font-size:11px;color:var(--dim);font-style:italic}.cache-tab{display:flex;flex-direction:column;gap:12px}@media (max-width: 640px){.overview-card-grid{grid-template-columns:1fr}}@media (min-width: 1025px){.overview-card-grid{grid-template-columns:repeat(3,1fr)}}@media (min-width: 1601px){.overview-card-grid{grid-template-columns:repeat(4,1fr);font-size:clamp(13px,.9vw,16px)}}.config-tab{display:flex;flex-direction:column;gap:16px}.config-settings,.config-display{padding:14px 16px;background:var(--panel);border:1px solid var(--border);border-radius:8px}.config-settings h3,.config-display h3{margin:0 0 12px;font-size:clamp(12px,1vw,14px);color:var(--muted);font-weight:600;text-transform:uppercase;letter-spacing:.5px}.settings-row{margin-bottom:10px}.settings-row:last-child{margin-bottom:0}.settings-row label{display:flex;align-items:center;gap:8px;font-size:clamp(13px,.9vw,15px);color:var(--text);cursor:pointer}.settings-row select{padding:4px 8px;font-size:clamp(12px,.85vw,14px);background:var(--bg);color:var(--text);border:1px solid var(--border);border-radius:4px;cursor:pointer}.settings-row select:disabled{opacity:.5;cursor:not-allowed}.settings-row input[type=checkbox]{width:16px;height:16px;cursor:pointer}.config-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,200px),1fr));gap:10px}.config-item{display:flex;flex-direction:column;gap:3px;padding:8px 10px;background:var(--bg);border:1px solid var(--border);border-radius:6px}.config-label{font-size:clamp(11px,.75vw,13px);color:var(--muted);text-transform:uppercase;letter-spacing:.4px}.config-value{font-size:clamp(13px,1vw,16px);font-weight:600;color:var(--text)}.event-category-filter{display:flex;flex-wrap:wrap;gap:6px;align-items:center}.category-chip{padding:3px 10px;font-size:clamp(11px,.75vw,13px);border:1px solid var(--border);background:var(--bg);color:var(--muted);border-radius:12px;cursor:pointer;text-transform:capitalize;transition:color .15s,border-color .15s,background .15s}.category-chip:hover{color:var(--text)}.category-chip.active{color:var(--text);border-color:var(--accent);background:var(--panel)}@media (max-width: 640px){.config-grid{grid-template-columns:1fr}.settings-row label{flex-direction:column;align-items:flex-start;gap:4px}.settings-row select{width:100%}}:root{--mega: #f0883e;--mega-gold: #ffd700;--game-blue: #1f6feb;--game-purple: #a371f7}.game-tab{display:flex;flex-direction:column;gap:12px}.game-mode-on{--accent: var(--mega)}.mega-cache-banner{display:block;background:linear-gradient(135deg,var(--mega),var(--mega-gold));color:#1a1006;font-weight:700;padding:10px 14px;border-radius:8px;margin:12px 0;font-size:clamp(13px,1vw,16px);animation:mega-banner-shimmer 3s ease-in-out infinite}@keyframes mega-banner-shimmer{0%,to{filter:brightness(1)}50%{filter:brightness(1.15)}}.mega-cache-toast{display:none;position:fixed;top:16px;left:50%;transform:translate(-50%);background:var(--mega);color:#1a1006;font-weight:700;padding:10px 18px;border-radius:8px;z-index:1000;box-shadow:0 4px 20px #0008;max-width:92vw}.mega-cache-toast.show{display:block;animation:mega-flash .6s ease-in-out 2}@keyframes mega-flash{0%{background:transparent}25%{background:var(--mega-gold)}to{background:transparent}}.achievement-tile{display:none;background:linear-gradient(135deg,var(--mega),var(--mega-gold));color:#1a1006;font-weight:700;padding:12px 16px;border-radius:8px;margin:12px 0;box-shadow:0 0 16px #f0883e88;font-size:clamp(13px,1vw,16px)}.achievement-tile.unlocked{display:block}.achievement-tile .ach-detail{display:block;font-weight:500;font-size:12px;margin-top:4px}.game-leaderboards{display:grid;grid-template-columns:1fr 1fr;gap:16px;margin-top:16px}.lb-card{background:var(--panel);border:1px solid var(--border);border-radius:8px;padding:14px}.lb-card h3{font-size:12px;text-transform:uppercase;letter-spacing:.5px;color:var(--muted);margin:0 0 10px;font-weight:600;display:flex;align-items:center;gap:4px}.lb-card table{width:100%;border-collapse:collapse;font-size:13px}.lb-card td{padding:4px 8px;border-bottom:1px solid var(--border)}.lb-card td.num{text-align:right;font-family:monospace;color:var(--text);font-weight:600}.lb-card .lb-meta{color:var(--muted);font-size:11px;margin-left:6px}.lb-empty{color:var(--muted);font-size:12px;padding:8px 0}.lvl-badge{display:inline-block;background:var(--game-blue);color:#fff;font-size:11px;font-weight:700;padding:2px 8px;border-radius:10px;margin-left:8px}.repos-badge-line{margin-top:8px}.repos-badge{display:inline-block;background:var(--game-blue);color:#fff;font-size:11px;font-weight:700;padding:2px 8px;border-radius:10px}.game-empty{color:var(--muted);font-style:italic;padding:12px 0}.ach-section{position:relative}.ach-tiles{display:grid;grid-template-columns:repeat(auto-fill,minmax(160px,1fr));gap:8px;margin:8px 0 16px}.ach-tile{padding:10px 12px;border-radius:8px;border:1px solid var(--border);font-size:12px;background:var(--panel)}.ach-tile.unlocked{background:linear-gradient(135deg,var(--mega),var(--mega-gold));color:#1a1006;font-weight:700;box-shadow:0 0 12px #f0883e66}.ach-tile.locked{opacity:.55}.ach-tile.just-unlocked{animation:ach-unlock-pulse .6s ease-out}.ach-tile .ach-detail{display:block;font-weight:500;font-size:11px;margin-top:3px}@keyframes ach-unlock-pulse{0%{transform:scale(.9);opacity:.4}60%{transform:scale(1.05)}to{transform:scale(1);opacity:1}}.ach-toast{display:none;position:fixed;top:16px;left:50%;transform:translate(-50%);background:var(--game-blue);color:#fff;font-weight:700;padding:10px 18px;border-radius:8px;z-index:1000;box-shadow:0 4px 20px #0008;max-width:92vw}.ach-toast.show{display:block}.achievements-tab{display:flex;flex-direction:column;gap:12px}.achievements-tab h2{font-size:clamp(16px,1.4vw,22px);margin:0}@media (max-width: 640px){.game-leaderboards{grid-template-columns:1fr}}@media (min-width: 1601px){.game-leaderboards{gap:20px}}.sessions-tab{display:flex;flex-direction:column;gap:14px}.sessions-toolbar{display:flex;flex-wrap:wrap;align-items:center;gap:8px;padding:8px 0}.sessions-toolbar h2{margin:0;font-size:14px;font-weight:600;color:var(--text)}.sessions-window-select{display:inline-flex;gap:2px;padding:2px;background:var(--panel);border:1px solid var(--border);border-radius:6px}.sessions-window-btn{padding:4px 10px;background:transparent;border:none;border-radius:4px;color:var(--muted);font-size:12px;cursor:pointer;transition:background .15s,color .15s}.sessions-window-btn:hover{color:var(--text)}.sessions-window-btn.active{background:var(--accent);color:#0d1117;font-weight:600}.sessions-summary-tiles{display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));gap:10px}.sessions-chart{background:var(--panel);border:1px solid var(--border);border-radius:8px;padding:12px}.sessions-chart-empty,.sessions-empty{display:flex;align-items:center;justify-content:center;min-height:160px;color:var(--muted);font-size:14px;background:var(--panel);border:1px solid var(--border);border-radius:8px;padding:32px;text-align:center}.sessions-table-scroll{overflow-x:auto;background:var(--panel);border:1px solid var(--border);border-radius:8px}.sessions-table{width:100%;border-collapse:collapse;font-size:13px}.sessions-table th,.sessions-table td{padding:8px 10px;text-align:left;border-bottom:1px solid var(--border);white-space:nowrap}.sessions-table th{font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:.5px;color:var(--muted);background:#ffffff05;position:sticky;top:0}.sessions-table td.num{text-align:right;font-variant-numeric:tabular-nums}.sessions-table tr:last-child td{border-bottom:none}.sessions-table tr:hover td{background:#58a6ff0f}.sessions-empty-row td{color:var(--muted);font-style:italic;text-align:center}.sessions-pct-pill{display:inline-block;padding:2px 8px;border-radius:10px;font-size:11px;font-weight:600;font-variant-numeric:tabular-nums}.sessions-pct-ok{background:#3fb95026;color:var(--ok)}.sessions-pct-warn{background:#d2992226;color:var(--warn)}.sessions-pct-err{background:#f8514926;color:var(--err)}.sessions-sparkline{display:inline-block;vertical-align:middle}.sessions-sparkline-empty{color:var(--muted);font-size:11px}.sessions-meta{font-size:11px;color:var(--muted)}.sessions-footer{font-size:11px;color:var(--muted);margin-top:6px}@media (max-width: 640px){.sessions-summary-tiles{grid-template-columns:1fr}.sessions-table th,.sessions-table td{font-size:12px;padding:6px 8px}}.repo-stack-card{display:flex;flex-direction:column;gap:10px}.repo-stack-card h3{margin:0;font-size:14px;font-weight:600;color:var(--text)}.repo-stack-bar{display:flex;width:100%;height:22px;border-radius:6px;overflow:hidden;border:1px solid var(--border);background:var(--bg)}.repo-stack-segment{height:100%;min-width:2px;transition:opacity .15s,filter .15s}.repo-stack-segment:hover{opacity:.85;filter:brightness(1.15)}.repo-stack-total{font-size:13px;color:var(--text);font-variant-numeric:tabular-nums}.repo-stack-total .pct{color:var(--muted)}.repo-stack-legend{display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:6px}.repo-stack-legend-item{display:flex;align-items:center;gap:6px;font-size:12px;color:var(--muted);font-variant-numeric:tabular-nums}.repo-stack-legend-swatch{flex-shrink:0;width:12px;height:12px;border-radius:3px;border:1px solid var(--border)}.repo-stack-legend-name{color:var(--text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}@media (max-width: 640px){.repo-stack-legend{grid-template-columns:1fr}}.session-gauges-card{grid-column:1 / -1}.session-gauges-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(180px,1fr));gap:14px}.session-gauge{display:flex;flex-direction:column;gap:6px;padding:10px 12px;background:var(--bg);border:1px solid var(--border);border-radius:6px}.session-gauge-self{border-color:var(--accent);box-shadow:0 0 0 1px var(--accent);background:color-mix(in srgb,var(--accent) 8%,var(--bg))}.session-gauge-head{display:flex;justify-content:space-between;align-items:baseline;gap:6px}.session-gauge-label{font-size:12px;font-weight:600;color:var(--text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:70%}.session-gauge-self .session-gauge-label{color:var(--accent)}.session-gauge-pct{font-size:12px;font-weight:600;color:var(--muted);white-space:nowrap}.session-gauges-grid .gauge-bar{height:8px}.session-gauge-sub{margin:0}.session-gauge-meta{margin:0;font-size:11px;color:var(--muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}@media (max-width: 640px){.session-gauges-grid{grid-template-columns:1fr}}.maintenance-tab{display:flex;flex-direction:column;gap:12px}.card-header{font-size:13px;font-weight:600;text-transform:uppercase;letter-spacing:.5px;color:var(--muted);margin-bottom:10px;display:flex;align-items:center;gap:8px}.card-body{font-size:13px}.stat-section{margin-bottom:12px}.stat-section:last-child{margin-bottom:0}.stat-label{font-size:11px;color:var(--muted);text-transform:uppercase;letter-spacing:.4px;margin-bottom:4px}.stat-row{display:flex;justify-content:space-between;align-items:baseline;padding:3px 0;border-bottom:1px solid var(--border);font-size:13px}.num{text-align:right;font-family:monospace;font-weight:600}.compact-table{width:100%;border-collapse:collapse;font-size:13px}.compact-table th{text-align:left;padding:4px 6px;border-bottom:1px solid var(--border);font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:.4px;color:var(--muted)}.compact-table th.num{text-align:right}.compact-table td{padding:3px 6px;border-bottom:1px solid var(--border)}.compact-table td.num{text-align:right;font-family:monospace;font-weight:600}.compact-table tbody tr:last-child td{border-bottom:none}.text-muted{color:var(--muted)}.text-error{color:var(--err)}.text-ok{color:var(--ok)}.text-warn{color:var(--warn)}.text-mono{font-family:monospace;font-size:12px}.badge{display:inline-block;padding:1px 8px;font-size:10px;font-weight:700;border-radius:8px;text-transform:uppercase;letter-spacing:.3px}.badge-ok{background:color-mix(in srgb,var(--ok) 20%,transparent);color:var(--ok);border:1px solid var(--ok)}.badge-bad{background:color-mix(in srgb,var(--err) 20%,transparent);color:var(--err);border:1px solid var(--err)}.badge-warn{background:color-mix(in srgb,var(--warn) 20%,transparent);color:var(--warn);border:1px solid var(--warn)}.action-grid{display:grid;grid-template-columns:1fr;gap:8px}.action-item{display:flex;justify-content:space-between;align-items:center;gap:12px;padding:10px 12px;background:var(--bg);border:1px solid var(--border);border-radius:6px}.action-info{display:flex;flex-direction:column;gap:2px;flex:1;min-width:0}.action-label{font-size:13px;font-weight:600;color:var(--text);display:flex;align-items:center;gap:6px}.action-desc{font-size:11px;color:var(--muted)}.action-result{font-size:11px;margin-top:2px}.action-controls{display:flex;align-items:center;gap:8px;flex-shrink:0}.btn{padding:5px 14px;font-size:12px;font-weight:600;border:none;border-radius:6px;cursor:pointer;white-space:nowrap;transition:opacity .15s}.btn:disabled{opacity:.5;cursor:not-allowed}.btn-primary{background:var(--accent);color:#0d1117}.btn-danger{background:var(--err);color:#fff}.days-input{width:60px;padding:4px 6px;font-size:12px;background:var(--panel);border:1px solid var(--border);border-radius:4px;color:var(--text);text-align:center}.days-input:disabled{opacity:.5}@media (max-width: 640px){.action-item{flex-direction:column;align-items:stretch;gap:8px}.action-controls{justify-content:flex-end}}.ov-stripe-health-summary{display:flex;gap:12px;align-items:center;margin-bottom:12px;font-size:clamp(11px,.85vw,14px);flex-wrap:wrap}.ov-stripe-health-badge{display:inline-block;padding:2px 10px;border-radius:10px;background:var(--panel);border:1px solid var(--border);font-weight:600;text-transform:capitalize}.ov-text-green{color:var(--ok)}.ov-text-yellow{color:var(--warn)}.ov-text-orange{color:#d4761e}.ov-text-red{color:var(--err)}.ov-text-gray,.ov-stripe-health-score,.ov-stripe-churn,.ov-stripe-total{color:var(--muted)}.ov-stripe-bars{display:flex;flex-direction:column;gap:6px}.ov-stripe-row{display:grid;grid-template-columns:80px 1fr 40px 48px;align-items:center;gap:8px;font-size:clamp(11px,.8vw,13px)}.ov-stripe-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--text)}.ov-bar-track{height:18px;background:var(--bg);border-radius:4px;overflow:hidden;position:relative}.ov-bar-fill{height:100%;border-radius:4px;transition:width .5s ease;min-width:2px}.ov-bar-green{background:var(--ok)}.ov-bar-blue{background:var(--accent)}.ov-bar-teal{background:#3d9cb0}.ov-bar-yellow{background:var(--warn)}.ov-bar-gray{background:var(--muted)}.ov-bar-red{background:var(--err)}.ov-bar-orange{background:#d4761e}.ov-bar-latest{box-shadow:0 0 6px #ffffff80}.ov-stripe-count{text-align:right;color:var(--text);font-variant-numeric:tabular-nums}.ov-stripe-stability{color:var(--muted);font-size:clamp(10px,.75vw,12px)}.ov-stripe-footer{margin-top:10px;font-size:clamp(10px,.75vw,12px);color:var(--muted);display:flex;gap:8px}.ov-perf-summary{display:flex;gap:14px;align-items:center;margin-bottom:10px;font-size:clamp(11px,.85vw,14px);flex-wrap:wrap}.ov-perf-stat strong{font-variant-numeric:tabular-nums}.ov-sparkline{display:flex;align-items:flex-end;gap:3px;height:60px;padding:4px 2px;margin-bottom:6px}.ov-sparkline-bar{flex:1;min-width:4px;border-radius:2px 2px 0 0;transition:height .4s ease}.ov-empty-state{font-size:clamp(11px,.8vw,13px);color:var(--muted);padding:16px 0;text-align:center}.ov-card-footer{font-size:clamp(10px,.75vw,12px);color:var(--muted);margin-top:4px}.ov-card{background:var(--panel);border:1px solid var(--border);border-radius:8px;padding:clamp(8px,1.5vw,16px)}.ov-card-title{margin:0 0 10px;font-size:clamp(13px,.9vw,15px);font-weight:600}
|