canopy-engine 0.1.5 → 0.1.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/LICENSE +3 -2
- package/PRIVACY.md +72 -0
- package/README.md +241 -231
- package/dist/canopy.js +92 -82
- package/dist/{chunk-AF33YUHF.js → chunk-4UV7T77F.js} +1 -1
- package/dist/{chunk-JZZ4VDNH.js → chunk-4XUKEJ3C.js} +1 -1
- package/dist/chunk-AGOP4Q7U.js +12 -0
- package/dist/{chunk-3NY67ODS.js → chunk-DRLW6UU3.js} +1 -1
- package/dist/{chunk-NW4RXPYG.js → chunk-F535OXGZ.js} +1 -1
- package/dist/{chunk-SR4HILUN.js → chunk-ILPARXQH.js} +1 -1
- package/dist/chunk-KFBDAACV.js +5 -0
- package/dist/{chunk-5KSCMRFH.js → chunk-LAKMPJML.js} +1 -1
- package/dist/{chunk-OGPL4QTW.js → chunk-MWFO5O33.js} +1 -1
- package/dist/chunk-SVREO35Y.js +5 -0
- package/dist/chunk-TV6NLY7O.js +14 -0
- package/dist/chunk-UTAZPOBT.js +6 -0
- package/dist/{chunk-KGDTP5LR.js → chunk-W57Z6UQP.js} +1 -1
- package/dist/chunk-WALU7QUQ.js +25 -0
- package/dist/chunk-ZE3NJMCS.js +5 -0
- package/dist/chunk-ZF5SEDQB.js +5 -0
- package/dist/chunk-ZQ6F3H6X.js +5 -0
- package/package.json +10 -2
- package/ui-react/dist/bundle.css +1 -1
- package/ui-react/dist/bundle.js +53 -48
- package/dist/chunk-67UE7CV6.js +0 -6
- package/dist/chunk-DVXET5T4.js +0 -5
- package/dist/chunk-LLZJOZFY.js +0 -20
- package/dist/chunk-WCTNLSYC.js +0 -14
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import{fileURLToPath as __cf,pathToFileURL as __cu}from"node:url";import{dirname as __cd,join as __cj}from"node:path";import{createRequire as __cr}from"node:module";
|
|
2
|
+
const require=__cr(import.meta.url);
|
|
3
|
+
globalThis.__canopyBundle??=__cj(__cd(__cf(import.meta.url)),"canopy.js");
|
|
4
|
+
globalThis.__canopyUrl??=(r)=>__cu(__cj(__cd(__cd(globalThis.__canopyBundle)),r)).href;
|
|
5
|
+
import{a as te,b as me}from"./chunk-KFBDAACV.js";import{a as de,e as pe,r as he}from"./chunk-DRLW6UU3.js";import{a as Se}from"./chunk-AGOP4Q7U.js";import{c as we,d as ke}from"./chunk-MWFO5O33.js";import{f as ne,g as oe,i as re,j as se,k as ae,l as ie,m as M,n as ce,o as le}from"./chunk-W57Z6UQP.js";import{e as ue,g as fe}from"./chunk-LAKMPJML.js";import"./chunk-SVREO35Y.js";import{a as ge,c as ye}from"./chunk-F535OXGZ.js";import{a as F}from"./chunk-ZF5SEDQB.js";import"./chunk-ZQ6F3H6X.js";import D from"node:fs";import Ze from"node:http";import E from"node:path";import{spawn as Qe}from"node:child_process";import $e from"node:path";import{execFile as Je}from"node:child_process";function Me(e,t,o){let r=e.length,s=t.length,l=Math.min(r+s,o),i=l+1,g=new Int32Array(2*l+3),m=[];for(let p=0;p<=l;p++){m.push(g.slice());for(let n=-p;n<=p;n+=2){let a=n===-p||n!==p&&g[i+n-1]<g[i+n+1]?g[i+n+1]:g[i+n-1]+1,c=a-n;for(;a<r&&c<s&&e[a]===t[c];)a++,c++;if(g[i+n]=a,a>=r&&c>=s)return Ce(m,r,s,p,i,e,t)}}return null}function Ce(e,t,o,r,s){let l=t,i=o,g=[];for(let m=r;m>0;m--){let p=e[m],n=l-i,a=n===-m||n!==m&&p[s+n-1]<p[s+n+1]?n+1:n-1,c=p[s+a],S=c-a;for(;l>c&&i>S;)g.push(["=",l-1,i-1]),l--,i--;l===c?g.push(["+",-1,i-1]):g.push(["-",l-1,-1]),l=c,i=S}for(;l>0&&i>0;)g.push(["=",l-1,i-1]),l--,i--;return g.reverse()}function De(e,t,{maxD:o=1500}={}){let r=0;for(;r<e.length&&r<t.length&&e[r]===t[r];)r++;let s=0;for(;s<e.length-r&&s<t.length-r&&e[e.length-1-s]===t[t.length-1-s];)s++;let l=e.slice(r,e.length-s),i=t.slice(r,t.length-s),g,m=!1;l.length?i.length?(g=Me(l,i,o),g||(m=!0,g=[...l.map((n,a)=>["-",a,-1]),...i.map((n,a)=>["+",-1,a])])):g=l.map((n,a)=>["-",a,-1]):g=i.map((n,a)=>["+",-1,a]);let p=[];for(let n=0;n<r;n++)p.push(["=",n,n]);for(let[n,a,c]of g)p.push([n,a<0?-1:a+r,c<0?-1:c+r]);for(let n=0;n<s;n++)p.push(["=",e.length-s+n,t.length-s+n]);return{ops:p,coarse:m}}function be(e,t,{aBase:o=1,bBase:r=1,context:s=3,maxD:l}={}){let{ops:i,coarse:g}=De(e,t,l?{maxD:l}:{}),m=[];i.forEach((c,S)=>{c[0]!=="="&&m.push(S)});let p={added:i.filter(c=>c[0]==="+").length,removed:i.filter(c=>c[0]==="-").length};if(!m.length)return{rows:[],stats:p,coarse:g};let n=[];for(let c of m){let S=Math.max(0,c-s),u=Math.min(i.length-1,c+s),f=n[n.length-1];f&&S<=f[1]+1?f[1]=Math.max(f[1],u):n.push([S,u])}let a=[];for(let[c,S]of n){let u=null,f=null,h=0,y=0,v=[];for(let x=c;x<=S;x++){let[k,_,P]=i[x];k!=="+"&&(u==null&&(u=_+1),h++),k!=="-"&&(f==null&&(f=P+1),y++),k==="="?v.push({t:" ",o:o+_,n:r+P,text:e[_]}):k==="-"?v.push({t:"-",o:o+_,n:null,text:e[_]}):v.push({t:"+",o:null,n:r+P,text:t[P]})}u==null&&(u=i.slice(0,c).filter(x=>x[0]!=="+").length),f==null&&(f=i.slice(0,c).filter(x=>x[0]!=="-").length);let T=(x,k)=>k===0?`${x},0`:k===1?`${x}`:`${x},${k}`;a.push({t:"@",header:`@@ -${T(u,h)} +${T(f,y)} @@`,oldStart:u,oldLen:h,newStart:f,newLen:y}),a.push(...v)}return{rows:a,stats:p,coarse:g}}function W(e,t,o=1){let r=e.map((l,i)=>t==="+"?{t:"+",o:null,n:o+i,text:l}:{t:"-",o:o+i,n:null,text:l}),s=t==="+"?`@@ -0,0 +1${e.length===1?"":","+e.length} @@`:`@@ -1${e.length===1?"":","+e.length} +0,0 @@`;return{rows:e.length?[{t:"@",header:s,oldStart:t==="+"?0:1,oldLen:t==="+"?0:e.length,newStart:t==="+"?1:0,newLen:t==="+"?e.length:0},...r]:[],stats:t==="+"?{added:e.length,removed:0}:{added:0,removed:e.length}}}var Ye=5e3,Fe=3*1024*1024,Be="line-level changes need git history",Ge=/^[0-9a-f]{40}$/,ve=/^[1-9][0-9]{0,5}$/,Ue=2e3;function Xe(e=process.env){let t=["PATH","Path","SystemRoot","SYSTEMROOT","windir","TEMP","TMP","TMPDIR","HOME","USERPROFILE","HOMEDRIVE","HOMEPATH","APPDATA","LOCALAPPDATA","COMSPEC","PATHEXT"],o={};for(let r of t)e[r]!==void 0&&(o[r]=e[r]);return{...o,GIT_CONFIG_NOSYSTEM:"1",GIT_TERMINAL_PROMPT:"0",GIT_PAGER:"cat",GIT_OPTIONAL_LOCKS:"0",GIT_ASKPASS:"",LC_ALL:"C"}}function We(e){return typeof e!="string"||!e||e.length>1e3?"not a path":/[\u0000-\u001f\u007f]/.test(e)?"control characters in the path":e.startsWith("-")?"path starts with a dash":$e.isAbsolute(e)||/^[A-Za-z]:/.test(e)||e.startsWith("/")||e.startsWith("\\")||e.split(/[\\/]/).includes("..")?"not a path inside the project":e.split(/[\\/]/).some(t=>oe(t))?"environment, key and certificate files are never served":null}function xe({repoRoot:e,gitFile:t="git",gitPre:o=[],timeoutMs:r=Ye,maxBlob:s=Fe,env:l=Xe()}){let i=new Map;function g(u){if(i.has(u.file))return i.get(u.file);let f=se(e,u),h=new Map;for(let y of f?.nodes??[])h.has(y.id)||h.set(y.id,y);return i.set(u.file,h),i.size>4&&i.delete(i.keys().next().value),h}let m=new Map;function p(u,f){let h=u+":"+f;return m.has(h)?Promise.resolve({ok:!0,buf:m.get(h)}):n(u,f).then(y=>(y.ok&&(m.set(h,y.buf),m.size>24&&m.delete(m.keys().next().value)),y))}function n(u,f){return new Promise(h=>{Je(t,[...o,"--no-pager","cat-file","blob",`${u}:${f}`],{cwd:e,env:l,timeout:r,maxBuffer:s,encoding:"buffer",windowsHide:!0},(y,v)=>{if(!y)return h({ok:!0,buf:v});if(y.killed||y.signal==="SIGTERM"||y.code==="ETIMEDOUT")return h({ok:!1,why:"timeout"});if(String(y.code).includes("MAXBUFFER"))return h({ok:!1,why:"too-large"});h({ok:!1,why:"missing"})})})}function a(u,f,h){let y=u.get(h),v=f.get(h);if(y&&v)return{status:y.bodyHash===v.bodyHash?"unchanged":"modified",oldN:y,newN:v};let T=(x,k)=>x.kind===k.kind&&x.name===k.name&&x.bodyHash===k.bodyHash&&x.filePath!==k.filePath;if(v){let x=[...u.values()].filter(k=>!f.has(k.id)&&T(k,v)).sort((k,_)=>k.id<_.id?-1:1)[0];return x?{status:"moved",oldN:x,newN:v}:{status:"added",oldN:null,newN:v}}if(y){let x=[...f.values()].filter(k=>!u.has(k.id)&&T(y,k)).sort((k,_)=>k.id<_.id?-1:1)[0];return x?{status:"moved",oldN:y,newN:x}:{status:"removed",oldN:y,newN:null}}return null}let c=u=>u&&Number.isInteger(u.startLine)&&u.startLine>0&&Number.isInteger(u.endLine)&&u.endLine>=u.startLine?[u.startLine,u.endLine]:null;async function S(u,f,h){try{if(typeof u!="string"||!u||u.length>Ue)return{status:400,body:{ok:!1,code:"bad-request",message:"node must be a node id"}};if(!ve.test(String(f))||!ve.test(String(h)))return{status:400,body:{ok:!1,code:"bad-request",message:"from and to must be version numbers"}};let y=re(e),v=y?.versions?.find(O=>String(O.version)===String(f)),T=y?.versions?.find(O=>String(O.version)===String(h));if(!v||!T)return{status:404,body:{ok:!1,code:"unknown-version",message:"no such stored version"}};let x=g(v),k=g(T),_=a(x,k,u);if(!_)return{status:404,body:{ok:!1,code:"unknown-node",message:"no such node in these versions"}};let{status:P,oldN:I,newN:w}=_;for(let O of[I,w]){let A=O&&We(O.filePath);if(A)return{status:403,body:{ok:!1,code:"refused",message:"refused: "+A}}}let d={nodeId:u,status:P,from:v.version,to:T.version,oldFile:I?.filePath??null,newFile:w?.filePath??null,oldRange:c(I),newRange:c(w),name:(w??I).name},H=[];I&&v.dirty&&H.push(v.version),w&&T.dirty&&!H.includes(T.version)&&H.push(T.version);let b=H.length?"approximate: taken with uncommitted changes":null,N=(O,A="")=>({status:200,body:{ok:!0,mode:"node-only",reason:O,message:Be+A,approximate:b,...d}});if(P==="unchanged")return{status:200,body:{ok:!0,mode:"lines",rows:[],stats:{added:0,removed:0},formattingOnly:!1,approximate:b,message:"this function did not change between these versions",...d}};let L=[];I&&L.push(["old",v.headSha,I.filePath]),w&&L.push(["new",T.headSha,w.filePath]);for(let[,O]of L)if(typeof O!="string"||!Ge.test(O))return N("no-git");let $=await Promise.all(L.map(([,O,A])=>p(O,A))),R={};for(let O=0;O<L.length;O++){let A=$[O];if(!A.ok)return A.why==="too-large"?{status:200,body:{ok:!0,mode:"node-only",reason:"too-large",message:"this file is too large to diff here",approximate:b,...d}}:N(A.why==="timeout"?"timeout":"missing-commit");if(A.buf.subarray(0,8e3).includes(0))return{status:403,body:{ok:!1,code:"binary",message:"refused: binary file"}};R[L[O][0]]=A.buf.toString("utf8")}let U=O=>{let A=O.replace(/\r\n/g,`
|
|
6
|
+
`).split(`
|
|
7
|
+
`);return A.length>1&&A[A.length-1]===""&&A.pop(),A},z=(O,A)=>{let X=U(O);if(!A)return{lines:X,base:1,clamped:!1};let Le=A[1]>X.length;return{lines:X.slice(A[0]-1,A[1]),base:A[0],clamped:Le}},J=R.old!=null?z(R.old,d.oldRange):{lines:[],base:1,clamped:!1},Y=R.new!=null?z(R.new,d.newRange):{lines:[],base:1,clamped:!1},V=R.old!=null&&R.new!=null&&R.old!==R.new&&U(R.old).join(`
|
|
8
|
+
`)===U(R.new).join(`
|
|
9
|
+
`)&&/\r\n/.test(R.old)!==/\r\n/.test(R.new),Z={...d,approximate:b??(J.clamped||Y.clamped?"approximate: the stored line range no longer fits the file":null)};if(J.lines.length>5e3||Y.lines.length>5e3)return{status:200,body:{ok:!0,mode:"node-only",reason:"too-large",message:`too large to diff here (more than ${5e3} lines on one side)`,...Z}};let C;P==="added"?C=W(Y.lines,"+",Y.base):P==="removed"?C=W(J.lines,"-",J.base):C=be(J.lines,Y.lines,{aBase:J.base,bBase:Y.base});let Q=O=>O.join(`
|
|
10
|
+
`).replace(/\s+/g,""),ee=P!=="added"&&P!=="removed"&&C.stats.added+C.stats.removed>0&&Q(J.lines)===Q(Y.lines);return{status:200,body:{ok:!0,mode:"lines",rows:C.rows,stats:C.stats,coarse:!!C.coarse,formattingOnly:ee,eolOnly:V,...Z,message:V?"line endings changed":P==="moved"&&!C.rows.length?"moved to another file, the code is the same":ee?"formatting only":null}}}catch{return{status:500,body:{ok:!1,code:"error",message:"the diff could not be computed"}}}}return{diff:S}}async function Ne(e,t,{token:o,service:r}){let s=M(e,o);if(s)return s;let l=[...t.searchParams.keys()],i=["node","from","to"].every(g=>t.searchParams.getAll(g).length===1);return l.length!==3||!i?{status:400,body:{ok:!1,code:"bad-request",message:"send exactly three parameters: node=<node id>&from=<version>&to=<version>"}}:r.diff(t.searchParams.get("node"),t.searchParams.get("from"),t.searchParams.get("to"))}function Oe({now:e=Date.now,holdMs:t=Number(process.env.CANOPY_SEEN_HOLD_MS)||6e4,staleMs:o=null,commit:r}){let s=o??Math.max(t*.75,2e3),l=null,i=null,g=!1;return{ping(){let m=e();l===null&&(l=m),i=m},check(){if(g||l===null)return!1;let m=e();return m-l>=t&&m-i<=s?(g=!0,r(),!0):!1},flush(){return g||l===null?!1:(g=!0,r(),!0)},get acknowledged(){return l!==null},get committed(){return g}}}import Ae from"node:fs";import Pe from"node:path";import Te from"node:crypto";var qe="x-canopy-nav-token",Ke=168*3600*1e3,ze=(e,t)=>{let o=Buffer.from(String(e??"")),r=Buffer.from(String(t??""));return o.length===r.length&&o.length>0&&Te.timingSafeEqual(o,r)},_e=()=>Te.randomBytes(24).toString("hex");function Ee({navToken:e,searchService:t,repoRoot:o}){let r=new Set,s=setInterval(()=>{for(let p of r)try{p.write(`: ping
|
|
11
|
+
|
|
12
|
+
`)}catch{r.delete(p)}},25e3);s.unref?.();let l=p=>{let n=0,a=`data: ${JSON.stringify(p)}
|
|
13
|
+
|
|
14
|
+
`;for(let c of r)try{c.write(a),n++}catch{r.delete(c)}return n};function i(p,n,a){let c=M(p,a);if(c){n.writeHead(c.status,{"content-type":"application/json","cache-control":"no-store"}).end(JSON.stringify(c.body));return}n.writeHead(200,{"content-type":"text/event-stream; charset=utf-8","cache-control":"no-store",connection:"keep-alive","x-accel-buffering":"no"}),n.write(`: ready
|
|
15
|
+
|
|
16
|
+
`),r.add(n),p.on("close",()=>r.delete(n))}function g(p){return new Promise(n=>{let a=(f,h)=>n({status:f,body:h});if(p.method!=="POST")return a(405,{ok:!1,code:"method",message:"POST only"});if(p.headers.origin!==void 0)return a(403,{ok:!1,code:"origin",message:"refused: a request from a web page"});if(!ze(p.headers[qe],e))return a(403,{ok:!1,code:"token",message:"missing or wrong navigation token"});let c=[],S=0,u=!1;p.on("data",f=>{S+=f.length,S>4096?(u=!0,a(413,{ok:!1,code:"too-large",message:"request too large"}),p.destroy()):c.push(f)}),p.on("end",()=>{if(u)return;let f;try{f=JSON.parse(Buffer.concat(c).toString("utf8"))}catch{return a(400,{ok:!1,code:"bad-request",message:"send JSON"})}let h=f&&typeof f=="object"&&!Array.isArray(f)?Object.keys(f):[];if(h.length!==2||!h.includes("kind")||!h.includes("id")||typeof f.id!="string"||f.id.length>2e3)return a(400,{ok:!1,code:"bad-request",message:"send { kind, id }"});let y=t.prepared();if(!y)return a(409,{ok:!1,code:"no-index",message:"no map yet"});if(f.kind==="node")return y.nodeDoc.has(f.id)?a(200,{ok:!0,delivered:l({type:"navigate",nodeId:f.id})}):a(404,{ok:!1,code:"unknown-id",message:"unknown node id"});if(f.kind==="workflow"){let v=/^workflow:(\d{1,7})$/.exec(f.id),T=v?Number(v[1]):-1;return T<0||T>=y.workflows.length?a(404,{ok:!1,code:"unknown-id",message:"unknown workflow id"}):a(200,{ok:!0,delivered:l({type:"navigate",workflowIndex:T})})}return a(400,{ok:!1,code:"bad-request",message:"kind is node or workflow"})}),p.on("error",()=>a(400,{ok:!1,code:"bad-request",message:"unreadable request"}))})}function m(p,n){let a=M(p,n);if(a)return a;let c=!1,S=!1;try{o&&(c=Date.now()-Ae.statSync(Pe.join(o,".canopy","mcp-seen.json")).mtimeMs<Ke)}catch{}try{o&&(S=JSON.parse(Ae.readFileSync(Pe.join(o,".canopy","prefs.json"),"utf8"))?.experimentalDeepLinks===!0)}catch{}return{status:200,body:{ok:!0,mcpRecent:c,deepLinks:S,root:o||null}}}return{events:i,navigate:g,ai:m,send:l,close(){clearInterval(s);for(let p of r)try{p.end()}catch{}r.clear()}}}var Ve=16*1024,Re={"cache-control":"no-store"};function j(e,t,o){e.writeHead(t,{"content-type":"application/json; charset=utf-8",...Re,...t>=400?{connection:"close"}:{}}).end(JSON.stringify(o))}function G(e){return new Promise(t=>{let o=[],r=0,s=!1;e.on("data",l=>{r+=l.length,!s&&(r>Ve?(s=!0,t({tooLarge:!0})):o.push(l))}),e.on("end",()=>{s||t({text:Buffer.concat(o).toString("utf8")})}),e.on("error",()=>{s||t({text:""})})})}var je=new Set(["/api/ai/status","/api/ai/ask","/api/ai/cancel","/api/ai/reset","/api/ai/use"]);async function Ie(e,t,o,{token:r,service:s}){let l=e!=="/api/ai/status",i=M(t,r,l?"POST":"GET");if(i)return t.resume(),j(o,i.status,i.body);if(l&&!/^application\/json\b/i.test(String(t.headers["content-type"]??"")))return t.resume(),j(o,415,{ok:!1,code:"content-type",message:"send application/json"});if(e==="/api/ai/status")return j(o,200,await s.status());if(e==="/api/ai/use"){let c=await G(t);if(c.tooLarge)return j(o,413,{ok:!1,code:"too-large",message:"The request is too large."});let S;try{S=JSON.parse(c.text)}catch{return j(o,400,{ok:!1,code:"bad-request",message:"send JSON"})}let u=S&&typeof S=="object"&&!Array.isArray(S)?Object.keys(S):[];if(c.tooLarge||u.length!==1||!["candidate","path"].includes(u[0])||typeof S[u[0]]!="string")return j(o,400,{ok:!1,code:"bad-request",message:"send { candidate } or { path }"});let f=await s.use(S);return j(o,f.status,f.body)}if(e==="/api/ai/cancel")return await G(t),j(o,200,{ok:!0,cancelled:s.cancel()});if(e==="/api/ai/reset"){await G(t);let c=s.reset();return j(o,c.ok?200:409,c.ok?{ok:!0}:{ok:!1,code:"busy",message:"A question is still running. Cancel it first."})}let g=await G(t);if(g.tooLarge)return j(o,413,{ok:!1,code:"too-large",message:"The request is too large."});let m;try{m=JSON.parse(g.text)}catch{return j(o,400,{ok:!1,code:"bad-request",message:"send JSON"})}let p=m&&typeof m=="object"&&!Array.isArray(m)?Object.keys(m):[];if(p.length!==1||p[0]!=="question"||typeof m.question!="string")return j(o,400,{ok:!1,code:"bad-request",message:"send { question }"});let n=s.start(m.question);if(n.error)return j(o,n.error.status,{ok:!1,code:n.error.code,message:n.error.message});o.writeHead(200,{"content-type":"text/event-stream; charset=utf-8",...Re,connection:"keep-alive","x-accel-buffering":"no"});let a=!1;o.on("close",()=>{a||s.cancel()});try{for await(let c of n.events)o.writable&&o.write(`data: ${JSON.stringify(c)}
|
|
17
|
+
|
|
18
|
+
`)}catch{o.writable&&o.write(`data: ${JSON.stringify({type:"error",code:"failed",message:"Canopy could not finish the request."})}
|
|
19
|
+
|
|
20
|
+
`)}finally{a=!0,n.release(),o.end()}}var K={".html":"text/html; charset=utf-8",".js":"text/javascript; charset=utf-8",".json":"application/json",".css":"text/css",".svg":"image/svg+xml",".png":"image/png",".woff2":"font/woff2",".map":"application/json"};function He(e,t,o){let r=E.join(e,E.normalize(t).replace(/^([/\\]|\.\.[/\\])+/,""));if(!r.startsWith(e+E.sep)&&r!==e){o.writeHead(403).end("forbidden");return}D.readFile(r,(s,l)=>{if(s){o.writeHead(404,{"content-type":"text/plain"}).end("not found: "+t);return}o.writeHead(200,{"content-type":K[E.extname(r).toLowerCase()]??"application/octet-stream","cache-control":"no-store"}).end(l)})}var B=(()=>{try{return JSON.parse(D.readFileSync(E.join(F,"package.json"),"utf8")).version}catch{return null}})();function et({env:e=process.env,version:t=B,kind:o=ye()}={}){return e.CANOPY_NO_UPDATE_CHECK==="1"||e.CANOPY_NO_UPDATE_CHECK==="true"||o!=="installed"||!/^\d+\.\d+\.\d+(-[0-9A-Za-z.-]+)?$/.test(String(t))?"":`<meta name="canopy-update-check" content="${ge}" data-current="${t}">`}function tt(e,t,o){D.readFile(E.join(e,"index.html"),"utf8",(r,s)=>{if(r){t.writeHead(404,{"content-type":"text/plain"}).end("not found: index.html");return}t.writeHead(200,{"content-type":K[".html"],"cache-control":"no-store"}).end(o?s.replace("</head>",o+`
|
|
21
|
+
</head>`):s)})}var $t=()=>{let e=E.join(F,"ui-react");return!D.existsSync(E.join(e,"index.html"))||!D.existsSync(E.join(e,"dist"))?`this install has no built viewer (ui-react/dist is missing)
|
|
22
|
+
fix: reinstall canopy from a build that includes the viewer`:null};function nt(){try{let e=JSON.parse(D.readFileSync(E.join(F,"package.json"),"utf8")).canopyFeedbackUrl;return typeof e=="string"&&/^https:\/\/[^\s"<>]+$/.test(e)?e:null}catch{return null}}function ot(e,t){if(t)return t;try{return JSON.parse(D.readFileSync(E.join(e,"meta.json"),"utf8")).repoRoot??null}catch{return null}}function rt(e,{argv1:t=process.argv[1],env:o=process.env}={}){let r={};for(let s of["CANOPY_OUTPUT_DIR","CANOPY_CACHE_DIR"])o[s]&&(r[s]=o[s]);return{command:process.execPath,args:[t,"mcp",e,"--ai-panel"],env:{...r,CANOPY_NO_RESPAWN:"1",CANOPY_NO_UPDATE_CHECK:"1"}}}async function Jt(e,t=0,{updateTag:o=et(),repoRoot:r=null,token:s=ne(),navToken:l=_e(),diffOptions:i={},aiOptions:g={},telemetry:m=te({version:B??"unknown"})}={}){e=E.resolve(e);let p=E.join(F,"ui-react"),n=ot(e,r)??"",a=ae({outDir:e,repoRoot:n}),c=xe({repoRoot:n,...i}),S=we({repoRoot:n,outDir:e}),u=Ee({navToken:l,searchService:S,repoRoot:n||null}),f=n?Se({repoRoot:n,searchService:S,mcp:rt(n),onAsk:w=>m?.askAiUsed(w),...g}):null;m.record("viewer_opened");let h=(w,d)=>w.writeHead(d.status,{"content-type":"application/json; charset=utf-8","cache-control":"no-store"}).end(JSON.stringify(d.body)),y=nt(),v=B?me({version:B}):null,T=`<meta name="canopy-session" content="${s}">`+(v?`
|
|
23
|
+
<meta name="canopy-feedback-mail" content="${v}">`:"")+(y?`
|
|
24
|
+
<meta name="canopy-feedback" content="${y}">`:""),x=new Map,k=n?Oe({commit:()=>{try{let w=fe(n),d=w.versions[w.versions.length-1];d&&pe(n,d,{branch:ue(n,["rev-parse","--abbrev-ref","HEAD"])})}catch{}}}):null,_=0,P=Ze.createServer((w,d)=>{if(!ie(w,_)){d.writeHead(403,{"content-type":"text/plain","cache-control":"no-store"}).end("forbidden");return}let H;try{H=new URL(w.url??"/","http://127.0.0.1")}catch{d.writeHead(400).end("bad request");return}let b;try{b=decodeURIComponent(H.pathname)}catch{d.writeHead(400).end("bad request");return}if(b==="/api/source"){let N=le(w,H,{port:_,token:s,service:a});h(d,N);return}if(b==="/api/health"){let N=null;try{N=n?de(n)?.projectId??null:null}catch{}h(d,{status:200,body:{ok:!0,app:"canopy",version:B,pid:process.pid,projectId:N}});return}if(b==="/api/seen"){let N=M(w,s,"POST");if(N){h(d,N);return}k?.ping(),h(d,{status:200,body:{ok:!0}});return}if(b==="/output/history.js"&&n&&D.existsSync(E.join(n,".canopy","history","index.json"))){let N=null;try{N=he(n,{sinceCache:x})}catch{N=null}if(N){d.writeHead(200,{"content-type":K[".js"],"cache-control":"no-store"}).end(N);return}}if(b==="/api/search"||b==="/api/grep"||b==="/api/entrypoints"){ke(b.slice(5),w,H,{token:s,service:S}).then(N=>h(d,N),()=>h(d,{status:500,body:{ok:!1,code:"error",message:"the search failed"}}));return}if(b==="/api/events"){u.events(w,d,s);return}if(b==="/api/navigate"){u.navigate(w).then(N=>h(d,N),()=>h(d,{status:500,body:{ok:!1,code:"error",message:"failed"}}));return}if(b==="/api/telemetry"){let N=M(w,s,"POST");if(N){h(d,N);return}let L="";w.on("data",$=>{L.length<512&&(L+=$)}),w.on("end",()=>{try{let $=JSON.parse(L);$&&typeof $.event=="string"&&m.recordBrowser($.event)}catch{}h(d,{status:200,body:{ok:!0}})});return}if(je.has(b)){if(!f){h(d,{status:404,body:{ok:!1,code:"no-project",message:"no project"}});return}Ie(b,w,d,{token:s,service:f}).catch(()=>{try{d.destroy()}catch{}});return}if(b==="/api/ai"){h(d,u.ai(w,s));return}if(b==="/api/nodes"){h(d,ce(w,H,{token:s,service:a}));return}if(b==="/api/diff"){Ne(w,H,{token:s,service:c}).then(N=>h(d,N),()=>h(d,{status:500,body:{ok:!1,code:"error",message:"the diff could not be computed"}}));return}if(b==="/"||b==="/index.html"){d.writeHead(302,{location:"/ui-react/index.html"}).end();return}if(b==="/ui-react/index.html")return tt(p,d,T+(o?`
|
|
25
|
+
`+o:""));if(b.startsWith("/ui-react/"))return He(p,b.slice(10),d);if(b.startsWith("/output/"))return He(e,b.slice(8),d);d.writeHead(404).end("not found")});await new Promise((w,d)=>{P.once("error",d),P.listen(t,"127.0.0.1",w)}),_=P.address().port;let I=null;if(k){I=setInterval(()=>{try{k.check()}catch{}},2e3),I.unref?.();let w=P.close.bind(P);P.close=d=>{clearInterval(I);try{k.flush()}catch{}return w(d)},process.once("exit",d=>{if(d===0||d===130||d===143)try{k.flush()}catch{}})}{let w=P.close.bind(P);P.close=d=>(u.close(),f?.cancel(),m.flush(),w(d))}return{server:P,port:_,url:`http://127.0.0.1:${_}/`,token:s,navToken:l,seen:k}}function Yt(e){if(process.env.CANOPY_NO_BROWSER)return!1;try{let t,o;if(process.platform==="win32")t="cmd.exe",o=["/c","start","",e];else if(process.platform==="darwin")t="open",o=[e];else if(process.env.DISPLAY||process.env.WAYLAND_DISPLAY)t="xdg-open",o=[e];else return!1;let r=Qe(t,o,{detached:!0,stdio:"ignore",windowsHide:!0});return r.on("error",()=>{}),r.unref(),!0}catch{return!1}}export{rt as aiMcpLauncher,Yt as openBrowser,Jt as startViewer,et as updateMetaTag,$t as viewerProblem};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import{fileURLToPath as __cf,pathToFileURL as __cu}from"node:url";import{dirname as __cd,join as __cj}from"node:path";import{createRequire as __cr}from"node:module";
|
|
2
|
+
const require=__cr(import.meta.url);
|
|
3
|
+
globalThis.__canopyBundle??=__cj(__cd(__cf(import.meta.url)),"canopy.js");
|
|
4
|
+
globalThis.__canopyUrl??=(r)=>__cu(__cj(__cd(__cd(globalThis.__canopyBundle)),r)).href;
|
|
5
|
+
import{a as s}from"./chunk-AGOP4Q7U.js";import"./chunk-SVREO35Y.js";import"./chunk-ZQ6F3H6X.js";async function d(o,r={}){let e=await s({repoRoot:o,searchService:{prepared:()=>null},...r}).status(),t=e.version?` (v${e.version})`:"";return e.state==="ready"&&e.source?`Ask AI: Using Claude Code from ${e.source.label}${t}`:e.state==="needs_approval"?`Ask AI: Found Claude Code from ${e.offer?.label??"an editor"}${t}. Open the Ask AI panel in the viewer and press Allow to use it.`:e.state==="unsupported"?`Ask AI: this Claude Code is too old${t}; update it.`:"Ask AI: Claude Code was not found. Install it (https://docs.claude.com/en/docs/claude-code/setup) or set CANOPY_CLAUDE_BIN to its full path."}export{d as describeClaude};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import{fileURLToPath as __cf,pathToFileURL as __cu}from"node:url";import{dirname as __cd,join as __cj}from"node:path";import{createRequire as __cr}from"node:module";
|
|
2
|
+
const require=__cr(import.meta.url);
|
|
3
|
+
globalThis.__canopyBundle??=__cj(__cd(__cf(import.meta.url)),"canopy.js");
|
|
4
|
+
globalThis.__canopyUrl??=(r)=>__cu(__cj(__cd(__cd(globalThis.__canopyBundle)),r)).href;
|
|
5
|
+
import s from"node:fs";import o from"node:path";import{fileURLToPath as d}from"node:url";var r=o.join(o.dirname(d(globalThis.__canopyUrl("src/utils/pkgPath.js"))),"..","..");function f(i){let n=o.join(r,"vendor",i);if(l()&&s.existsSync(n))return n;for(let e=r;;e=o.dirname(e)){let t=o.join(e,"node_modules",i);if(s.existsSync(t))return t;if(o.dirname(e)===e)break}return o.join(r,"node_modules",i)}var l=()=>r.split(o.sep).includes("node_modules");export{r as a,f as b,l as c};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import{fileURLToPath as __cf,pathToFileURL as __cu}from"node:url";import{dirname as __cd,join as __cj}from"node:path";import{createRequire as __cr}from"node:module";
|
|
2
|
+
const require=__cr(import.meta.url);
|
|
3
|
+
globalThis.__canopyBundle??=__cj(__cd(__cf(import.meta.url)),"canopy.js");
|
|
4
|
+
globalThis.__canopyUrl??=(r)=>__cu(__cj(__cd(__cd(globalThis.__canopyBundle)),r)).href;
|
|
5
|
+
var g=Object.create;var f=Object.defineProperty;var h=Object.getOwnPropertyDescriptor;var i=Object.getOwnPropertyNames;var j=Object.getPrototypeOf,k=Object.prototype.hasOwnProperty;var m=(b,a)=>()=>{try{return a||b((a={exports:{}}).exports,a),a.exports}catch(c){throw a=0,c}};var l=(b,a,c,e)=>{if(a&&typeof a=="object"||typeof a=="function")for(let d of i(a))!k.call(b,d)&&d!==c&&f(b,d,{get:()=>a[d],enumerable:!(e=h(a,d))||e.enumerable});return b};var n=(b,a,c)=>(c=b!=null?g(j(b)):{},l(a||!b||!b.__esModule?f(c,"default",{value:b,enumerable:!0}):c,b));export{m as a,n as b};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "canopy-engine",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.7",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Canopy: a map of what a JavaScript / TypeScript codebase does - entry points, call flows and services, drawn from the code itself.",
|
|
6
6
|
"keywords": [
|
|
@@ -34,6 +34,7 @@
|
|
|
34
34
|
"!ui-react/dist/*.map",
|
|
35
35
|
"README.md",
|
|
36
36
|
"FEEDBACK.md",
|
|
37
|
+
"PRIVACY.md",
|
|
37
38
|
"LICENSE"
|
|
38
39
|
],
|
|
39
40
|
"engines": {
|
|
@@ -82,7 +83,14 @@
|
|
|
82
83
|
"test:diff": "node test/diff-endpoint.js",
|
|
83
84
|
"test:respawn": "node test/respawn.js",
|
|
84
85
|
"test:term": "node test/term.js",
|
|
85
|
-
"test:state": "node test/state.js"
|
|
86
|
+
"test:state": "node test/state.js",
|
|
87
|
+
"test:ai": "node test/ai.js",
|
|
88
|
+
"test:queues-base": "node test/queue-base-links.js",
|
|
89
|
+
"test:ai-prompt": "node test/ai-prompt.js",
|
|
90
|
+
"test:ai-answer": "node test/ai-answer.js",
|
|
91
|
+
"test:ai-detect": "node test/ai-detect.js",
|
|
92
|
+
"test:telemetry": "node test/telemetry.js",
|
|
93
|
+
"ai:eval-notes": "node scripts/ai-eval-notes.js"
|
|
86
94
|
},
|
|
87
95
|
"dependencies": {
|
|
88
96
|
"web-tree-sitter": "0.26.12"
|
package/ui-react/dist/bundle.css
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
@font-face{font-family:Inter;font-style:normal;font-weight:400 700;font-display:swap;src:url("./fonts/Inter-latin-var.woff2") format("woff2")}@font-face{font-family:JetBrains Mono;font-style:normal;font-weight:400 700;font-display:swap;src:url("./fonts/JetBrainsMono-latin-var.woff2") format("woff2")}:root{--paper: #f3efe3;--paper-raised: #faf7ee;--paper-hover: #eee7d4;--contour: #d9d0ba;--ink: #2b2a22;--ink-dim: #6b664f;--ink-faint: #a39a7d;--shadow-sm: 0 1px 2px rgba(40, 35, 20, .06), 0 2px 6px rgba(40, 35, 20, .05);--shadow-md: 0 2px 4px rgba(40, 35, 20, .07), 0 8px 20px rgba(40, 35, 20, .09);--shadow-lg: 0 4px 10px rgba(40, 35, 20, .1), 0 18px 38px rgba(40, 35, 20, .14);--accent-client: #4f7a5c;--accent-client-bg: #e4ecdf;--accent-server: #9a5b32;--accent-server-bg: #f1e2cf;--accent-unknown: #6b5a8f;--accent-unknown-bg: #e7e1ef;--accent-cross: #4a6480;--accent-cross-bg: #dfe6ec;--font-ui: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;--font-mono: "JetBrains Mono", "SF Mono", Consolas, monospace}*{box-sizing:border-box}html,body,#root{height:100%;margin:0}body{font-family:var(--font-ui);color:var(--ink);background:radial-gradient(ellipse 100% 70% at 50% -10%,#f8f4e8,#efe8d5 55%,#e4dabf);overflow:hidden}.canopy-app{height:100vh;display:flex;flex-direction:column}.canopy-topbar{display:flex;align-items:center;justify-content:space-between;padding:14px 22px;border-bottom:1px solid var(--contour);background:var(--paper-raised);box-shadow:0 1px #28231408,0 2px 10px #2823140d;z-index:10;position:relative}.canopy-brand{font-family:var(--font-ui);font-weight:700;font-size:16px;letter-spacing:-.01em;color:var(--ink);display:flex;align-items:center;gap:7px}.canopy-brand .leaf{color:var(--accent-client);font-size:15px}.canopy-crumbs{display:flex;align-items:center;gap:5px;font-size:13px}.crumb{padding:4px 9px;border-radius:6px;cursor:pointer;color:var(--ink-dim);font-weight:500;transition:background .15s ease,color .15s ease}.crumb:hover{background:var(--paper-hover);color:var(--ink)}.crumb.current{color:var(--ink);font-weight:700;cursor:default;font-size:14px}.crumb.current:hover{background:none}.crumb-sep{color:var(--ink-faint);font-size:11px}.canopy-hint{font-size:11.5px;color:var(--ink-faint);margin-top:1px;font-weight:500}.picker-entry-btn{font-family:var(--font-mono);font-size:11px;font-weight:600;color:var(--accent-cross);background:var(--accent-cross-bg);border:1px solid var(--accent-cross);border-radius:7px;padding:6px 11px;cursor:pointer;transition:background .15s ease}.picker-entry-btn:hover{background:var(--accent-cross);color:var(--paper-raised)}.canopy-stats{display:flex;gap:18px}.stat{text-align:right}.stat-num{font-size:17px;font-weight:700;line-height:1;color:var(--ink);font-variant-numeric:tabular-nums}.stat-label{font-size:9.5px;text-transform:uppercase;letter-spacing:.06em;color:var(--ink-faint);font-weight:600;margin-top:2px}.canopy-canvas{flex:1;position:relative}.react-flow__attribution{display:none}.react-flow__controls{box-shadow:var(--shadow-md);border-radius:10px;overflow:hidden;border:1px solid var(--contour)}.react-flow__controls-button{background:var(--paper-raised);border-bottom:1px solid var(--contour);color:var(--ink-dim);width:30px;height:30px}.react-flow__controls-button:hover{background:var(--paper-hover);color:var(--ink)}.react-flow__controls-button svg{fill:currentColor}.react-flow__minimap{border-radius:10px;box-shadow:var(--shadow-md);border:1px solid var(--contour);overflow:hidden}.group-bg{width:100%;height:100%;border-radius:20px;background:#96855414;border:1px dashed rgba(110,95,55,.18);pointer-events:none}.v-scrollbar-track{position:absolute;top:10px;bottom:30px;right:4px;width:10px;border-radius:6px;background:#b4a88a29;z-index:5;cursor:pointer}.v-scrollbar-thumb{position:absolute;left:0;width:100%;border-radius:6px;background:var(--ink-faint);opacity:.55;cursor:grab;transition:opacity .15s ease,background .15s ease}.v-scrollbar-thumb:hover{opacity:.85;background:var(--ink-dim)}.v-scrollbar-thumb:active{cursor:grabbing;opacity:1}.react-flow__edge-path{stroke-linecap:round}.react-flow__edge.same-service .react-flow__edge-path{stroke:var(--ink-dim);stroke-width:2px}.react-flow__edge.cross-service .react-flow__edge-path{stroke:var(--accent-cross);stroke-width:2.2px;stroke-dasharray:7 5}.react-flow__edge.service-link .react-flow__edge-path{stroke:var(--accent-cross);stroke-width:2.4px;stroke-dasharray:8 6}.card{background:var(--paper-raised);border-radius:12px;box-shadow:var(--shadow-sm);transition:box-shadow .18s ease,transform .18s ease;border:1px solid rgba(40,35,20,.06)}.card:hover{box-shadow:var(--shadow-lg);transform:translateY(-2px)}.svc-node{width:240px;padding:18px 20px;cursor:pointer}.svc-kind{display:inline-block;font-size:9.5px;font-weight:700;text-transform:uppercase;letter-spacing:.07em;padding:3px 9px;border-radius:5px}.svc-name{font-size:19px;font-weight:700;margin-top:10px;letter-spacing:-.01em;color:var(--ink)}.svc-meta{font-family:var(--font-mono);font-size:10.5px;color:var(--ink-dim);margin-top:6px}.svc-badges{display:flex;gap:6px;margin-top:11px;flex-wrap:wrap}.svc-badge{font-family:var(--font-mono);font-size:9px;font-weight:600;background:var(--accent-cross-bg);color:var(--accent-cross);border-radius:4px;padding:2px 7px}.wf-node{width:100%;height:100%;padding:14px 18px;cursor:pointer;display:flex;align-items:center;gap:14px}.wf-dot{width:9px;height:9px;border-radius:50%;flex-shrink:0}.wf-body{flex:1;min-width:0}.wf-name{font-size:14.5px;font-weight:650;color:var(--ink);line-height:1.3;overflow-wrap:break-word;word-break:normal}.wf-meta{font-family:var(--font-mono);font-size:10.5px;color:var(--ink-faint);margin-top:4px}.wf-chevron{color:var(--ink-faint);font-size:18px;flex-shrink:0}.minor-panel{position:absolute;left:50%;bottom:22px;transform:translate(-50%);z-index:15;width:460px;max-width:calc(100% - 44px);background:var(--paper-raised);border:1px solid var(--contour);border-radius:12px;box-shadow:var(--shadow-md);overflow:hidden}.minor-toggle{width:100%;border:none;background:none;cursor:pointer;padding:11px 18px;display:flex;align-items:center;justify-content:space-between;font-family:var(--font-mono);font-size:11.5px;font-weight:600;color:var(--ink-dim)}.minor-toggle:hover{color:var(--ink);background:var(--paper-hover)}.minor-caret{color:var(--ink-faint);font-size:10px}.minor-list{max-height:260px;overflow-y:auto;border-top:1px solid var(--contour)}.minor-item{padding:8px 18px;font-size:12px;color:var(--ink-dim);cursor:pointer;border-bottom:1px solid rgba(40,35,20,.05);display:flex;justify-content:space-between;gap:10px}.minor-item:last-child{border-bottom:none}.minor-item:hover{background:var(--paper-hover);color:var(--ink)}.minor-item .minor-file{font-family:var(--font-mono);font-size:9.5px;color:var(--ink-faint);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex-shrink:1}.context-rail{position:absolute;top:14px;left:10px;z-index:8;width:190px;max-height:calc(100% - 28px);overflow-y:auto;display:flex;flex-direction:column;gap:12px}.context-group{background:var(--paper-raised);border:1px solid var(--contour);border-radius:10px;padding:9px 10px;box-shadow:var(--shadow-sm)}.context-label{font-family:var(--font-mono);font-size:8.5px;font-weight:700;text-transform:uppercase;letter-spacing:.05em;color:var(--ink-faint);margin-bottom:6px}.context-chip{font-size:11px;font-weight:600;color:var(--ink);background:var(--paper);border:1px solid var(--contour);border-radius:6px;padding:5px 8px;margin-top:4px;cursor:pointer;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;transition:background .15s ease}.context-chip:first-child{margin-top:0}.context-chip:hover{background:var(--paper-hover)}.context-more{font-family:var(--font-mono);font-size:9.5px;color:var(--ink-faint);margin-top:4px}.step-node{width:100%;height:100%;min-height:90px;padding:18px;box-sizing:border-box;overflow:visible;position:relative}.step-node.root{border-color:var(--accent-client);box-shadow:0 0 0 1.5px var(--accent-client),var(--shadow-sm)}.step-node.active-expanded:not(.root){border-color:var(--accent-cross);box-shadow:0 0 0 1.5px var(--accent-cross),var(--shadow-sm)}.step-top{display:flex;align-items:center;gap:6px;flex-wrap:wrap}.step-badge{font-family:var(--font-mono);font-size:9px;font-weight:700;background:var(--ink);color:var(--paper);border-radius:4px;padding:1.5px 6px;flex-shrink:0}.step-cat{font-family:var(--font-mono);font-size:8px;font-weight:700;border-radius:4px;padding:1.5px 6px;flex-shrink:0;text-transform:uppercase;letter-spacing:.03em}.step-name{font-size:13px;font-weight:650;color:var(--ink);line-height:1.3;flex:1;min-width:60px;overflow-wrap:break-word;word-break:normal}.step-file{font-family:var(--font-mono);font-size:8.5px;color:var(--ink-faint);margin-top:5px;overflow-wrap:break-word;word-break:normal}.step-expand{margin-top:8px;font-family:var(--font-mono);font-size:10px;font-weight:600;border:1px solid var(--contour);background:var(--paper);color:var(--ink-dim);border-radius:6px;padding:3px 9px;cursor:pointer;transition:background .15s ease,color .15s ease,border-color .15s ease}.step-expand:hover{background:var(--paper-hover);color:var(--ink)}.step-expand.open{background:var(--ink);color:var(--paper);border-color:var(--ink)}.react-flow__edge.secondary-link .react-flow__edge-path{stroke:var(--ink-faint);stroke-dasharray:3 4;stroke-width:1.3}.source-icon{border:none;background:var(--paper);color:var(--ink-faint);font-family:var(--font-mono);font-size:9.5px;font-weight:700;border-radius:4px;padding:1px 5px;cursor:pointer;flex-shrink:0;margin-left:auto}.source-icon:hover{background:var(--ink);color:var(--paper)}.detail-source{font-family:var(--font-mono);font-size:11px;line-height:1.55;color:var(--ink);background:var(--paper);border:1px solid var(--contour);border-radius:8px;padding:10px 12px;margin-top:6px;white-space:pre-wrap;word-break:break-word;overflow-wrap:break-word;word-break:normal}.source-unavailable{color:var(--accent-server);font-style:italic}.recursive-badge{margin-top:7px;font-family:var(--font-mono);font-size:9.5px;font-weight:700;color:var(--accent-server);background:var(--accent-server-bg);border-radius:5px;padding:3px 7px;display:inline-block}.runtime-bucket{width:100%;padding:16px;border:1px dashed var(--contour);background:var(--paper);box-sizing:border-box;max-height:270px;overflow-y:auto}.runtime-bucket-header{font-family:var(--font-mono);font-size:8.5px;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--ink-faint);padding:2px 8px 6px}.runtime-bucket-item{display:flex;flex-direction:column;align-items:flex-start;gap:3px;padding:6px 8px;font-size:10.5px;color:var(--ink-dim)}.runtime-bucket-item.inline{padding:5px 0}.runtime-bucket-item-row{display:flex;align-items:center;gap:6px;width:100%}.runtime-bucket-label{flex:1;min-width:60px;overflow-wrap:break-word;word-break:normal;font-family:var(--font-mono)}.runtime-tag{font-family:var(--font-mono);font-size:8px;font-weight:700;border-radius:4px;padding:1.5px 5px;flex-shrink:0;text-transform:uppercase;letter-spacing:.02em}.runtime-tag-unresolvable-call-site{background:var(--accent-unknown-bg);color:var(--accent-unknown)}.runtime-tag-runtime-dispatched{background:var(--accent-cross-bg);color:var(--accent-cross)}.runtime-tag-return-value{background:var(--accent-client-bg);color:var(--accent-client)}.runtime-bucket.nested-bucket{margin:0}.inline-call{width:100%;height:100%;padding:16px;display:flex;flex-direction:column;align-items:flex-start;gap:3px;border:1px solid var(--contour);background:var(--paper);box-sizing:border-box;font-size:10.5px;color:var(--ink-dim)}.branch-diagram{width:100%;padding:4px 10px;border:1.5px solid var(--accent-cross);box-sizing:border-box}.branch-diagram.nested{border-width:1px;box-shadow:none;padding:3px 8px}.branch-condition{display:flex;align-items:center;gap:7px;padding-bottom:2px;border-bottom:1px dashed var(--contour)}.branch-condition-kind{font-family:var(--font-mono);font-size:8px;font-weight:700;text-transform:uppercase;letter-spacing:.05em;background:var(--accent-cross-bg);color:var(--accent-cross);border-radius:4px;padding:2px 6px;flex-shrink:0}.branch-condition-text{font-family:var(--font-mono);font-size:11.5px;font-weight:650;color:var(--ink);overflow-wrap:break-word;word-break:normal;flex:1;min-width:80px}.branch-outcomes{display:flex;flex-direction:row;align-items:flex-start;gap:18px;margin-top:4px;overflow-x:visible}.branch-outcome{display:flex;flex-direction:row;align-items:flex-start;gap:8px;min-width:150px;flex-shrink:0}.branch-arrow-row{display:flex;align-items:center;gap:5px;height:12px}.branch-arrow-svg{height:10px}.branch-arrow-label{font-family:var(--font-mono);font-size:9px;font-weight:700;color:var(--accent-cross);text-transform:uppercase;flex-shrink:0}.branch-chain-lane{display:flex;flex-direction:column;gap:3px;min-width:0}.branch-empty{font-family:var(--font-mono);font-size:10px;color:var(--ink-faint);font-style:italic;padding:4px 0}.step-body-contained{margin-top:14px;padding-top:12px;border-top:1px dashed var(--contour)}.chain-row{position:relative;min-width:0}.branch-step-chip{display:flex;align-items:center;gap:6px;background:var(--paper);border:1px solid var(--contour);border-radius:6px;padding:6px 9px;cursor:pointer;transition:background .15s ease,border-color .15s ease}.branch-step-chip:hover{background:var(--paper-hover)}.branch-step-chip.promoted{border-color:var(--accent-cross);border-style:dashed;background:var(--accent-cross-bg)}.branch-step-name{font-size:11.5px;font-weight:600;color:var(--ink);flex:1;min-width:40px;overflow-wrap:break-word;word-break:normal}.promoted-hint{font-family:var(--font-mono);font-size:8.5px;font-weight:600;color:var(--accent-cross);flex-shrink:0}.empty-state{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);text-align:center;color:var(--ink-faint);font-family:var(--font-mono);font-size:12.5px;max-width:320px;line-height:1.6;pointer-events:none}.empty-state .glyph{font-size:26px;margin-bottom:10px;opacity:.55}.detail-panel{position:absolute;top:0;right:0;height:100%;width:320px;background:var(--paper-raised);border-left:1px solid var(--contour);box-shadow:-8px 0 26px #2823141f;padding:24px 22px;overflow-y:auto;transform:translate(0);animation:panelIn .22s cubic-bezier(.22,.9,.3,1) both;z-index:20}@keyframes panelIn{0%{transform:translate(16px);opacity:0}to{transform:translate(0);opacity:1}}.detail-close{position:absolute;top:16px;right:16px;border:none;background:none;cursor:pointer;font-size:15px;color:var(--ink-faint)}.detail-close:hover{color:var(--ink)}.detail-label{font-size:9.5px;text-transform:uppercase;letter-spacing:.07em;color:var(--ink-faint);font-weight:700;margin-top:18px;margin-bottom:5px}.detail-label:first-of-type{margin-top:8px}.detail-name{font-size:18px;font-weight:700;margin-top:20px;color:var(--ink)}.detail-mono{font-family:var(--font-mono);font-size:11.5px;color:var(--ink-dim);word-break:break-all;line-height:1.5}.detail-note{font-size:12.5px;color:var(--ink-dim);line-height:1.5}@keyframes nodeFadeIn{0%{opacity:0}to{opacity:1}}.react-flow__node{animation:nodeFadeIn .18s ease both}@keyframes cardIn{0%{transform:scale(.92) translateY(6px)}to{transform:scale(1) translateY(0)}}.react-flow__node .card{animation:cardIn .22s cubic-bezier(.22,.9,.3,1) both}.inferred-badge{display:inline-block;margin-left:8px;padding:1px 6px;border-radius:8px;font-size:9px;font-weight:600;letter-spacing:.02em;text-transform:uppercase;background:#ece6d2;color:#7a7355;border:1px dashed #b8ae8a;vertical-align:middle}.runtime-bucket-item.compact{flex-direction:row;align-items:center;gap:8px;height:24px;padding:0 2px;box-sizing:border-box;cursor:pointer}.runtime-bucket-item.compact:hover{background:#00000009}.compact-dot{width:7px;height:7px;padding:0;border-radius:50%;flex:0 0 7px}.compact-label{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0;max-width:420px;font-size:10.5px}.branch-arrow-label{line-height:24px;min-width:42px}.changes-btn{border:1px solid var(--contour);background:var(--paper-raised);color:var(--ink);font-family:var(--font-mono);font-size:11px;font-weight:700;border-radius:8px;padding:6px 12px;cursor:pointer}.changes-btn.active,.changes-btn:hover{background:var(--ink);color:var(--paper)}.changes-btn-count{margin-left:7px;background:#c8892c;color:#fff;border-radius:9px;padding:0 6px;font-size:10px}.changes-panel{position:fixed;top:76px;right:12px;bottom:12px;width:440px;z-index:30;overflow-y:auto;background:var(--paper-raised);border:1px solid var(--contour);border-radius:12px;box-shadow:0 10px 40px #3c321438;padding:14px 16px 18px}.chg-empty{font-size:14px;font-weight:600;color:var(--ink);margin:14px 0 8px}.chg-stepper{display:flex;align-items:center;gap:10px;margin:8px 0 10px}.chg-stepper button{width:30px;height:30px;border-radius:8px;border:1px solid var(--contour);background:var(--paper);font-size:18px;cursor:pointer;color:var(--ink)}.chg-stepper button:disabled{opacity:.3;cursor:default}.chg-ver{flex:1;min-width:0;text-align:center}.chg-ver-title{font-family:var(--font-mono);font-weight:700;font-size:14px;color:var(--ink)}.chg-ver-sha{font-weight:500;color:var(--ink-faint);font-size:11px;margin-left:4px}.chg-dirty{color:#c8892c}.chg-ver-msg{font-size:12px;color:var(--ink);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.chg-ver-meta{font-size:10px;color:var(--ink-faint);font-family:var(--font-mono)}.chg-summary{display:flex;flex-direction:column;gap:3px;font-family:var(--font-mono);font-size:11px;color:var(--ink-dim);padding:8px 10px;background:var(--paper);border-radius:8px;margin-bottom:10px}.chg-summary b{color:var(--ink)}.chg-section{margin-top:8px}.chg-section-head{width:100%;display:flex;align-items:center;gap:8px;border:none;background:none;cursor:pointer;font-family:var(--font-mono);font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:.05em;color:var(--ink-dim);padding:4px 0;border-bottom:1px dashed var(--contour)}.chg-section-head .chg-count{background:var(--paper);border-radius:8px;padding:0 6px;color:var(--ink)}.chg-section-head .chg-caret{margin-left:auto}.chg-section-body{padding-top:4px}.chg-wf{padding:6px 8px;border-radius:8px;cursor:pointer;border:1px solid transparent}.chg-wf:hover{background:var(--paper);border-color:var(--contour)}.chg-wf.gone{cursor:default;opacity:.6}.chg-wf-name{font-size:12px;font-weight:650;color:var(--ink);display:flex;align-items:center;gap:6px;flex-wrap:wrap}.chg-wf-why{font-family:var(--font-mono);font-size:10px;color:var(--ink-dim);margin-top:2px;overflow-wrap:anywhere}.chg-svc{font-family:var(--font-mono);font-size:9px;color:var(--ink-faint);margin-left:auto}.chg-tag{font-family:var(--font-mono);font-size:8px;font-weight:700;text-transform:uppercase;border-radius:4px;padding:1px 5px;background:#ece6d2;color:#7a7355}.chg-tag-new{background:#dcefd9;color:#2f6a2a}.chg-tag-removed{background:#f3d9d4;color:#8a3326}.chg-tag-changed{background:#f3e6c4;color:#85601a}.chg-row{font-family:var(--font-mono);font-size:10.5px;color:var(--ink);padding:2px 4px;overflow-wrap:anywhere}.chg-row .chg-sign{display:inline-block;width:14px;font-weight:700}.chg-row.add .chg-sign{color:#2f6a2a}.chg-row.del .chg-sign{color:#8a3326}.chg-row.mod .chg-sign{color:#85601a}.chg-row.mv .chg-sign{color:#4a6480}.chg-file{display:block;margin-left:14px;color:var(--ink-faint);font-size:9.5px}.chg-more,.chg-info{font-size:10px;color:var(--ink-faint);padding:4px}.chg-info{margin-top:12px;border-top:1px dashed var(--contour);padding-top:8px}.change-badge{font-family:var(--font-mono);font-size:8px;font-weight:800;letter-spacing:.04em;border-radius:4px;padding:1px 5px;margin-left:6px;flex-shrink:0}.change-badge-new{background:#2f8a3a;color:#fff}.change-badge-modified{background:#c8892c;color:#fff}.canopy-topbar{flex-wrap:wrap;gap:8px 18px;align-items:flex-start;padding:10px 16px}.topbar-title{flex:1 1 280px;min-width:0}.topbar-controls{display:flex;flex-wrap:wrap;align-items:center;justify-content:flex-end;gap:8px 10px;margin-left:auto;min-width:0}.tb-group{display:inline-flex;gap:4px}.tb-btn{font-family:var(--font-mono);font-size:11px;font-weight:700;color:var(--ink);background:var(--paper-raised);border:1px solid var(--contour);border-radius:7px;padding:6px 10px;min-width:30px;cursor:pointer;white-space:nowrap;transition:background .12s ease}.tb-btn:hover:not(:disabled){background:var(--paper-hover)}.tb-btn.active{background:var(--ink);color:var(--paper)}.tb-btn:disabled{opacity:.4;cursor:default}.changes-btn{white-space:nowrap}.picker-entry-btn{white-space:nowrap;max-width:100%;overflow:hidden;text-overflow:ellipsis}@media(max-width:1100px){.canopy-stats{display:none}}@media(max-width:1000px){.canopy-hint{display:none}}.canopy-body{flex:1;display:flex;min-height:0;position:relative}.canopy-canvas{flex:1;position:relative;min-width:0}.side-panel{background:var(--paper-raised);border-right:1px solid var(--contour);min-height:0}.side-panel.docked{flex:0 0 260px;width:260px;position:relative;display:flex;flex-direction:column;transition:flex-basis .15s ease,width .15s ease}.side-panel.docked.collapsed{flex-basis:30px;width:30px}.side-scroll{overflow-y:auto;flex:1;padding:10px 12px 14px 10px;display:flex;flex-direction:column;gap:10px;min-height:0}.side-title{font-family:var(--font-mono);font-size:9.5px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:var(--ink-faint);padding-right:26px;display:flex;justify-content:space-between;align-items:center}.side-handle{position:absolute;top:6px;right:4px;width:22px;height:22px;border-radius:6px;border:1px solid var(--contour);background:var(--paper);color:var(--ink-dim);cursor:pointer;z-index:2;line-height:1;font-size:14px;padding:0}.side-panel.docked.collapsed .side-handle{right:3px}.side-handle:hover{background:var(--paper-hover)}.side-panel.drawer{position:absolute;top:0;bottom:0;left:0;width:270px;max-width:86%;z-index:26;display:flex;flex-direction:column;transform:translate(-104%);visibility:hidden;transition:transform .18s ease,visibility 0s linear .18s;box-shadow:var(--shadow-lg)}.side-panel.drawer.open{transform:none;visibility:visible;transition:transform .18s ease}.side-scrim{position:absolute;inset:0;z-index:25;background:#2823142e}.side-close{border:none;background:none;cursor:pointer;color:var(--ink-dim);font-size:13px;padding:0 2px}.side-groups{display:flex;flex-direction:column;gap:12px}.canopy-edge-path{fill:none;stroke:var(--ink-dim);stroke-width:2px;stroke-linecap:round;stroke-linejoin:round;transition:opacity .12s ease,stroke-width .12s ease}.react-flow__edge.cross-service .canopy-edge-path{stroke:var(--accent-cross);stroke-dasharray:7 5}.canopy-edge-path.hl{stroke:#c8892c;stroke-width:3px;stroke-dasharray:none}.canopy-edge-path.dim{opacity:.14}.v-scrollbar-track.minimap-open{bottom:196px}.h-scrollbar-track{position:absolute;left:10px;right:30px;bottom:4px;height:10px;border-radius:6px;background:#b4a88a29;z-index:5;cursor:pointer}.h-scrollbar-track.minimap-open{right:230px}.h-scrollbar-thumb{position:absolute;top:0;height:100%;border-radius:6px;background:var(--ink-faint);opacity:.55;cursor:grab;transition:opacity .15s ease,background .15s ease}.h-scrollbar-thumb:hover{opacity:.85;background:var(--ink-dim)}.h-scrollbar-thumb:active{cursor:grabbing;opacity:1}.react-flow__minimap{margin:14px 14px 18px}.step-expand.step-toggle{width:22px;height:22px;min-width:22px;padding:0;margin:0;display:inline-flex;align-items:center;justify-content:center;border-radius:6px;font-size:12px;line-height:1;border:1px solid var(--contour);background:var(--paper);color:var(--ink-dim);cursor:pointer;flex:0 0 22px}.step-expand.step-toggle:hover{background:var(--paper-hover);color:var(--ink)}.step-expand.step-toggle.open{background:var(--paper);color:var(--ink)}.chip-more{margin-left:auto;font-family:var(--font-mono);font-size:9px;font-weight:700;color:var(--accent-cross);background:var(--accent-cross-bg);border-radius:8px;padding:0 6px}.seg{display:inline-flex;border:1px solid var(--contour);border-radius:8px;overflow:hidden;width:100%}.seg button{flex:1;border:none;background:var(--paper);color:var(--ink-dim);font-family:var(--font-mono);font-size:10.5px;font-weight:700;padding:6px 8px;cursor:pointer}.seg button+button{border-left:1px solid var(--contour)}.seg button.on{background:var(--ink);color:var(--paper)}.step-node.selected-entry{border-color:var(--accent-cross);box-shadow:0 0 0 2px var(--accent-cross),var(--shadow-md)}.step-node.parent-card{border-style:dashed;background:var(--paper)}.caller-tag{font-family:var(--font-mono);font-size:8px;font-weight:800;letter-spacing:.05em;text-transform:uppercase;color:var(--accent-cross);background:var(--accent-cross-bg);border-radius:4px;padding:1px 5px}.excerpt-gap{font-family:var(--font-mono);font-size:9.5px;color:var(--ink-faint);padding:2px 4px;height:20px;line-height:16px}.branch-step-chip.call-target{background:var(--accent-cross-bg);border-color:var(--accent-cross);border-style:solid;box-shadow:0 0 0 1.5px var(--accent-cross)}.context-chip-node{display:flex;align-items:center;justify-content:center;width:100%;height:100%;border:1px dashed var(--accent-cross);background:var(--accent-cross-bg);box-shadow:none;padding:0 12px}.context-chip-text{font-family:var(--font-mono);font-size:11px;font-weight:700;color:var(--accent-cross)}.trigger-node{display:flex;align-items:center;gap:8px;width:100%;height:100%;padding:0 12px;background:var(--paper-raised);border:1px solid var(--accent-cross)}.trigger-node.inferred{border-style:dashed;color:var(--ink-dim)}.trigger-kind{font-family:var(--font-mono);font-size:8.5px;font-weight:800;letter-spacing:.05em;text-transform:uppercase;background:var(--accent-cross-bg);color:var(--accent-cross);border-radius:4px;padding:2px 6px;flex-shrink:0}.trigger-label{font-family:var(--font-mono);font-size:11px;font-weight:600;color:var(--ink);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}[data-lod=compact] .step-node .step-file,[data-lod=compact] .step-node .step-cat,[data-lod=compact] .step-node .source-icon,[data-lod=compact] .step-node .change-badge,[data-lod=compact] .step-node .caller-tag,[data-lod=compact] .step-node .chip-more,[data-lod=compact] .step-node .promoted-hint,[data-lod=compact] .step-node .excerpt-gap,[data-lod=compact] .step-node .branch-condition-text,[data-lod=compact] .step-node .branch-condition-kind,[data-lod=compact] .step-node .branch-arrow-label,[data-lod=compact] .step-node .branch-step-name,[data-lod=compact] .step-node .compact-label,[data-lod=compact] .step-node .compact-dot,[data-lod=compact] .step-node .runtime-bucket-header,[data-lod=compact] .step-node .runtime-tag{visibility:hidden}[data-lod=compact] .step-node .branch-step-chip{background:var(--accent-cross-bg);border-color:var(--accent-cross)}[data-lod=compact] .step-node .branch-step-chip.promoted{background:var(--accent-cross)}[data-lod=compact] .step-node .runtime-bucket-item.compact{background:var(--accent-unknown-bg);border-radius:4px}[data-lod=compact] .step-node .runtime-bucket-item.compact:has(.runtime-tag-runtime-dispatched){background:var(--accent-cross-bg)}[data-lod=compact] .step-node .runtime-bucket-item.compact:has(.runtime-tag-return-value){background:var(--accent-client-bg)}[data-lod=compact] .step-node .branch-diagram{background:var(--paper)}[data-lod=compact] .step-node .step-name,[data-lod=boxes] .step-node .step-name{transform:scale(var(--inv-zoom, 1));transform-origin:left center;max-width:calc(100% / var(--inv-zoom, 1));white-space:nowrap;overflow:hidden;text-overflow:ellipsis;display:block;font-weight:700;position:relative;z-index:2}[data-lod=boxes] .step-node .step-body-contained,[data-lod=boxes] .step-node .step-file,[data-lod=boxes] .step-node .step-cat,[data-lod=boxes] .step-node .source-icon,[data-lod=boxes] .step-node .change-badge,[data-lod=boxes] .step-node .caller-tag,[data-lod=boxes] .step-node .step-badge,[data-lod=boxes] .step-node .step-toggle{visibility:hidden}[data-lod=boxes] .step-node{background:var(--paper-raised)}.back-btn{margin-right:4px;padding:4px 9px}.side-sub{font-size:11.5px;line-height:1.4;color:var(--ink-dim);margin:-4px 0 2px;padding-right:6px}.react-flow__edge.hop-solid .canopy-edge-path{stroke-dasharray:none}.react-flow__edge.hop-dashed .canopy-edge-path{stroke-dasharray:7 5}.react-flow__edge.hop-solid .canopy-edge-path:not(.hl),.react-flow__edge.hop-dashed .canopy-edge-path:not(.hl){stroke:var(--accent-cross);stroke-width:2.2px}.hop-node{width:100%;height:100%;padding:7px 10px 8px;display:flex;flex-direction:column;gap:2px;cursor:pointer;background:var(--accent-cross-bg);border:1.5px solid var(--accent-cross);overflow:hidden}.hop-node.hop-dashed{border-style:dashed}.hop-top{display:flex;align-items:center;justify-content:space-between;gap:6px}.hop-svc{font-family:var(--font-mono);font-size:9px;font-weight:700;text-transform:uppercase;letter-spacing:.03em;color:var(--accent-cross);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}.hop-tag{font-family:var(--font-mono);font-size:8px;font-weight:700;text-transform:uppercase;border-radius:4px;padding:1px 5px;background:var(--paper-raised);color:var(--ink-dim);flex-shrink:0}.hop-tag-exact,.hop-tag-resolved{color:var(--accent-client)}.hop-call{font-family:var(--font-mono);font-size:10.5px;font-weight:700;color:var(--ink);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.hop-handler{font-family:var(--font-mono);font-size:9.5px;color:var(--ink-dim);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-height:12px}.hop-view{align-self:flex-start;margin-top:auto;border:1px solid var(--accent-cross);background:var(--paper-raised);color:var(--accent-cross);border-radius:6px;font-size:10px;font-weight:600;padding:2px 8px;cursor:pointer}.hop-view:hover{background:var(--paper-hover)}.called-from-chip{display:block;max-width:100%;margin-top:4px;border:1px solid var(--accent-cross);background:var(--accent-cross-bg);color:var(--accent-cross);border-radius:999px;font-family:var(--font-mono);font-size:9.5px;font-weight:600;padding:2px 9px;cursor:pointer;text-align:left;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.called-from-chip:hover{background:var(--paper-hover)}.hop-chooser{position:fixed;z-index:200;width:284px;background:var(--paper-raised);border:1px solid var(--contour);border-radius:10px;box-shadow:var(--shadow-lg);padding:6px;display:flex;flex-direction:column;gap:2px}.hop-chooser-label{font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:.04em;color:var(--ink-faint);padding:2px 6px 4px}.hop-chooser-item{display:flex;flex-direction:column;align-items:flex-start;text-align:left;border:none;background:none;border-radius:6px;padding:5px 8px;cursor:pointer}.hop-chooser-item:hover{background:var(--paper-hover)}.hop-chooser-title{font-family:var(--font-mono);font-size:11px;font-weight:600;color:var(--ink);max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.hop-chooser-sub{font-size:10px;color:var(--ink-dim)}.hop-chooser-more{font-size:10.5px;color:var(--ink-dim);padding:3px 8px;font-style:italic}[data-lod=compact] .hop-node .hop-handler,[data-lod=compact] .hop-node .hop-view,[data-lod=compact] .hop-node .hop-tag,[data-lod=boxes] .hop-node .hop-handler,[data-lod=boxes] .hop-node .hop-view,[data-lod=boxes] .hop-node .hop-tag,[data-lod=boxes] .hop-node .hop-call,[data-lod=boxes] .called-from-chip{visibility:hidden}.canopy-topbar{flex-wrap:nowrap;align-items:center;gap:10px 14px;padding:8px 16px}.canopy-crumbs{flex:1 1 auto;min-width:0;overflow:hidden;flex-wrap:nowrap;white-space:nowrap}button.crumb{background:none;border:none;font:inherit;font-size:13px;font-weight:500}.crumb{max-width:220px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:0 1 auto}.crumb.current{max-width:320px}.topbar-controls{flex:0 0 auto;flex-wrap:nowrap;gap:6px 8px}.icon-btn{position:relative;display:inline-flex;align-items:center;justify-content:center;gap:4px;min-width:32px;height:30px;padding:0 8px;border:1px solid var(--contour);border-radius:7px;background:var(--paper-raised);color:var(--ink);cursor:pointer;transition:background .12s ease}.icon-btn:hover{background:var(--paper-hover)}.icon-btn.active{background:var(--ink);color:var(--paper)}.icon-btn .changes-btn-count{margin-left:0}button:focus-visible,[role=button]:focus-visible,.search-input:focus-visible,.code-box:focus-visible,a:focus-visible{outline:2px solid var(--accent-cross);outline-offset:2px}.search{position:relative;flex:0 1 340px;min-width:150px}.search-input{width:100%;box-sizing:border-box;height:30px;padding:0 10px;border:1px solid var(--contour);border-radius:7px;background:var(--paper);color:var(--ink);font:12px var(--font-ui)}.search-input::placeholder{color:var(--ink-faint)}.search-results{position:absolute;top:34px;left:0;width:min(520px,calc(100vw - 32px));max-height:60vh;overflow-y:auto;z-index:45;background:var(--paper-raised);border:1px solid var(--contour);border-radius:10px;box-shadow:var(--shadow-lg);padding:6px}.search-group-title{font-family:var(--font-mono);font-size:9.5px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:var(--ink-faint);padding:6px 8px 3px}.search-item{display:flex;align-items:baseline;gap:10px;padding:5px 8px;border-radius:6px;cursor:pointer}.search-item.active,.search-item:hover{background:var(--paper-hover)}.search-name{font-size:12.5px;font-weight:600;color:var(--ink);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;flex:0 1 auto;max-width:55%}.search-meta{font-family:var(--font-mono);font-size:10px;color:var(--ink-faint);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0;margin-left:auto}.search-empty{padding:10px;font-size:12px;color:var(--ink-dim)}.modebar{display:flex;align-items:center;gap:12px;padding:6px 16px;background:var(--paper-raised);border-bottom:1px solid var(--contour)}.mode-toggle{width:auto}.mode-toggle button{flex:none;padding:5px 14px}.disclaimer-bar{padding:5px 16px;font-size:12px;line-height:1.4;color:var(--ink-dim);background:var(--accent-cross-bg);border-bottom:1px solid var(--contour)}.disclaimer-bar a{color:var(--accent-cross);font-weight:700}button.context-chip{display:block;width:100%;text-align:left;font-family:inherit}.context-chip.current{background:var(--ink);color:var(--paper);border-color:var(--ink)}.context-chip.current:hover{background:var(--ink)}.code-overlay{flex:0 0 440px;width:440px;min-width:0;min-height:0;display:flex;flex-direction:column;background:var(--paper-raised);border-left:1px solid var(--contour);box-shadow:-8px 0 26px #2823141a;z-index:22}.ov-head{display:flex;align-items:flex-start;gap:8px;padding:12px 14px 8px;border-bottom:1px solid var(--contour)}.ov-title{flex:1;min-width:0}.ov-name{font-size:15px;font-weight:700;color:var(--ink);word-break:break-word}.ov-file{font-family:var(--font-mono);font-size:11px;color:var(--ink-dim);margin-top:2px;word-break:break-all}.ov-close{border:none;background:none;cursor:pointer;font-size:15px;color:var(--ink-faint);padding:4px 6px;border-radius:6px}.ov-close:hover{color:var(--ink);background:var(--paper-hover)}.ov-scroll{flex:1;min-height:0;overflow-y:auto;padding:8px 14px 18px}.ov-section{margin-top:12px}.ov-label{font-size:9.5px;text-transform:uppercase;letter-spacing:.07em;color:var(--ink-faint);font-weight:700;margin-bottom:5px}.ov-count{margin-left:4px;background:var(--paper);border-radius:8px;padding:0 6px;color:var(--ink-dim)}.ov-note{font-size:12px;color:var(--ink-dim);line-height:1.5}.ov-warn{color:#8a3326}.ov-removed-note{display:inline-block;font-weight:700;color:#8a3326;background:#f3d9d4;border-radius:6px;padding:3px 9px;margin-bottom:8px}.ov-meta{font-family:var(--font-mono);font-size:11px;color:var(--ink-dim);word-break:break-all;line-height:1.6}.ov-meta b{color:var(--ink);margin-right:6px}.ov-edge-ends{display:flex;align-items:center;gap:6px;flex-wrap:wrap;margin-bottom:4px}.ov-arrow{color:var(--ink-faint)}.code-box{max-height:46vh;overflow:auto;background:var(--paper);border:1px solid var(--contour);border-radius:8px;font-family:var(--font-mono);font-size:11.5px;line-height:1.55;position:relative}.code-line{display:flex;white-space:pre}.code-no{flex:0 0 46px;text-align:right;padding-right:10px;color:var(--ink-faint);user-select:none;background:var(--paper-raised);position:sticky;left:0}.code-text{padding-right:12px;color:var(--ink)}.code-line.in-range{background:#c8892c29}.code-line.in-range .code-no{color:var(--ink);font-weight:700;background:#c8892c38}.ov-item{display:flex;align-items:baseline;gap:8px;width:100%;text-align:left;font:inherit;font-size:12px;color:var(--ink);background:var(--paper);border:1px solid var(--contour);border-radius:6px;padding:5px 8px;margin-top:4px;cursor:pointer}.ov-item:hover{background:var(--paper-hover)}.ov-item.dashed{border-style:dashed}.ov-i-name{font-weight:600;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ov-i-meta{margin-left:auto;font-family:var(--font-mono);font-size:9.5px;color:var(--ink-faint);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:55%}.chg-group-title{font-family:var(--font-mono);font-size:9.5px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:var(--ink-faint);margin:12px 0 2px}.chg-row.clickable{cursor:pointer;border-radius:6px;padding:3px 6px}.chg-row.clickable:hover{background:var(--paper)}.chg-row.chg-open-wf{color:var(--accent-cross);font-weight:700}.chg-section-head .chg-tag{margin-left:2px}.has-overlay .changes-panel{right:452px}@media(max-width:1099px){.code-overlay{position:fixed;left:0;right:0;bottom:0;width:auto;flex:none;height:58vh;border-left:none;border-top:1px solid var(--contour);border-radius:12px 12px 0 0;box-shadow:0 -10px 30px #2823142e;z-index:36}.code-box{max-height:30vh}.has-overlay .changes-panel{right:12px}.changes-panel{z-index:40}}@media(max-width:820px){.canopy-topbar{flex-wrap:wrap}.canopy-crumbs{flex:1 1 100%}.search{flex:1 1 160px}.topbar-controls{flex-wrap:wrap}}@media(max-width:480px){.changes-panel{left:8px;right:8px;width:auto}.search-results{width:calc(100vw - 16px)}}.changes-panel{top:calc(var(--chrome-h, 68px) + 8px)}.search-flag{font-family:var(--font-mono);font-size:8.5px;font-weight:700;letter-spacing:.03em;text-transform:uppercase;color:var(--ink-dim);border:1px solid var(--contour);border-radius:4px;padding:0 5px;margin-left:8px;white-space:nowrap;flex-shrink:0}:root{--diff-add: #dcefd9;--diff-del: #f3d9d4;--diff-paper: var(--paper);--diff-ink: var(--ink);--diff-gutter: var(--ink-faint);--diff-add-sign: #2f6a2a;--diff-del-sign: #8a3326}.ov-tabs{display:flex;gap:4px;border-bottom:1px solid var(--contour);margin:2px 0 10px}.ov-tab{border:1px solid transparent;border-bottom:none;background:none;color:var(--ink-dim);font-family:var(--font-mono);font-size:11px;font-weight:700;padding:5px 12px;border-radius:8px 8px 0 0;cursor:pointer}.ov-tab.on{background:var(--paper-raised);color:var(--ink);border-color:var(--contour);margin-bottom:-1px}.ov-tab:focus-visible{outline:2px solid var(--accent-cross);outline-offset:1px}.diff-head{display:flex;flex-wrap:wrap;align-items:center;gap:8px;margin-bottom:8px;font-family:var(--font-mono);font-size:11px}.diff-stat{font-weight:700;color:var(--ink)}.diff-flag{border:1px solid var(--contour);border-radius:4px;padding:0 6px;font-size:10px;font-weight:700;color:var(--ink-dim)}.diff-moved{color:var(--ink-dim);overflow-wrap:anywhere;font-size:10px}.diff-box{max-height:52vh;overflow:auto;background:var(--diff-paper);color:var(--diff-ink);border:1px solid var(--contour);border-radius:8px;font-family:var(--font-mono);font-size:11.5px;line-height:1.5;padding:4px 0}.diff-row{display:flex;align-items:baseline;min-width:max-content;width:100%;white-space:pre}.diff-row.add{background:var(--diff-add)}.diff-row.del{background:var(--diff-del)}.diff-row.hunk{background:transparent;color:var(--diff-gutter);font-size:10.5px;padding:3px 8px;border-top:1px dashed var(--contour);border-bottom:1px dashed var(--contour);margin:4px 0}.diff-row.hunk:first-child{margin-top:0;border-top:none}.diff-no{flex:none;width:38px;text-align:right;padding-right:6px;color:var(--diff-gutter);user-select:none;font-size:10.5px}.diff-sign{flex:none;width:16px;text-align:center;font-weight:800;user-select:none}.diff-row.add .diff-sign{color:var(--diff-add-sign)}.diff-row.del .diff-sign{color:var(--diff-del-sign)}.diff-text{flex:1;padding-right:10px}.diff-row.diff-hit{outline:2px solid var(--accent-cross);outline-offset:-2px}.diff-hit-tag,.code-line .diff-hit-tag{flex:none;align-self:center;margin:0 8px 0 auto;font-family:var(--font-mono);font-size:8.5px;font-weight:800;letter-spacing:.04em;text-transform:uppercase;color:var(--accent-cross);background:var(--accent-cross-bg);border-radius:4px;padding:0 5px}.code-line.code-hit{outline:2px solid var(--accent-cross);outline-offset:-2px;display:flex}.chg-stat{margin-left:8px;font-size:9.5px;font-weight:700;color:var(--ink-dim);white-space:nowrap}.chg-stat.pending{min-width:1px}.rt-band{width:100%;height:100%;border:1px solid;border-radius:14px;opacity:.55;pointer-events:none}.rt-band-head{display:flex;flex-direction:column;gap:1px;padding:10px 14px}.rt-band-name{font-family:var(--font-mono);font-size:13px;font-weight:700}.rt-band-kind{font-family:var(--font-mono);font-size:9.5px;font-weight:600;opacity:.85}.rt-node{width:100%;height:100%;background:var(--paper-raised);border:1px solid var(--contour);border-left:4px solid var(--accent-cross);border-radius:8px;box-shadow:var(--shadow-sm);padding:5px 10px;cursor:pointer;overflow:hidden}.rt-node:hover{box-shadow:var(--shadow-md)}.rt-node.start{border-color:var(--ink);border-left-width:4px}.rt-name{font-family:var(--font-mono);font-size:11.5px;font-weight:700;color:var(--ink);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.rt-file{font-family:var(--font-mono);font-size:9.5px;color:var(--ink-faint);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;margin-top:2px}.rt-more{font-family:var(--font-mono);font-size:10.5px;font-weight:700;color:var(--ink-dim);background:var(--paper-raised);border:1px dashed var(--contour);border-radius:8px;padding:6px 10px;white-space:nowrap}.react-flow__edge.rt-edge path.react-flow__edge-path{stroke:#6b664f;stroke-width:1.8;fill:none}.react-flow__edge.rt-cross path.react-flow__edge-path{stroke:#4a6480;stroke-width:2.2}.react-flow__edge.rt-dashed path.react-flow__edge-path{stroke-dasharray:8 6}.react-flow__edge.rt-solid path.react-flow__edge-path{stroke-dasharray:none}.project-name{flex:none;max-width:150px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-family:var(--font-mono);font-size:11px;font-weight:600;color:var(--ink-faint);padding-right:8px;margin-right:3px;border-right:1px solid var(--contour)}.rt-progress{position:absolute;left:50%;top:10px;transform:translate(-50%);z-index:5;font-family:var(--font-mono);font-size:11px;font-weight:700;color:var(--ink-dim);background:var(--paper-raised);border:1px solid var(--contour);border-radius:999px;padding:3px 12px;box-shadow:var(--shadow-sm);pointer-events:none}.rt-loop{float:right;font-family:var(--font-mono);font-size:10px;font-weight:800;color:var(--accent-cross)}.chg-modes{display:flex;margin:4px 0 10px;border:1px solid var(--contour);border-radius:8px;overflow:hidden}.chg-modes button{flex:1;font-size:10.5px;padding:5px 6px}.chg-since{background:var(--paper);border:1px solid var(--contour);border-radius:8px;padding:8px 10px;margin-bottom:10px}.chg-since-head{font-family:var(--font-mono);font-size:11.5px;font-weight:700;color:var(--ink)}.chg-since-note{font-size:11px;color:var(--ink-dim);margin-top:4px}.react-flow__edge.rt-lite path.react-flow__edge-path,.rt-line{stroke:#b9b196;stroke-width:1.4;fill:none}.search-item-rich{flex-direction:column;align-items:stretch;gap:3px}.search-line1,.search-line2{display:flex;align-items:baseline;gap:8px;min-width:0}.search-line2{flex-wrap:wrap}.search-method{font-family:var(--font-mono);font-size:10.5px;color:var(--accent-cross)}.search-chip{font-family:var(--font-mono);font-size:8.5px;font-weight:700;letter-spacing:.03em;text-transform:uppercase;color:var(--ink-dim);background:var(--paper-hover);border-radius:4px;padding:0 5px;white-space:nowrap;flex-shrink:0}.search-appears{font-size:10.5px;color:var(--ink-dim)}.search-switch{display:inline-flex;flex-wrap:wrap;gap:4px;align-items:baseline}.search-switch-btn{font:10.5px var(--font-ui);color:var(--ink);background:var(--paper);border:1px solid var(--contour);border-radius:5px;padding:1px 6px;cursor:pointer;max-width:220px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.search-switch-btn:hover{background:var(--paper-hover)}.search-code-text{font-family:var(--font-mono);font-size:11px;color:var(--ink);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.start-head,.start-more,.start-item{display:flex;align-items:baseline;gap:8px;width:100%;box-sizing:border-box;text-align:left;background:none;border:0;color:var(--ink);font:inherit;cursor:pointer;border-radius:6px;padding:5px 8px}.start-head:hover,.start-more:hover,.start-item:hover{background:var(--paper-hover)}.start-caret{width:10px;color:var(--ink-faint)}.start-item{padding-left:26px}.start-more{padding-left:26px;font-size:11px;color:var(--ink-dim)}.canopy-topbar:focus-within{z-index:50}.search-ask{display:block;width:100%;box-sizing:border-box;text-align:left;background:none;border:0;border-top:1px solid var(--contour);margin-top:6px;padding:8px 8px 4px;font:12px var(--font-ui);color:var(--accent-cross);cursor:pointer}.search-ask:hover{text-decoration:underline}.ask-ai{position:absolute;top:34px;left:0;width:min(520px,calc(100vw - 32px));z-index:46;box-sizing:border-box;background:var(--paper-raised);border:1px solid var(--contour);border-radius:10px;box-shadow:var(--shadow-lg);padding:10px 12px 12px;display:flex;flex-direction:column;gap:8px}.ask-ai-head{display:flex;align-items:center;justify-content:space-between;font-size:12.5px}.ask-ai-text{width:100%;box-sizing:border-box;resize:vertical;font:12.5px var(--font-ui);color:var(--ink);background:var(--paper);border:1px solid var(--contour);border-radius:7px;padding:7px 9px}.ask-ai-row{display:flex;align-items:center;gap:10px;flex-wrap:wrap}.ask-ai-primary{font:600 12px var(--font-ui);color:#fff;background:var(--accent-cross);border:0;border-radius:7px;padding:7px 14px;cursor:pointer}.ask-ai-secondary{display:inline-block;font:12px var(--font-ui);color:var(--ink);background:var(--paper);border:1px solid var(--contour);border-radius:7px;padding:5px 10px;cursor:pointer;text-decoration:none}.ask-ai-secondary:hover{background:var(--paper-hover)}.ask-ai-note,.ask-ai-privacy{font-size:10.5px;color:var(--ink-dim)}.ask-ai-preview summary{font-size:11px;color:var(--ink-dim);cursor:pointer}.ask-ai-preview pre{max-height:180px;overflow:auto;white-space:pre-wrap;font:10.5px var(--font-mono);color:var(--ink-dim);margin:6px 0 0}@media(max-width:480px){.ask-ai{width:calc(100vw - 16px)}}.react-flow{direction:ltr;--xy-edge-stroke-default: #b1b1b7;--xy-edge-stroke-width-default: 1;--xy-edge-stroke-selected-default: #555;--xy-connectionline-stroke-default: #b1b1b7;--xy-connectionline-stroke-width-default: 1;--xy-attribution-background-color-default: rgba(255, 255, 255, .5);--xy-minimap-background-color-default: #fff;--xy-minimap-mask-background-color-default: rgba(240, 240, 240, .6);--xy-minimap-mask-stroke-color-default: transparent;--xy-minimap-mask-stroke-width-default: 1;--xy-minimap-node-background-color-default: #e2e2e2;--xy-minimap-node-stroke-color-default: transparent;--xy-minimap-node-stroke-width-default: 2;--xy-background-color-default: transparent;--xy-background-pattern-dots-color-default: #91919a;--xy-background-pattern-lines-color-default: #eee;--xy-background-pattern-cross-color-default: #e2e2e2;background-color:var(--xy-background-color, var(--xy-background-color-default));--xy-node-color-default: inherit;--xy-node-border-default: 1px solid #1a192b;--xy-node-background-color-default: #fff;--xy-node-group-background-color-default: rgba(240, 240, 240, .25);--xy-node-boxshadow-hover-default: 0 1px 4px 1px rgba(0, 0, 0, .08);--xy-node-boxshadow-selected-default: 0 0 0 .5px #1a192b;--xy-node-border-radius-default: 3px;--xy-handle-background-color-default: #1a192b;--xy-handle-border-color-default: #fff;--xy-selection-background-color-default: rgba(0, 89, 220, .08);--xy-selection-border-default: 1px dotted rgba(0, 89, 220, .8);--xy-controls-button-background-color-default: #fefefe;--xy-controls-button-background-color-hover-default: #f4f4f4;--xy-controls-button-color-default: inherit;--xy-controls-button-color-hover-default: inherit;--xy-controls-button-border-color-default: #eee;--xy-controls-box-shadow-default: 0 0 2px 1px rgba(0, 0, 0, .08);--xy-edge-label-background-color-default: #ffffff;--xy-edge-label-color-default: inherit;--xy-resize-background-color-default: #3367d9}.react-flow.dark{--xy-edge-stroke-default: #3e3e3e;--xy-edge-stroke-width-default: 1;--xy-edge-stroke-selected-default: #727272;--xy-connectionline-stroke-default: #b1b1b7;--xy-connectionline-stroke-width-default: 1;--xy-attribution-background-color-default: rgba(150, 150, 150, .25);--xy-minimap-background-color-default: #141414;--xy-minimap-mask-background-color-default: rgba(60, 60, 60, .6);--xy-minimap-mask-stroke-color-default: transparent;--xy-minimap-mask-stroke-width-default: 1;--xy-minimap-node-background-color-default: #2b2b2b;--xy-minimap-node-stroke-color-default: transparent;--xy-minimap-node-stroke-width-default: 2;--xy-background-color-default: #141414;--xy-background-pattern-dots-color-default: #555;--xy-background-pattern-lines-color-default: #333;--xy-background-pattern-cross-color-default: #333;--xy-node-color-default: #f8f8f8;--xy-node-border-default: 1px solid #3c3c3c;--xy-node-background-color-default: #1e1e1e;--xy-node-group-background-color-default: rgba(240, 240, 240, .25);--xy-node-boxshadow-hover-default: 0 1px 4px 1px rgba(255, 255, 255, .08);--xy-node-boxshadow-selected-default: 0 0 0 .5px #999;--xy-handle-background-color-default: #bebebe;--xy-handle-border-color-default: #1e1e1e;--xy-selection-background-color-default: rgba(200, 200, 220, .08);--xy-selection-border-default: 1px dotted rgba(200, 200, 220, .8);--xy-controls-button-background-color-default: #2b2b2b;--xy-controls-button-background-color-hover-default: #3e3e3e;--xy-controls-button-color-default: #f8f8f8;--xy-controls-button-color-hover-default: #fff;--xy-controls-button-border-color-default: #5b5b5b;--xy-controls-box-shadow-default: 0 0 2px 1px rgba(0, 0, 0, .08);--xy-edge-label-background-color-default: #141414;--xy-edge-label-color-default: #f8f8f8}.react-flow__background{background-color:var(--xy-background-color-props, var(--xy-background-color, var(--xy-background-color-default)));pointer-events:none;z-index:-1}.react-flow__container{position:absolute;width:100%;height:100%;top:0;left:0}.react-flow__pane{z-index:1;touch-action:none}.react-flow__pane.draggable{cursor:grab}.react-flow__pane.dragging{cursor:grabbing}.react-flow__pane.selection{cursor:pointer}.react-flow__viewport{transform-origin:0 0;z-index:2;pointer-events:none}.react-flow__renderer{z-index:4}.react-flow__selection{z-index:6}.react-flow__nodesselection-rect:focus,.react-flow__nodesselection-rect:focus-visible{outline:none}.react-flow__edge-path{stroke:var(--xy-edge-stroke, var(--xy-edge-stroke-default));stroke-width:var(--xy-edge-stroke-width, var(--xy-edge-stroke-width-default));fill:none}.react-flow__connection-path{stroke:var(--xy-connectionline-stroke, var(--xy-connectionline-stroke-default));stroke-width:var(--xy-connectionline-stroke-width, var(--xy-connectionline-stroke-width-default));fill:none}.react-flow .react-flow__edges{position:absolute}.react-flow .react-flow__edges svg{overflow:visible;position:absolute;pointer-events:none}.react-flow__edge{pointer-events:visibleStroke}.react-flow__edge.selectable{cursor:pointer}.react-flow__edge.animated path{stroke-dasharray:5;animation:dashdraw .5s linear infinite}.react-flow__edge.animated path.react-flow__edge-interaction{stroke-dasharray:none;animation:none}.react-flow__edge.inactive{pointer-events:none}.react-flow__edge.selected,.react-flow__edge:focus,.react-flow__edge:focus-visible{outline:none}.react-flow__edge.selected .react-flow__edge-path,.react-flow__edge.selectable:focus .react-flow__edge-path,.react-flow__edge.selectable:focus-visible .react-flow__edge-path{stroke:var(--xy-edge-stroke-selected, var(--xy-edge-stroke-selected-default))}.react-flow__edge-textwrapper{pointer-events:all}.react-flow__edge .react-flow__edge-text{pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.react-flow__arrowhead polyline{stroke:var(--xy-edge-stroke, var(--xy-edge-stroke-default))}.react-flow__arrowhead polyline.arrowclosed{fill:var(--xy-edge-stroke, var(--xy-edge-stroke-default))}.react-flow__connection{pointer-events:none}.react-flow__connection .animated{stroke-dasharray:5;animation:dashdraw .5s linear infinite}svg.react-flow__connectionline{z-index:1001;overflow:visible;position:absolute}.react-flow__nodes{pointer-events:none;transform-origin:0 0}.react-flow__node{position:absolute;-webkit-user-select:none;-moz-user-select:none;user-select:none;pointer-events:all;transform-origin:0 0;box-sizing:border-box;cursor:default}.react-flow__node.selectable{cursor:pointer}.react-flow__node.draggable{cursor:grab;pointer-events:all}.react-flow__node.draggable.dragging{cursor:grabbing}.react-flow__nodesselection{z-index:3;transform-origin:left top;pointer-events:none}.react-flow__nodesselection-rect{position:absolute;pointer-events:all;cursor:grab}.react-flow__handle{position:absolute;pointer-events:none;min-width:5px;min-height:5px;width:6px;height:6px;background-color:var(--xy-handle-background-color, var(--xy-handle-background-color-default));border:1px solid var(--xy-handle-border-color, var(--xy-handle-border-color-default));border-radius:100%}.react-flow__handle.connectingfrom{pointer-events:all}.react-flow__handle.connectionindicator{pointer-events:all;cursor:crosshair}.react-flow__handle-bottom{top:auto;left:50%;bottom:0;transform:translate(-50%,50%)}.react-flow__handle-top{top:0;left:50%;transform:translate(-50%,-50%)}.react-flow__handle-left{top:50%;left:0;transform:translate(-50%,-50%)}.react-flow__handle-right{top:50%;right:0;transform:translate(50%,-50%)}.react-flow__edgeupdater{cursor:move;pointer-events:all}.react-flow__pane.selection .react-flow__panel{pointer-events:none}.react-flow__panel{position:absolute;z-index:5;margin:15px}.react-flow__panel.top{top:0}.react-flow__panel.bottom{bottom:0}.react-flow__panel.top.center,.react-flow__panel.bottom.center{left:50%;transform:translate(-15px) translate(-50%)}.react-flow__panel.left{left:0}.react-flow__panel.right{right:0}.react-flow__panel.left.center,.react-flow__panel.right.center{top:50%;transform:translateY(-15px) translateY(-50%)}.react-flow__attribution{font-size:10px;background:var(--xy-attribution-background-color, var(--xy-attribution-background-color-default));padding:2px 3px;margin:0}.react-flow__attribution a{text-decoration:none;color:#999}@keyframes dashdraw{0%{stroke-dashoffset:10}}.react-flow__edgelabel-renderer{position:absolute;width:100%;height:100%;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none;left:0;top:0}.react-flow__viewport-portal{position:absolute;width:100%;height:100%;left:0;top:0;-webkit-user-select:none;-moz-user-select:none;user-select:none}.react-flow__minimap{background:var( --xy-minimap-background-color-props, var(--xy-minimap-background-color, var(--xy-minimap-background-color-default)) )}.react-flow__minimap-svg{display:block}.react-flow__minimap-mask{fill:var( --xy-minimap-mask-background-color-props, var(--xy-minimap-mask-background-color, var(--xy-minimap-mask-background-color-default)) );stroke:var( --xy-minimap-mask-stroke-color-props, var(--xy-minimap-mask-stroke-color, var(--xy-minimap-mask-stroke-color-default)) );stroke-width:var( --xy-minimap-mask-stroke-width-props, var(--xy-minimap-mask-stroke-width, var(--xy-minimap-mask-stroke-width-default)) )}.react-flow__minimap-node{fill:var( --xy-minimap-node-background-color-props, var(--xy-minimap-node-background-color, var(--xy-minimap-node-background-color-default)) );stroke:var( --xy-minimap-node-stroke-color-props, var(--xy-minimap-node-stroke-color, var(--xy-minimap-node-stroke-color-default)) );stroke-width:var( --xy-minimap-node-stroke-width-props, var(--xy-minimap-node-stroke-width, var(--xy-minimap-node-stroke-width-default)) )}.react-flow__background-pattern.dots{fill:var( --xy-background-pattern-color-props, var(--xy-background-pattern-color, var(--xy-background-pattern-dots-color-default)) )}.react-flow__background-pattern.lines{stroke:var( --xy-background-pattern-color-props, var(--xy-background-pattern-color, var(--xy-background-pattern-lines-color-default)) )}.react-flow__background-pattern.cross{stroke:var( --xy-background-pattern-color-props, var(--xy-background-pattern-color, var(--xy-background-pattern-cross-color-default)) )}.react-flow__controls{display:flex;flex-direction:column;box-shadow:var(--xy-controls-box-shadow, var(--xy-controls-box-shadow-default))}.react-flow__controls.horizontal{flex-direction:row}.react-flow__controls-button{display:flex;justify-content:center;align-items:center;height:26px;width:26px;padding:4px;border:none;background:var(--xy-controls-button-background-color, var(--xy-controls-button-background-color-default));border-bottom:1px solid var( --xy-controls-button-border-color-props, var(--xy-controls-button-border-color, var(--xy-controls-button-border-color-default)) );color:var( --xy-controls-button-color-props, var(--xy-controls-button-color, var(--xy-controls-button-color-default)) );cursor:pointer;-webkit-user-select:none;-moz-user-select:none;user-select:none}.react-flow__controls-button svg{width:100%;max-width:12px;max-height:12px;fill:currentColor}.react-flow__edge.updating .react-flow__edge-path{stroke:#777}.react-flow__edge-text{font-size:10px}.react-flow__node.selectable:focus,.react-flow__node.selectable:focus-visible{outline:none}.react-flow__node-input,.react-flow__node-default,.react-flow__node-output,.react-flow__node-group{padding:10px;border-radius:var(--xy-node-border-radius, var(--xy-node-border-radius-default));width:150px;font-size:12px;color:var(--xy-node-color, var(--xy-node-color-default));text-align:center;border:var(--xy-node-border, var(--xy-node-border-default));background-color:var(--xy-node-background-color, var(--xy-node-background-color-default))}.react-flow__node-input.selectable:hover,.react-flow__node-default.selectable:hover,.react-flow__node-output.selectable:hover,.react-flow__node-group.selectable:hover{box-shadow:var(--xy-node-boxshadow-hover, var(--xy-node-boxshadow-hover-default))}.react-flow__node-input.selectable.selected,.react-flow__node-input.selectable:focus,.react-flow__node-input.selectable:focus-visible,.react-flow__node-default.selectable.selected,.react-flow__node-default.selectable:focus,.react-flow__node-default.selectable:focus-visible,.react-flow__node-output.selectable.selected,.react-flow__node-output.selectable:focus,.react-flow__node-output.selectable:focus-visible,.react-flow__node-group.selectable.selected,.react-flow__node-group.selectable:focus,.react-flow__node-group.selectable:focus-visible{box-shadow:var(--xy-node-boxshadow-selected, var(--xy-node-boxshadow-selected-default))}.react-flow__node-group{background-color:var(--xy-node-group-background-color, var(--xy-node-group-background-color-default))}.react-flow__nodesselection-rect,.react-flow__selection{background:var(--xy-selection-background-color, var(--xy-selection-background-color-default));border:var(--xy-selection-border, var(--xy-selection-border-default))}.react-flow__nodesselection-rect:focus,.react-flow__nodesselection-rect:focus-visible,.react-flow__selection:focus,.react-flow__selection:focus-visible{outline:none}.react-flow__controls-button:hover{background:var( --xy-controls-button-background-color-hover-props, var(--xy-controls-button-background-color-hover, var(--xy-controls-button-background-color-hover-default)) );color:var( --xy-controls-button-color-hover-props, var(--xy-controls-button-color-hover, var(--xy-controls-button-color-hover-default)) )}.react-flow__controls-button:disabled{pointer-events:none}.react-flow__controls-button:disabled svg{fill-opacity:.4}.react-flow__controls-button:last-child{border-bottom:none}.react-flow__controls.horizontal .react-flow__controls-button{border-bottom:none;border-right:1px solid var( --xy-controls-button-border-color-props, var(--xy-controls-button-border-color, var(--xy-controls-button-border-color-default)) )}.react-flow__controls.horizontal .react-flow__controls-button:last-child{border-right:none}.react-flow__resize-control{position:absolute}.react-flow__resize-control.left,.react-flow__resize-control.right{cursor:ew-resize}.react-flow__resize-control.top,.react-flow__resize-control.bottom{cursor:ns-resize}.react-flow__resize-control.top.left,.react-flow__resize-control.bottom.right{cursor:nwse-resize}.react-flow__resize-control.bottom.left,.react-flow__resize-control.top.right{cursor:nesw-resize}.react-flow__resize-control.handle{width:5px;height:5px;border:1px solid #fff;border-radius:1px;background-color:var(--xy-resize-background-color, var(--xy-resize-background-color-default));translate:-50% -50%}.react-flow__resize-control.handle.left{left:0;top:50%}.react-flow__resize-control.handle.right{left:100%;top:50%}.react-flow__resize-control.handle.top{left:50%;top:0}.react-flow__resize-control.handle.bottom{left:50%;top:100%}.react-flow__resize-control.handle.top.left,.react-flow__resize-control.handle.bottom.left{left:0}.react-flow__resize-control.handle.top.right,.react-flow__resize-control.handle.bottom.right{left:100%}.react-flow__resize-control.line{border-color:var(--xy-resize-background-color, var(--xy-resize-background-color-default));border-width:0;border-style:solid}.react-flow__resize-control.line.left,.react-flow__resize-control.line.right{width:1px;transform:translate(-50%);top:0;height:100%}.react-flow__resize-control.line.left{left:0;border-left-width:1px}.react-flow__resize-control.line.right{left:100%;border-right-width:1px}.react-flow__resize-control.line.top,.react-flow__resize-control.line.bottom{height:1px;transform:translateY(-50%);left:0;width:100%}.react-flow__resize-control.line.top{top:0;border-top-width:1px}.react-flow__resize-control.line.bottom{border-bottom-width:1px;top:100%}.react-flow__edge-textbg{fill:var(--xy-edge-label-background-color, var(--xy-edge-label-background-color-default))}.react-flow__edge-text{fill:var(--xy-edge-label-color, var(--xy-edge-label-color-default))}
|
|
1
|
+
@font-face{font-family:Inter;font-style:normal;font-weight:400 700;font-display:swap;src:url("./fonts/Inter-latin-var.woff2") format("woff2")}@font-face{font-family:JetBrains Mono;font-style:normal;font-weight:400 700;font-display:swap;src:url("./fonts/JetBrainsMono-latin-var.woff2") format("woff2")}:root{--paper: #f3efe3;--paper-raised: #faf7ee;--paper-hover: #eee7d4;--contour: #d9d0ba;--ink: #2b2a22;--ink-dim: #6b664f;--ink-faint: #a39a7d;--shadow-sm: 0 1px 2px rgba(40, 35, 20, .06), 0 2px 6px rgba(40, 35, 20, .05);--shadow-md: 0 2px 4px rgba(40, 35, 20, .07), 0 8px 20px rgba(40, 35, 20, .09);--shadow-lg: 0 4px 10px rgba(40, 35, 20, .1), 0 18px 38px rgba(40, 35, 20, .14);--accent-client: #4f7a5c;--accent-client-bg: #e4ecdf;--accent-server: #9a5b32;--accent-server-bg: #f1e2cf;--accent-unknown: #6b5a8f;--accent-unknown-bg: #e7e1ef;--accent-cross: #4a6480;--accent-cross-bg: #dfe6ec;--font-ui: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;--font-mono: "JetBrains Mono", "SF Mono", Consolas, monospace}*{box-sizing:border-box}html,body,#root{height:100%;margin:0}body{font-family:var(--font-ui);color:var(--ink);background:radial-gradient(ellipse 100% 70% at 50% -10%,#f8f4e8,#efe8d5 55%,#e4dabf);overflow:hidden}.canopy-app{height:100vh;display:flex;flex-direction:column}.canopy-topbar{display:flex;align-items:center;justify-content:space-between;padding:14px 22px;border-bottom:1px solid var(--contour);background:var(--paper-raised);box-shadow:0 1px #28231408,0 2px 10px #2823140d;z-index:10;position:relative}.canopy-brand{font-family:var(--font-ui);font-weight:700;font-size:16px;letter-spacing:-.01em;color:var(--ink);display:flex;align-items:center;gap:7px}.canopy-brand .leaf{color:var(--accent-client);font-size:15px}.canopy-crumbs{display:flex;align-items:center;gap:5px;font-size:13px}.crumb{padding:4px 9px;border-radius:6px;cursor:pointer;color:var(--ink-dim);font-weight:500;transition:background .15s ease,color .15s ease}.crumb:hover{background:var(--paper-hover);color:var(--ink)}.crumb.current{color:var(--ink);font-weight:700;cursor:default;font-size:14px}.crumb.current:hover{background:none}.crumb-sep{color:var(--ink-faint);font-size:11px}.canopy-hint{font-size:11.5px;color:var(--ink-faint);margin-top:1px;font-weight:500}.picker-entry-btn{font-family:var(--font-mono);font-size:11px;font-weight:600;color:var(--accent-cross);background:var(--accent-cross-bg);border:1px solid var(--accent-cross);border-radius:7px;padding:6px 11px;cursor:pointer;transition:background .15s ease}.picker-entry-btn:hover{background:var(--accent-cross);color:var(--paper-raised)}.canopy-stats{display:flex;gap:18px}.stat{text-align:right}.stat-num{font-size:17px;font-weight:700;line-height:1;color:var(--ink);font-variant-numeric:tabular-nums}.stat-label{font-size:9.5px;text-transform:uppercase;letter-spacing:.06em;color:var(--ink-faint);font-weight:600;margin-top:2px}.canopy-canvas{flex:1;position:relative}.react-flow__attribution{display:none}.react-flow__controls{box-shadow:var(--shadow-md);border-radius:10px;overflow:hidden;border:1px solid var(--contour)}.react-flow__controls-button{background:var(--paper-raised);border-bottom:1px solid var(--contour);color:var(--ink-dim);width:30px;height:30px}.react-flow__controls-button:hover{background:var(--paper-hover);color:var(--ink)}.react-flow__controls-button svg{fill:currentColor}.react-flow__minimap{border-radius:10px;box-shadow:var(--shadow-md);border:1px solid var(--contour);overflow:hidden}.group-bg{width:100%;height:100%;border-radius:20px;background:#96855414;border:1px dashed rgba(110,95,55,.18);pointer-events:none}.v-scrollbar-track{position:absolute;top:10px;bottom:30px;right:4px;width:10px;border-radius:6px;background:#b4a88a29;z-index:5;cursor:pointer}.v-scrollbar-thumb{position:absolute;left:0;width:100%;border-radius:6px;background:var(--ink-faint);opacity:.55;cursor:grab;transition:opacity .15s ease,background .15s ease}.v-scrollbar-thumb:hover{opacity:.85;background:var(--ink-dim)}.v-scrollbar-thumb:active{cursor:grabbing;opacity:1}.react-flow__edge-path{stroke-linecap:round}.react-flow__edge.same-service .react-flow__edge-path{stroke:var(--ink-dim);stroke-width:2px}.react-flow__edge.cross-service .react-flow__edge-path{stroke:var(--accent-cross);stroke-width:2.2px;stroke-dasharray:7 5}.react-flow__edge.service-link .react-flow__edge-path{stroke:var(--accent-cross);stroke-width:2.4px;stroke-dasharray:8 6}.card{background:var(--paper-raised);border-radius:12px;box-shadow:var(--shadow-sm);transition:box-shadow .18s ease,transform .18s ease;border:1px solid rgba(40,35,20,.06)}.card:hover{box-shadow:var(--shadow-lg);transform:translateY(-2px)}.svc-node{width:240px;padding:18px 20px;cursor:pointer}.svc-kind{display:inline-block;font-size:9.5px;font-weight:700;text-transform:uppercase;letter-spacing:.07em;padding:3px 9px;border-radius:5px}.svc-name{font-size:19px;font-weight:700;margin-top:10px;letter-spacing:-.01em;color:var(--ink)}.svc-meta{font-family:var(--font-mono);font-size:10.5px;color:var(--ink-dim);margin-top:6px}.svc-badges{display:flex;gap:6px;margin-top:11px;flex-wrap:wrap}.svc-badge{font-family:var(--font-mono);font-size:9px;font-weight:600;background:var(--accent-cross-bg);color:var(--accent-cross);border-radius:4px;padding:2px 7px}.wf-node{width:100%;height:100%;padding:14px 18px;cursor:pointer;display:flex;align-items:center;gap:14px}.wf-dot{width:9px;height:9px;border-radius:50%;flex-shrink:0}.wf-body{flex:1;min-width:0}.wf-name{font-size:14.5px;font-weight:650;color:var(--ink);line-height:1.3;overflow-wrap:break-word;word-break:normal}.wf-meta{font-family:var(--font-mono);font-size:10.5px;color:var(--ink-faint);margin-top:4px}.wf-chevron{color:var(--ink-faint);font-size:18px;flex-shrink:0}.minor-panel{position:absolute;left:50%;bottom:22px;transform:translate(-50%);z-index:15;width:460px;max-width:calc(100% - 44px);background:var(--paper-raised);border:1px solid var(--contour);border-radius:12px;box-shadow:var(--shadow-md);overflow:hidden}.minor-toggle{width:100%;border:none;background:none;cursor:pointer;padding:11px 18px;display:flex;align-items:center;justify-content:space-between;font-family:var(--font-mono);font-size:11.5px;font-weight:600;color:var(--ink-dim)}.minor-toggle:hover{color:var(--ink);background:var(--paper-hover)}.minor-caret{color:var(--ink-faint);font-size:10px}.minor-list{max-height:260px;overflow-y:auto;border-top:1px solid var(--contour)}.minor-item{padding:8px 18px;font-size:12px;color:var(--ink-dim);cursor:pointer;border-bottom:1px solid rgba(40,35,20,.05);display:flex;justify-content:space-between;gap:10px}.minor-item:last-child{border-bottom:none}.minor-item:hover{background:var(--paper-hover);color:var(--ink)}.minor-item .minor-file{font-family:var(--font-mono);font-size:9.5px;color:var(--ink-faint);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex-shrink:1}.context-rail{position:absolute;top:14px;left:10px;z-index:8;width:190px;max-height:calc(100% - 28px);overflow-y:auto;display:flex;flex-direction:column;gap:12px}.context-group{background:var(--paper-raised);border:1px solid var(--contour);border-radius:10px;padding:9px 10px;box-shadow:var(--shadow-sm)}.context-label{font-family:var(--font-mono);font-size:8.5px;font-weight:700;text-transform:uppercase;letter-spacing:.05em;color:var(--ink-faint);margin-bottom:6px}.context-chip{font-size:11px;font-weight:600;color:var(--ink);background:var(--paper);border:1px solid var(--contour);border-radius:6px;padding:5px 8px;margin-top:4px;cursor:pointer;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;transition:background .15s ease}.context-chip:first-child{margin-top:0}.context-chip:hover{background:var(--paper-hover)}.context-more{font-family:var(--font-mono);font-size:9.5px;color:var(--ink-faint);margin-top:4px}.step-node{width:100%;height:100%;min-height:90px;padding:18px;box-sizing:border-box;overflow:visible;position:relative}.step-node.root{border-color:var(--accent-client);box-shadow:0 0 0 1.5px var(--accent-client),var(--shadow-sm)}.step-node.active-expanded:not(.root){border-color:var(--accent-cross);box-shadow:0 0 0 1.5px var(--accent-cross),var(--shadow-sm)}.step-top{display:flex;align-items:center;gap:6px;flex-wrap:wrap}.step-badge{font-family:var(--font-mono);font-size:9px;font-weight:700;background:var(--ink);color:var(--paper);border-radius:4px;padding:1.5px 6px;flex-shrink:0}.step-cat{font-family:var(--font-mono);font-size:8px;font-weight:700;border-radius:4px;padding:1.5px 6px;flex-shrink:0;text-transform:uppercase;letter-spacing:.03em}.step-name{font-size:13px;font-weight:650;color:var(--ink);line-height:1.3;flex:1;min-width:60px;overflow-wrap:break-word;word-break:normal}.step-file{font-family:var(--font-mono);font-size:8.5px;color:var(--ink-faint);margin-top:5px;overflow-wrap:break-word;word-break:normal}.step-expand{margin-top:8px;font-family:var(--font-mono);font-size:10px;font-weight:600;border:1px solid var(--contour);background:var(--paper);color:var(--ink-dim);border-radius:6px;padding:3px 9px;cursor:pointer;transition:background .15s ease,color .15s ease,border-color .15s ease}.step-expand:hover{background:var(--paper-hover);color:var(--ink)}.step-expand.open{background:var(--ink);color:var(--paper);border-color:var(--ink)}.react-flow__edge.secondary-link .react-flow__edge-path{stroke:var(--ink-faint);stroke-dasharray:3 4;stroke-width:1.3}.source-icon{border:none;background:var(--paper);color:var(--ink-faint);font-family:var(--font-mono);font-size:9.5px;font-weight:700;border-radius:4px;padding:1px 5px;cursor:pointer;flex-shrink:0;margin-left:auto}.source-icon:hover{background:var(--ink);color:var(--paper)}.detail-source{font-family:var(--font-mono);font-size:11px;line-height:1.55;color:var(--ink);background:var(--paper);border:1px solid var(--contour);border-radius:8px;padding:10px 12px;margin-top:6px;white-space:pre-wrap;word-break:break-word;overflow-wrap:break-word;word-break:normal}.source-unavailable{color:var(--accent-server);font-style:italic}.recursive-badge{margin-top:7px;font-family:var(--font-mono);font-size:9.5px;font-weight:700;color:var(--accent-server);background:var(--accent-server-bg);border-radius:5px;padding:3px 7px;display:inline-block}.runtime-bucket{width:100%;padding:16px;border:1px dashed var(--contour);background:var(--paper);box-sizing:border-box;max-height:270px;overflow-y:auto}.runtime-bucket-header{font-family:var(--font-mono);font-size:8.5px;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--ink-faint);padding:2px 8px 6px}.runtime-bucket-item{display:flex;flex-direction:column;align-items:flex-start;gap:3px;padding:6px 8px;font-size:10.5px;color:var(--ink-dim)}.runtime-bucket-item.inline{padding:5px 0}.runtime-bucket-item-row{display:flex;align-items:center;gap:6px;width:100%}.runtime-bucket-label{flex:1;min-width:60px;overflow-wrap:break-word;word-break:normal;font-family:var(--font-mono)}.runtime-tag{font-family:var(--font-mono);font-size:8px;font-weight:700;border-radius:4px;padding:1.5px 5px;flex-shrink:0;text-transform:uppercase;letter-spacing:.02em}.runtime-tag-unresolvable-call-site{background:var(--accent-unknown-bg);color:var(--accent-unknown)}.runtime-tag-runtime-dispatched{background:var(--accent-cross-bg);color:var(--accent-cross)}.runtime-tag-return-value{background:var(--accent-client-bg);color:var(--accent-client)}.runtime-bucket.nested-bucket{margin:0}.inline-call{width:100%;height:100%;padding:16px;display:flex;flex-direction:column;align-items:flex-start;gap:3px;border:1px solid var(--contour);background:var(--paper);box-sizing:border-box;font-size:10.5px;color:var(--ink-dim)}.branch-diagram{width:100%;padding:4px 10px;border:1.5px solid var(--accent-cross);box-sizing:border-box}.branch-diagram.nested{border-width:1px;box-shadow:none;padding:3px 8px}.branch-condition{display:flex;align-items:center;gap:7px;padding-bottom:2px;border-bottom:1px dashed var(--contour)}.branch-condition-kind{font-family:var(--font-mono);font-size:8px;font-weight:700;text-transform:uppercase;letter-spacing:.05em;background:var(--accent-cross-bg);color:var(--accent-cross);border-radius:4px;padding:2px 6px;flex-shrink:0}.branch-condition-text{font-family:var(--font-mono);font-size:11.5px;font-weight:650;color:var(--ink);overflow-wrap:break-word;word-break:normal;flex:1;min-width:80px}.branch-outcomes{display:flex;flex-direction:row;align-items:flex-start;gap:18px;margin-top:4px;overflow-x:visible}.branch-outcome{display:flex;flex-direction:row;align-items:flex-start;gap:8px;min-width:150px;flex-shrink:0}.branch-arrow-row{display:flex;align-items:center;gap:5px;height:12px}.branch-arrow-svg{height:10px}.branch-arrow-label{font-family:var(--font-mono);font-size:9px;font-weight:700;color:var(--accent-cross);text-transform:uppercase;flex-shrink:0}.branch-chain-lane{display:flex;flex-direction:column;gap:3px;min-width:0}.branch-empty{font-family:var(--font-mono);font-size:10px;color:var(--ink-faint);font-style:italic;padding:4px 0}.step-body-contained{margin-top:14px;padding-top:12px;border-top:1px dashed var(--contour)}.chain-row{position:relative;min-width:0}.branch-step-chip{display:flex;align-items:center;gap:6px;background:var(--paper);border:1px solid var(--contour);border-radius:6px;padding:6px 9px;cursor:pointer;transition:background .15s ease,border-color .15s ease}.branch-step-chip:hover{background:var(--paper-hover)}.branch-step-chip.promoted{border-color:var(--accent-cross);border-style:dashed;background:var(--accent-cross-bg)}.branch-step-name{font-size:11.5px;font-weight:600;color:var(--ink);flex:1;min-width:40px;overflow-wrap:break-word;word-break:normal}.promoted-hint{font-family:var(--font-mono);font-size:8.5px;font-weight:600;color:var(--accent-cross);flex-shrink:0}.empty-state{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);text-align:center;color:var(--ink-faint);font-family:var(--font-mono);font-size:12.5px;max-width:320px;line-height:1.6;pointer-events:none}.empty-state .glyph{font-size:26px;margin-bottom:10px;opacity:.55}.detail-panel{position:absolute;top:0;right:0;height:100%;width:320px;background:var(--paper-raised);border-left:1px solid var(--contour);box-shadow:-8px 0 26px #2823141f;padding:24px 22px;overflow-y:auto;transform:translate(0);animation:panelIn .22s cubic-bezier(.22,.9,.3,1) both;z-index:20}@keyframes panelIn{0%{transform:translate(16px);opacity:0}to{transform:translate(0);opacity:1}}.detail-close{position:absolute;top:16px;right:16px;border:none;background:none;cursor:pointer;font-size:15px;color:var(--ink-faint)}.detail-close:hover{color:var(--ink)}.detail-label{font-size:9.5px;text-transform:uppercase;letter-spacing:.07em;color:var(--ink-faint);font-weight:700;margin-top:18px;margin-bottom:5px}.detail-label:first-of-type{margin-top:8px}.detail-name{font-size:18px;font-weight:700;margin-top:20px;color:var(--ink)}.detail-mono{font-family:var(--font-mono);font-size:11.5px;color:var(--ink-dim);word-break:break-all;line-height:1.5}.detail-note{font-size:12.5px;color:var(--ink-dim);line-height:1.5}@keyframes nodeFadeIn{0%{opacity:0}to{opacity:1}}.react-flow__node{animation:nodeFadeIn .18s ease both}@keyframes cardIn{0%{transform:scale(.92) translateY(6px)}to{transform:scale(1) translateY(0)}}.react-flow__node .card{animation:cardIn .22s cubic-bezier(.22,.9,.3,1) both}.inferred-badge{display:inline-block;margin-left:8px;padding:1px 6px;border-radius:8px;font-size:9px;font-weight:600;letter-spacing:.02em;text-transform:uppercase;background:#ece6d2;color:#7a7355;border:1px dashed #b8ae8a;vertical-align:middle}.runtime-bucket-item.compact{flex-direction:row;align-items:center;gap:8px;height:24px;padding:0 2px;box-sizing:border-box;cursor:pointer}.runtime-bucket-item.compact:hover{background:#00000009}.compact-dot{width:7px;height:7px;padding:0;border-radius:50%;flex:0 0 7px}.compact-label{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0;max-width:420px;font-size:10.5px}.branch-arrow-label{line-height:24px;min-width:42px}.changes-btn{border:1px solid var(--contour);background:var(--paper-raised);color:var(--ink);font-family:var(--font-mono);font-size:11px;font-weight:700;border-radius:8px;padding:6px 12px;cursor:pointer}.changes-btn.active,.changes-btn:hover{background:var(--ink);color:var(--paper)}.changes-btn-count{margin-left:7px;background:#c8892c;color:#fff;border-radius:9px;padding:0 6px;font-size:10px}.changes-panel{position:fixed;top:76px;right:12px;bottom:12px;width:440px;z-index:30;overflow-y:auto;background:var(--paper-raised);border:1px solid var(--contour);border-radius:12px;box-shadow:0 10px 40px #3c321438;padding:14px 16px 18px}.chg-empty{font-size:14px;font-weight:600;color:var(--ink);margin:14px 0 8px}.chg-stepper{display:flex;align-items:center;gap:10px;margin:8px 0 10px}.chg-stepper button{width:30px;height:30px;border-radius:8px;border:1px solid var(--contour);background:var(--paper);font-size:18px;cursor:pointer;color:var(--ink)}.chg-stepper button:disabled{opacity:.3;cursor:default}.chg-ver{flex:1;min-width:0;text-align:center}.chg-ver-title{font-family:var(--font-mono);font-weight:700;font-size:14px;color:var(--ink)}.chg-ver-sha{font-weight:500;color:var(--ink-faint);font-size:11px;margin-left:4px}.chg-dirty{color:#c8892c}.chg-ver-msg{font-size:12px;color:var(--ink);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.chg-ver-meta{font-size:10px;color:var(--ink-faint);font-family:var(--font-mono)}.chg-summary{display:flex;flex-direction:column;gap:3px;font-family:var(--font-mono);font-size:11px;color:var(--ink-dim);padding:8px 10px;background:var(--paper);border-radius:8px;margin-bottom:10px}.chg-summary b{color:var(--ink)}.chg-section{margin-top:8px}.chg-section-head{width:100%;display:flex;align-items:center;gap:8px;border:none;background:none;cursor:pointer;font-family:var(--font-mono);font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:.05em;color:var(--ink-dim);padding:4px 0;border-bottom:1px dashed var(--contour)}.chg-section-head .chg-count{background:var(--paper);border-radius:8px;padding:0 6px;color:var(--ink)}.chg-section-head .chg-caret{margin-left:auto}.chg-section-body{padding-top:4px}.chg-wf{padding:6px 8px;border-radius:8px;cursor:pointer;border:1px solid transparent}.chg-wf:hover{background:var(--paper);border-color:var(--contour)}.chg-wf.gone{cursor:default;opacity:.6}.chg-wf-name{font-size:12px;font-weight:650;color:var(--ink);display:flex;align-items:center;gap:6px;flex-wrap:wrap}.chg-wf-why{font-family:var(--font-mono);font-size:10px;color:var(--ink-dim);margin-top:2px;overflow-wrap:anywhere}.chg-svc{font-family:var(--font-mono);font-size:9px;color:var(--ink-faint);margin-left:auto}.chg-tag{font-family:var(--font-mono);font-size:8px;font-weight:700;text-transform:uppercase;border-radius:4px;padding:1px 5px;background:#ece6d2;color:#7a7355}.chg-tag-new{background:#dcefd9;color:#2f6a2a}.chg-tag-removed{background:#f3d9d4;color:#8a3326}.chg-tag-changed{background:#f3e6c4;color:#85601a}.chg-row{font-family:var(--font-mono);font-size:10.5px;color:var(--ink);padding:2px 4px;overflow-wrap:anywhere}.chg-row .chg-sign{display:inline-block;width:14px;font-weight:700}.chg-row.add .chg-sign{color:#2f6a2a}.chg-row.del .chg-sign{color:#8a3326}.chg-row.mod .chg-sign{color:#85601a}.chg-row.mv .chg-sign{color:#4a6480}.chg-file{display:block;margin-left:14px;color:var(--ink-faint);font-size:9.5px}.chg-more,.chg-info{font-size:10px;color:var(--ink-faint);padding:4px}.chg-info{margin-top:12px;border-top:1px dashed var(--contour);padding-top:8px}.change-badge{font-family:var(--font-mono);font-size:8px;font-weight:800;letter-spacing:.04em;border-radius:4px;padding:1px 5px;margin-left:6px;flex-shrink:0}.change-badge-new{background:#2f8a3a;color:#fff}.change-badge-modified{background:#c8892c;color:#fff}.canopy-topbar{flex-wrap:wrap;gap:8px 18px;align-items:flex-start;padding:10px 16px}.topbar-title{flex:1 1 280px;min-width:0}.topbar-controls{display:flex;flex-wrap:wrap;align-items:center;justify-content:flex-end;gap:8px 10px;margin-left:auto;min-width:0}.tb-group{display:inline-flex;gap:4px}.tb-btn{font-family:var(--font-mono);font-size:11px;font-weight:700;color:var(--ink);background:var(--paper-raised);border:1px solid var(--contour);border-radius:7px;padding:6px 10px;min-width:30px;cursor:pointer;white-space:nowrap;transition:background .12s ease}.tb-btn:hover:not(:disabled){background:var(--paper-hover)}.tb-btn.active{background:var(--ink);color:var(--paper)}.tb-btn:disabled{opacity:.4;cursor:default}.changes-btn{white-space:nowrap}.picker-entry-btn{white-space:nowrap;max-width:100%;overflow:hidden;text-overflow:ellipsis}@media(max-width:1100px){.canopy-stats{display:none}}@media(max-width:1000px){.canopy-hint{display:none}}.canopy-body{flex:1;display:flex;min-height:0;position:relative}.canopy-canvas{flex:1;position:relative;min-width:0}.side-panel{background:var(--paper-raised);border-right:1px solid var(--contour);min-height:0}.side-panel.docked{flex:0 0 260px;width:260px;position:relative;display:flex;flex-direction:column;transition:flex-basis .15s ease,width .15s ease}.side-panel.docked.collapsed{flex-basis:30px;width:30px}.side-scroll{overflow-y:auto;flex:1;padding:10px 12px 14px 10px;display:flex;flex-direction:column;gap:10px;min-height:0}.side-title{font-family:var(--font-mono);font-size:9.5px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:var(--ink-faint);padding-right:26px;display:flex;justify-content:space-between;align-items:center}.side-handle{position:absolute;top:6px;right:4px;width:22px;height:22px;border-radius:6px;border:1px solid var(--contour);background:var(--paper);color:var(--ink-dim);cursor:pointer;z-index:2;line-height:1;font-size:14px;padding:0}.side-panel.docked.collapsed .side-handle{right:3px}.side-handle:hover{background:var(--paper-hover)}.side-panel.drawer{position:absolute;top:0;bottom:0;left:0;width:270px;max-width:86%;z-index:26;display:flex;flex-direction:column;transform:translate(-104%);visibility:hidden;transition:transform .18s ease,visibility 0s linear .18s;box-shadow:var(--shadow-lg)}.side-panel.drawer.open{transform:none;visibility:visible;transition:transform .18s ease}.side-scrim{position:absolute;inset:0;z-index:25;background:#2823142e}.side-close{border:none;background:none;cursor:pointer;color:var(--ink-dim);font-size:13px;padding:0 2px}.side-groups{display:flex;flex-direction:column;gap:12px}.canopy-edge-path{fill:none;stroke:var(--ink-dim);stroke-width:2px;stroke-linecap:round;stroke-linejoin:round;transition:opacity .12s ease,stroke-width .12s ease}.react-flow__edge.cross-service .canopy-edge-path{stroke:var(--accent-cross);stroke-dasharray:7 5}.canopy-edge-path.hl{stroke:#c8892c;stroke-width:3px;stroke-dasharray:none}.canopy-edge-path.dim{opacity:.14}.v-scrollbar-track.minimap-open{bottom:196px}.h-scrollbar-track{position:absolute;left:10px;right:30px;bottom:4px;height:10px;border-radius:6px;background:#b4a88a29;z-index:5;cursor:pointer}.h-scrollbar-track.minimap-open{right:230px}.h-scrollbar-thumb{position:absolute;top:0;height:100%;border-radius:6px;background:var(--ink-faint);opacity:.55;cursor:grab;transition:opacity .15s ease,background .15s ease}.h-scrollbar-thumb:hover{opacity:.85;background:var(--ink-dim)}.h-scrollbar-thumb:active{cursor:grabbing;opacity:1}.react-flow__minimap{margin:14px 14px 18px}.step-expand.step-toggle{width:22px;height:22px;min-width:22px;padding:0;margin:0;display:inline-flex;align-items:center;justify-content:center;border-radius:6px;font-size:12px;line-height:1;border:1px solid var(--contour);background:var(--paper);color:var(--ink-dim);cursor:pointer;flex:0 0 22px}.step-expand.step-toggle:hover{background:var(--paper-hover);color:var(--ink)}.step-expand.step-toggle.open{background:var(--paper);color:var(--ink)}.chip-more{margin-left:auto;font-family:var(--font-mono);font-size:9px;font-weight:700;color:var(--accent-cross);background:var(--accent-cross-bg);border-radius:8px;padding:0 6px}.seg{display:inline-flex;border:1px solid var(--contour);border-radius:8px;overflow:hidden;width:100%}.seg button{flex:1;border:none;background:var(--paper);color:var(--ink-dim);font-family:var(--font-mono);font-size:10.5px;font-weight:700;padding:6px 8px;cursor:pointer}.seg button+button{border-left:1px solid var(--contour)}.seg button.on{background:var(--ink);color:var(--paper)}.step-node.selected-entry{border-color:var(--accent-cross);box-shadow:0 0 0 2px var(--accent-cross),var(--shadow-md)}.step-node.parent-card{border-style:dashed;background:var(--paper)}.caller-tag{font-family:var(--font-mono);font-size:8px;font-weight:800;letter-spacing:.05em;text-transform:uppercase;color:var(--accent-cross);background:var(--accent-cross-bg);border-radius:4px;padding:1px 5px}.excerpt-gap{font-family:var(--font-mono);font-size:9.5px;color:var(--ink-faint);padding:2px 4px;height:20px;line-height:16px}.branch-step-chip.call-target{background:var(--accent-cross-bg);border-color:var(--accent-cross);border-style:solid;box-shadow:0 0 0 1.5px var(--accent-cross)}.context-chip-node{display:flex;align-items:center;justify-content:center;width:100%;height:100%;border:1px dashed var(--accent-cross);background:var(--accent-cross-bg);box-shadow:none;padding:0 12px}.context-chip-text{font-family:var(--font-mono);font-size:11px;font-weight:700;color:var(--accent-cross)}.trigger-node{display:flex;align-items:center;gap:8px;width:100%;height:100%;padding:0 12px;background:var(--paper-raised);border:1px solid var(--accent-cross)}.trigger-node.inferred{border-style:dashed;color:var(--ink-dim)}.trigger-kind{font-family:var(--font-mono);font-size:8.5px;font-weight:800;letter-spacing:.05em;text-transform:uppercase;background:var(--accent-cross-bg);color:var(--accent-cross);border-radius:4px;padding:2px 6px;flex-shrink:0}.trigger-label{font-family:var(--font-mono);font-size:11px;font-weight:600;color:var(--ink);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}[data-lod=compact] .step-node .step-file,[data-lod=compact] .step-node .step-cat,[data-lod=compact] .step-node .source-icon,[data-lod=compact] .step-node .change-badge,[data-lod=compact] .step-node .caller-tag,[data-lod=compact] .step-node .chip-more,[data-lod=compact] .step-node .promoted-hint,[data-lod=compact] .step-node .excerpt-gap,[data-lod=compact] .step-node .branch-condition-text,[data-lod=compact] .step-node .branch-condition-kind,[data-lod=compact] .step-node .branch-arrow-label,[data-lod=compact] .step-node .branch-step-name,[data-lod=compact] .step-node .compact-label,[data-lod=compact] .step-node .compact-dot,[data-lod=compact] .step-node .runtime-bucket-header,[data-lod=compact] .step-node .runtime-tag{visibility:hidden}[data-lod=compact] .step-node .branch-step-chip{background:var(--accent-cross-bg);border-color:var(--accent-cross)}[data-lod=compact] .step-node .branch-step-chip.promoted{background:var(--accent-cross)}[data-lod=compact] .step-node .runtime-bucket-item.compact{background:var(--accent-unknown-bg);border-radius:4px}[data-lod=compact] .step-node .runtime-bucket-item.compact:has(.runtime-tag-runtime-dispatched){background:var(--accent-cross-bg)}[data-lod=compact] .step-node .runtime-bucket-item.compact:has(.runtime-tag-return-value){background:var(--accent-client-bg)}[data-lod=compact] .step-node .branch-diagram{background:var(--paper)}[data-lod=compact] .step-node .step-name,[data-lod=boxes] .step-node .step-name{transform:scale(var(--inv-zoom, 1));transform-origin:left center;max-width:calc(100% / var(--inv-zoom, 1));white-space:nowrap;overflow:hidden;text-overflow:ellipsis;display:block;font-weight:700;position:relative;z-index:2}[data-lod=boxes] .step-node .step-body-contained,[data-lod=boxes] .step-node .step-file,[data-lod=boxes] .step-node .step-cat,[data-lod=boxes] .step-node .source-icon,[data-lod=boxes] .step-node .change-badge,[data-lod=boxes] .step-node .caller-tag,[data-lod=boxes] .step-node .step-badge,[data-lod=boxes] .step-node .step-toggle{visibility:hidden}[data-lod=boxes] .step-node{background:var(--paper-raised)}.back-btn{margin-right:4px;padding:4px 9px}.side-sub{font-size:11.5px;line-height:1.4;color:var(--ink-dim);margin:-4px 0 2px;padding-right:6px}.react-flow__edge.hop-solid .canopy-edge-path{stroke-dasharray:none}.react-flow__edge.hop-dashed .canopy-edge-path{stroke-dasharray:7 5}.react-flow__edge.hop-solid .canopy-edge-path:not(.hl),.react-flow__edge.hop-dashed .canopy-edge-path:not(.hl){stroke:var(--accent-cross);stroke-width:2.2px}.hop-node{width:100%;height:100%;padding:7px 10px 8px;display:flex;flex-direction:column;gap:2px;cursor:pointer;background:var(--accent-cross-bg);border:1.5px solid var(--accent-cross);overflow:hidden}.hop-node.hop-dashed{border-style:dashed}.hop-top{display:flex;align-items:center;justify-content:space-between;gap:6px}.hop-svc{font-family:var(--font-mono);font-size:9px;font-weight:700;text-transform:uppercase;letter-spacing:.03em;color:var(--accent-cross);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}.hop-tag{font-family:var(--font-mono);font-size:8px;font-weight:700;text-transform:uppercase;border-radius:4px;padding:1px 5px;background:var(--paper-raised);color:var(--ink-dim);flex-shrink:0}.hop-tag-exact,.hop-tag-resolved{color:var(--accent-client)}.hop-call{font-family:var(--font-mono);font-size:10.5px;font-weight:700;color:var(--ink);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.hop-handler{font-family:var(--font-mono);font-size:9.5px;color:var(--ink-dim);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-height:12px}.hop-view{align-self:flex-start;margin-top:auto;border:1px solid var(--accent-cross);background:var(--paper-raised);color:var(--accent-cross);border-radius:6px;font-size:10px;font-weight:600;padding:2px 8px;cursor:pointer}.hop-view:hover{background:var(--paper-hover)}.called-from-chip{display:block;max-width:100%;margin-top:4px;border:1px solid var(--accent-cross);background:var(--accent-cross-bg);color:var(--accent-cross);border-radius:999px;font-family:var(--font-mono);font-size:9.5px;font-weight:600;padding:2px 9px;cursor:pointer;text-align:left;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.called-from-chip:hover{background:var(--paper-hover)}.hop-chooser{position:fixed;z-index:200;width:284px;background:var(--paper-raised);border:1px solid var(--contour);border-radius:10px;box-shadow:var(--shadow-lg);padding:6px;display:flex;flex-direction:column;gap:2px}.hop-chooser-label{font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:.04em;color:var(--ink-faint);padding:2px 6px 4px}.hop-chooser-item{display:flex;flex-direction:column;align-items:flex-start;text-align:left;border:none;background:none;border-radius:6px;padding:5px 8px;cursor:pointer}.hop-chooser-item:hover{background:var(--paper-hover)}.hop-chooser-title{font-family:var(--font-mono);font-size:11px;font-weight:600;color:var(--ink);max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.hop-chooser-sub{font-size:10px;color:var(--ink-dim)}.hop-chooser-more{font-size:10.5px;color:var(--ink-dim);padding:3px 8px;font-style:italic}[data-lod=compact] .hop-node .hop-handler,[data-lod=compact] .hop-node .hop-view,[data-lod=compact] .hop-node .hop-tag,[data-lod=boxes] .hop-node .hop-handler,[data-lod=boxes] .hop-node .hop-view,[data-lod=boxes] .hop-node .hop-tag,[data-lod=boxes] .hop-node .hop-call,[data-lod=boxes] .called-from-chip{visibility:hidden}.canopy-topbar{flex-wrap:nowrap;align-items:center;gap:10px 14px;padding:8px 16px}.canopy-crumbs{flex:1 1 auto;min-width:0;overflow:hidden;flex-wrap:nowrap;white-space:nowrap}button.crumb{background:none;border:none;font:inherit;font-size:13px;font-weight:500}.crumb{max-width:220px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:0 1 auto}.crumb.current{max-width:320px}.topbar-controls{flex:0 0 auto;flex-wrap:nowrap;gap:6px 8px}.icon-btn{position:relative;display:inline-flex;align-items:center;justify-content:center;gap:4px;min-width:32px;height:30px;padding:0 8px;border:1px solid var(--contour);border-radius:7px;background:var(--paper-raised);color:var(--ink);cursor:pointer;transition:background .12s ease}.icon-btn:hover{background:var(--paper-hover)}.icon-btn.active{background:var(--ink);color:var(--paper)}.icon-btn .changes-btn-count{margin-left:0}button:focus-visible,[role=button]:focus-visible,.search-input:focus-visible,.code-box:focus-visible,a:focus-visible{outline:2px solid var(--accent-cross);outline-offset:2px}.search{position:relative;flex:0 1 340px;min-width:150px}.search-input{width:100%;box-sizing:border-box;height:30px;padding:0 10px;border:1px solid var(--contour);border-radius:7px;background:var(--paper);color:var(--ink);font:12px var(--font-ui)}.search-input::placeholder{color:var(--ink-faint)}.search-results{position:absolute;top:34px;left:0;width:min(520px,calc(100vw - 32px));max-height:60vh;overflow-y:auto;z-index:45;background:var(--paper-raised);border:1px solid var(--contour);border-radius:10px;box-shadow:var(--shadow-lg);padding:6px}.search-group-title{font-family:var(--font-mono);font-size:9.5px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:var(--ink-faint);padding:6px 8px 3px}.search-item{display:flex;align-items:baseline;gap:10px;padding:5px 8px;border-radius:6px;cursor:pointer}.search-item.active,.search-item:hover{background:var(--paper-hover)}.search-name{font-size:12.5px;font-weight:600;color:var(--ink);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;flex:0 1 auto;max-width:55%}.search-meta{font-family:var(--font-mono);font-size:10px;color:var(--ink-faint);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0;margin-left:auto}.search-empty{padding:10px;font-size:12px;color:var(--ink-dim)}.modebar{display:flex;align-items:center;gap:12px;padding:6px 16px;background:var(--paper-raised);border-bottom:1px solid var(--contour)}.mode-toggle{width:auto}.mode-toggle button{flex:none;padding:5px 14px}.disclaimer-bar{padding:5px 16px;font-size:12px;line-height:1.4;color:var(--ink-dim);background:var(--accent-cross-bg);border-bottom:1px solid var(--contour)}.disclaimer-bar a{color:var(--accent-cross);font-weight:700}button.context-chip{display:block;width:100%;text-align:left;font-family:inherit}.context-chip.current{background:var(--ink);color:var(--paper);border-color:var(--ink)}.context-chip.current:hover{background:var(--ink)}.code-overlay{flex:0 0 440px;width:440px;min-width:0;min-height:0;display:flex;flex-direction:column;background:var(--paper-raised);border-left:1px solid var(--contour);box-shadow:-8px 0 26px #2823141a;z-index:22}.ov-head{display:flex;align-items:flex-start;gap:8px;padding:12px 14px 8px;border-bottom:1px solid var(--contour)}.ov-title{flex:1;min-width:0}.ov-name{font-size:15px;font-weight:700;color:var(--ink);word-break:break-word}.ov-file{font-family:var(--font-mono);font-size:11px;color:var(--ink-dim);margin-top:2px;word-break:break-all}.ov-close{border:none;background:none;cursor:pointer;font-size:15px;color:var(--ink-faint);padding:4px 6px;border-radius:6px}.ov-close:hover{color:var(--ink);background:var(--paper-hover)}.ov-scroll{flex:1;min-height:0;overflow-y:auto;padding:8px 14px 18px}.ov-section{margin-top:12px}.ov-label{font-size:9.5px;text-transform:uppercase;letter-spacing:.07em;color:var(--ink-faint);font-weight:700;margin-bottom:5px}.ov-count{margin-left:4px;background:var(--paper);border-radius:8px;padding:0 6px;color:var(--ink-dim)}.ov-note{font-size:12px;color:var(--ink-dim);line-height:1.5}.ov-warn{color:#8a3326}.ov-removed-note{display:inline-block;font-weight:700;color:#8a3326;background:#f3d9d4;border-radius:6px;padding:3px 9px;margin-bottom:8px}.ov-meta{font-family:var(--font-mono);font-size:11px;color:var(--ink-dim);word-break:break-all;line-height:1.6}.ov-meta b{color:var(--ink);margin-right:6px}.ov-edge-ends{display:flex;align-items:center;gap:6px;flex-wrap:wrap;margin-bottom:4px}.ov-arrow{color:var(--ink-faint)}.code-box{max-height:46vh;overflow:auto;background:var(--paper);border:1px solid var(--contour);border-radius:8px;font-family:var(--font-mono);font-size:11.5px;line-height:1.55;position:relative}.code-line{display:flex;white-space:pre}.code-no{flex:0 0 46px;text-align:right;padding-right:10px;color:var(--ink-faint);user-select:none;background:var(--paper-raised);position:sticky;left:0}.code-text{padding-right:12px;color:var(--ink)}.code-line.in-range{background:#c8892c29}.code-line.in-range .code-no{color:var(--ink);font-weight:700;background:#c8892c38}.ov-item{display:flex;align-items:baseline;gap:8px;width:100%;text-align:left;font:inherit;font-size:12px;color:var(--ink);background:var(--paper);border:1px solid var(--contour);border-radius:6px;padding:5px 8px;margin-top:4px;cursor:pointer}.ov-item:hover{background:var(--paper-hover)}.ov-item.dashed{border-style:dashed}.ov-i-name{font-weight:600;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ov-i-meta{margin-left:auto;font-family:var(--font-mono);font-size:9.5px;color:var(--ink-faint);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:55%}.chg-group-title{font-family:var(--font-mono);font-size:9.5px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:var(--ink-faint);margin:12px 0 2px}.chg-row.clickable{cursor:pointer;border-radius:6px;padding:3px 6px}.chg-row.clickable:hover{background:var(--paper)}.chg-row.chg-open-wf{color:var(--accent-cross);font-weight:700}.chg-section-head .chg-tag{margin-left:2px}.has-overlay .changes-panel{right:452px}@media(max-width:1099px){.code-overlay{position:fixed;left:0;right:0;bottom:0;width:auto;flex:none;height:58vh;border-left:none;border-top:1px solid var(--contour);border-radius:12px 12px 0 0;box-shadow:0 -10px 30px #2823142e;z-index:36}.code-box{max-height:30vh}.has-overlay .changes-panel{right:12px}.changes-panel{z-index:40}}@media(max-width:820px){.canopy-topbar{flex-wrap:wrap}.canopy-crumbs{flex:1 1 100%}.search{flex:1 1 160px}.topbar-controls{flex-wrap:wrap}}@media(max-width:480px){.changes-panel{left:8px;right:8px;width:auto}.search-results{width:calc(100vw - 16px)}}.changes-panel{top:calc(var(--chrome-h, 68px) + 8px)}.search-flag{font-family:var(--font-mono);font-size:8.5px;font-weight:700;letter-spacing:.03em;text-transform:uppercase;color:var(--ink-dim);border:1px solid var(--contour);border-radius:4px;padding:0 5px;margin-left:8px;white-space:nowrap;flex-shrink:0}:root{--diff-add: #dcefd9;--diff-del: #f3d9d4;--diff-paper: var(--paper);--diff-ink: var(--ink);--diff-gutter: var(--ink-faint);--diff-add-sign: #2f6a2a;--diff-del-sign: #8a3326}.ov-tabs{display:flex;gap:4px;border-bottom:1px solid var(--contour);margin:2px 0 10px}.ov-tab{border:1px solid transparent;border-bottom:none;background:none;color:var(--ink-dim);font-family:var(--font-mono);font-size:11px;font-weight:700;padding:5px 12px;border-radius:8px 8px 0 0;cursor:pointer}.ov-tab.on{background:var(--paper-raised);color:var(--ink);border-color:var(--contour);margin-bottom:-1px}.ov-tab:focus-visible{outline:2px solid var(--accent-cross);outline-offset:1px}.diff-head{display:flex;flex-wrap:wrap;align-items:center;gap:8px;margin-bottom:8px;font-family:var(--font-mono);font-size:11px}.diff-stat{font-weight:700;color:var(--ink)}.diff-flag{border:1px solid var(--contour);border-radius:4px;padding:0 6px;font-size:10px;font-weight:700;color:var(--ink-dim)}.diff-moved{color:var(--ink-dim);overflow-wrap:anywhere;font-size:10px}.diff-box{max-height:52vh;overflow:auto;background:var(--diff-paper);color:var(--diff-ink);border:1px solid var(--contour);border-radius:8px;font-family:var(--font-mono);font-size:11.5px;line-height:1.5;padding:4px 0}.diff-row{display:flex;align-items:baseline;min-width:max-content;width:100%;white-space:pre}.diff-row.add{background:var(--diff-add)}.diff-row.del{background:var(--diff-del)}.diff-row.hunk{background:transparent;color:var(--diff-gutter);font-size:10.5px;padding:3px 8px;border-top:1px dashed var(--contour);border-bottom:1px dashed var(--contour);margin:4px 0}.diff-row.hunk:first-child{margin-top:0;border-top:none}.diff-no{flex:none;width:38px;text-align:right;padding-right:6px;color:var(--diff-gutter);user-select:none;font-size:10.5px}.diff-sign{flex:none;width:16px;text-align:center;font-weight:800;user-select:none}.diff-row.add .diff-sign{color:var(--diff-add-sign)}.diff-row.del .diff-sign{color:var(--diff-del-sign)}.diff-text{flex:1;padding-right:10px}.diff-row.diff-hit{outline:2px solid var(--accent-cross);outline-offset:-2px}.diff-hit-tag,.code-line .diff-hit-tag{flex:none;align-self:center;margin:0 8px 0 auto;font-family:var(--font-mono);font-size:8.5px;font-weight:800;letter-spacing:.04em;text-transform:uppercase;color:var(--accent-cross);background:var(--accent-cross-bg);border-radius:4px;padding:0 5px}.code-line.code-hit{outline:2px solid var(--accent-cross);outline-offset:-2px;display:flex}.chg-stat{margin-left:8px;font-size:9.5px;font-weight:700;color:var(--ink-dim);white-space:nowrap}.chg-stat.pending{min-width:1px}.rt-band{width:100%;height:100%;border:1px solid;border-radius:14px;opacity:.55;pointer-events:none}.rt-band-head{display:flex;flex-direction:column;gap:1px;padding:10px 14px}.rt-band-name{font-family:var(--font-mono);font-size:13px;font-weight:700}.rt-band-kind{font-family:var(--font-mono);font-size:9.5px;font-weight:600;opacity:.85}.rt-node{width:100%;height:100%;background:var(--paper-raised);border:1px solid var(--contour);border-left:4px solid var(--accent-cross);border-radius:8px;box-shadow:var(--shadow-sm);padding:5px 10px;cursor:pointer;overflow:hidden}.rt-node:hover{box-shadow:var(--shadow-md)}.rt-node.start{border-color:var(--ink);border-left-width:4px}.rt-name{font-family:var(--font-mono);font-size:11.5px;font-weight:700;color:var(--ink);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.rt-file{font-family:var(--font-mono);font-size:9.5px;color:var(--ink-faint);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;margin-top:2px}.rt-more{font-family:var(--font-mono);font-size:10.5px;font-weight:700;color:var(--ink-dim);background:var(--paper-raised);border:1px dashed var(--contour);border-radius:8px;padding:6px 10px;white-space:nowrap}.react-flow__edge.rt-edge path.react-flow__edge-path{stroke:#6b664f;stroke-width:1.8;fill:none}.react-flow__edge.rt-cross path.react-flow__edge-path{stroke:#4a6480;stroke-width:2.2}.react-flow__edge.rt-dashed path.react-flow__edge-path{stroke-dasharray:8 6}.react-flow__edge.rt-solid path.react-flow__edge-path{stroke-dasharray:none}.project-name{flex:none;max-width:150px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-family:var(--font-mono);font-size:11px;font-weight:600;color:var(--ink-faint);padding-right:8px;margin-right:3px;border-right:1px solid var(--contour)}.rt-progress{position:absolute;left:50%;top:10px;transform:translate(-50%);z-index:5;font-family:var(--font-mono);font-size:11px;font-weight:700;color:var(--ink-dim);background:var(--paper-raised);border:1px solid var(--contour);border-radius:999px;padding:3px 12px;box-shadow:var(--shadow-sm);pointer-events:none}.rt-loop{float:right;font-family:var(--font-mono);font-size:10px;font-weight:800;color:var(--accent-cross)}.chg-modes{display:flex;margin:4px 0 10px;border:1px solid var(--contour);border-radius:8px;overflow:hidden}.chg-modes button{flex:1;font-size:10.5px;padding:5px 6px}.chg-since{background:var(--paper);border:1px solid var(--contour);border-radius:8px;padding:8px 10px;margin-bottom:10px}.chg-since-head{font-family:var(--font-mono);font-size:11.5px;font-weight:700;color:var(--ink)}.chg-since-note{font-size:11px;color:var(--ink-dim);margin-top:4px}.react-flow__edge.rt-lite path.react-flow__edge-path,.rt-line{stroke:#b9b196;stroke-width:1.4;fill:none}.search-item-rich{flex-direction:column;align-items:stretch;gap:3px}.search-line1,.search-line2{display:flex;align-items:baseline;gap:8px;min-width:0}.search-line2{flex-wrap:wrap}.search-method{font-family:var(--font-mono);font-size:10.5px;color:var(--accent-cross)}.search-chip{font-family:var(--font-mono);font-size:8.5px;font-weight:700;letter-spacing:.03em;text-transform:uppercase;color:var(--ink-dim);background:var(--paper-hover);border-radius:4px;padding:0 5px;white-space:nowrap;flex-shrink:0}.search-appears{font-size:10.5px;color:var(--ink-dim)}.search-switch{display:inline-flex;flex-wrap:wrap;gap:4px;align-items:baseline}.search-switch-btn{font:10.5px var(--font-ui);color:var(--ink);background:var(--paper);border:1px solid var(--contour);border-radius:5px;padding:1px 6px;cursor:pointer;max-width:220px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.search-switch-btn:hover{background:var(--paper-hover)}.search-code-text{font-family:var(--font-mono);font-size:11px;color:var(--ink);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.start-head,.start-more,.start-item{display:flex;align-items:baseline;gap:8px;width:100%;box-sizing:border-box;text-align:left;background:none;border:0;color:var(--ink);font:inherit;cursor:pointer;border-radius:6px;padding:5px 8px}.start-head:hover,.start-more:hover,.start-item:hover{background:var(--paper-hover)}.start-caret{width:10px;color:var(--ink-faint)}.start-item{padding-left:26px}.start-more{padding-left:26px;font-size:11px;color:var(--ink-dim)}.canopy-topbar:focus-within{z-index:50}.search-ask{display:block;width:100%;box-sizing:border-box;text-align:left;background:none;border:0;border-top:1px solid var(--contour);margin-top:6px;padding:8px 8px 4px;font:12px var(--font-ui);color:var(--accent-cross);cursor:pointer}.search-ask:hover{text-decoration:underline}.ask-ai{position:absolute;top:34px;left:0;width:min(520px,calc(100vw - 32px));z-index:46;box-sizing:border-box;background:var(--paper-raised);border:1px solid var(--contour);border-radius:10px;box-shadow:var(--shadow-lg);padding:10px 12px 12px;display:flex;flex-direction:column;gap:8px}.ask-ai-head{display:flex;align-items:center;justify-content:space-between;font-size:12.5px}.ask-ai-text{width:100%;box-sizing:border-box;resize:vertical;font:12.5px var(--font-ui);color:var(--ink);background:var(--paper);border:1px solid var(--contour);border-radius:7px;padding:7px 9px}.ask-ai-row{display:flex;align-items:center;gap:10px;flex-wrap:wrap}.ask-ai-primary{font:600 12px var(--font-ui);color:#fff;background:var(--accent-cross);border:0;border-radius:7px;padding:7px 14px;cursor:pointer}.ask-ai-secondary{display:inline-block;font:12px var(--font-ui);color:var(--ink);background:var(--paper);border:1px solid var(--contour);border-radius:7px;padding:5px 10px;cursor:pointer;text-decoration:none}.ask-ai-secondary:hover{background:var(--paper-hover)}.ask-ai-note,.ask-ai-privacy{font-size:10.5px;color:var(--ink-dim)}.ask-ai-preview summary{font-size:11px;color:var(--ink-dim);cursor:pointer}.ask-ai-preview pre{max-height:180px;overflow:auto;white-space:pre-wrap;font:10.5px var(--font-mono);color:var(--ink-dim);margin:6px 0 0}@media(max-width:480px){.ask-ai{width:calc(100vw - 16px)}}.modebar-right{margin-left:auto;display:flex;align-items:center;gap:14px}.fb-link{font:11.5px var(--font-ui);color:var(--ink-dim);text-decoration:none;border-bottom:1px dotted var(--ink-faint)}.fb-link:hover{color:var(--ink);border-bottom-color:var(--ink)}.ai-open-btn{display:inline-flex;align-items:center;gap:6px;font:600 12px var(--font-ui);color:var(--paper-raised);background:var(--accent-cross);border:1px solid var(--accent-cross);border-radius:8px;padding:5px 12px;cursor:pointer}.ai-open-btn:hover{filter:brightness(1.08)}.ai-open-btn.on{background:var(--ink);border-color:var(--ink)}.ai-open-btn:focus-visible,.ai-btn:focus-visible,.ai-primary:focus-visible,.ai-row:focus-visible,.ai-link:focus-visible{outline:2px solid var(--accent-cross);outline-offset:2px}.ai-panel{position:fixed;right:16px;width:min(440px,calc(100vw - 32px));max-height:calc(100vh - 120px);z-index:48;display:flex;flex-direction:column;background:var(--paper-raised);color:var(--ink);border:1px solid var(--contour);border-radius:12px;box-shadow:var(--shadow-lg);font-family:var(--font-ui)}.ai-head{display:flex;align-items:center;gap:10px;padding:10px 12px 8px;font-size:13px;border-bottom:1px solid var(--contour)}.ai-sub{font-size:10.5px;color:var(--ink-dim);font-family:var(--font-mono)}.ai-spacer{flex:1}.ai-link{background:none;border:0;padding:2px 0;font:11.5px var(--font-ui);color:var(--accent-cross);cursor:pointer;text-decoration:underline;text-underline-offset:2px}.ai-link:disabled{color:var(--ink-faint);cursor:default;text-decoration:none}.ai-list{flex:1 1 auto;min-height:120px;overflow:auto;padding:10px 12px;display:flex;flex-direction:column;gap:14px}.ai-empty{font-size:12.5px;color:var(--ink-dim);line-height:1.5;padding:6px 2px}.ai-entry{display:flex;flex-direction:column;gap:8px}.ai-q{align-self:flex-end;max-width:92%;background:var(--paper-hover);border:1px solid var(--contour);border-radius:10px 10px 2px;padding:6px 10px;font-size:12.5px;white-space:pre-wrap;overflow-wrap:anywhere}.ai-status{display:flex;align-items:center;gap:8px;font-size:12px;color:var(--ink-dim)}.ai-dots{width:8px;height:8px;border-radius:50%;background:var(--accent-cross);animation:ai-pulse 1s ease-in-out infinite}@keyframes ai-pulse{0%,to{opacity:.25}50%{opacity:1}}@media(prefers-reduced-motion:reduce){.ai-dots{animation:none}}.ai-summary{font-size:12.5px;color:var(--ink)}.ai-note,.ai-subtle{font-size:11px;color:var(--ink-dim)}.ai-results{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:6px}.ai-row{width:100%;text-align:left;display:flex;flex-direction:column;gap:3px;background:var(--paper);border:1px solid var(--contour);border-radius:8px;padding:7px 10px;cursor:pointer;font-family:var(--font-ui);color:var(--ink)}.ai-row:hover{background:var(--paper-hover)}.ai-row.active{border-color:var(--accent-cross);box-shadow:inset 3px 0 0 var(--accent-cross)}.ai-row-top{display:flex;align-items:baseline;gap:8px}.ai-row-label{font-size:12.5px;font-weight:600;flex:1;min-width:0;overflow-wrap:anywhere}.ai-row-reason{font-size:11.5px;color:var(--ink-dim);line-height:1.4}.ai-row-where{font:10px var(--font-mono);color:var(--ink-faint);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ai-badge{font:600 9.5px var(--font-mono);letter-spacing:.04em;text-transform:uppercase;padding:1px 6px;border-radius:99px;border:1px solid var(--contour);color:var(--ink-dim);background:var(--paper-raised);flex:none}.ai-badge-node{color:var(--accent-client);background:var(--accent-client-bg);border-color:transparent}.ai-badge-workflow{color:var(--accent-server);background:var(--accent-server-bg);border-color:transparent}.ai-badge-search{color:var(--accent-cross);background:var(--accent-cross-bg);border-color:transparent}.ai-entry-foot{display:flex;align-items:center;gap:10px;flex-wrap:wrap}.ai-btn{font:12px var(--font-ui);color:var(--ink);background:var(--paper);border:1px solid var(--contour);border-radius:7px;padding:5px 11px;cursor:pointer}.ai-btn:hover:not(:disabled){background:var(--paper-hover)}.ai-btn:disabled{color:var(--ink-faint);cursor:default}.ai-primary{font:600 12px var(--font-ui);color:var(--paper-raised);background:var(--accent-cross);border:0;border-radius:7px;padding:6px 16px;cursor:pointer}.ai-primary:disabled{background:var(--contour);color:var(--ink-faint);cursor:default}.ai-problem{display:flex;flex-direction:column;align-items:flex-start;gap:6px;font-size:12px;line-height:1.45;background:var(--paper);border:1px solid var(--contour);border-left:3px solid var(--accent-server);border-radius:8px;padding:8px 10px;overflow-wrap:anywhere}.ai-problem span{color:var(--ink-dim)}.ai-install{color:var(--accent-cross);font-weight:600}.ai-small{font-size:11px}.ai-compose{border-top:1px solid var(--contour);padding:8px 12px 10px;display:flex;flex-direction:column;gap:8px}.ai-text{width:100%;resize:vertical;min-height:44px;max-height:160px;font:12.5px var(--font-ui);color:var(--ink);background:var(--paper);border:1px solid var(--contour);border-radius:8px;padding:7px 9px}.ai-row-actions{display:flex;align-items:center;gap:12px;flex-wrap:wrap}.ai-follow{display:inline-flex;align-items:center;gap:5px;font-size:11.5px;color:var(--ink-dim);cursor:pointer}.ai-foot{font-size:10.5px;color:var(--ink-dim)}.react-flow__node.ai-hit{outline:3px solid var(--accent-cross);outline-offset:3px;border-radius:10px}@media(max-width:700px){.ai-panel{right:8px;left:8px;width:auto}.modebar{flex-wrap:wrap}}.ai-answer{font-size:12.5px;line-height:1.55;color:var(--ink);overflow-wrap:anywhere}.ai-answer p{margin:0 0 8px}.ai-answer ul,.ai-answer ol{margin:0 0 8px;padding-left:20px}.ai-answer li{margin:2px 0}.ai-code{font:11.5px var(--font-mono);background:var(--paper-hover);border-radius:4px;padding:0 4px}.ai-inline-link{background:none;border:0;padding:0;font:inherit;color:var(--accent-cross);text-decoration:underline;text-underline-offset:2px;cursor:pointer}.ai-inline-link.code{font:11.5px var(--font-mono);background:var(--accent-cross-bg);border-radius:4px;padding:0 4px;text-decoration:none}.ai-inline-link.bold{font-weight:700}.ai-topline{align-self:flex-start;background:none;border:0;padding:0;font:11px var(--font-ui);color:var(--accent-cross);cursor:pointer;text-decoration:underline;text-underline-offset:2px}.ai-places{display:flex;flex-direction:column;gap:8px;border-top:1px dashed var(--contour);padding-top:8px}.ai-places-title{font:700 10.5px var(--font-mono);letter-spacing:.06em;text-transform:uppercase;color:var(--ink-dim)}.ai-allow-row{display:flex;gap:8px}.ai-using{font-size:11px;color:var(--ink-dim)}.ai-change{display:flex;flex-wrap:wrap;gap:6px;align-items:center}.ai-paste{display:inline-flex;gap:6px;flex:1 1 100%}.ai-text-input{flex:1;min-width:0;font:11.5px var(--font-mono);color:var(--ink);background:var(--paper);border:1px solid var(--contour);border-radius:7px;padding:5px 8px}.react-flow{direction:ltr;--xy-edge-stroke-default: #b1b1b7;--xy-edge-stroke-width-default: 1;--xy-edge-stroke-selected-default: #555;--xy-connectionline-stroke-default: #b1b1b7;--xy-connectionline-stroke-width-default: 1;--xy-attribution-background-color-default: rgba(255, 255, 255, .5);--xy-minimap-background-color-default: #fff;--xy-minimap-mask-background-color-default: rgba(240, 240, 240, .6);--xy-minimap-mask-stroke-color-default: transparent;--xy-minimap-mask-stroke-width-default: 1;--xy-minimap-node-background-color-default: #e2e2e2;--xy-minimap-node-stroke-color-default: transparent;--xy-minimap-node-stroke-width-default: 2;--xy-background-color-default: transparent;--xy-background-pattern-dots-color-default: #91919a;--xy-background-pattern-lines-color-default: #eee;--xy-background-pattern-cross-color-default: #e2e2e2;background-color:var(--xy-background-color, var(--xy-background-color-default));--xy-node-color-default: inherit;--xy-node-border-default: 1px solid #1a192b;--xy-node-background-color-default: #fff;--xy-node-group-background-color-default: rgba(240, 240, 240, .25);--xy-node-boxshadow-hover-default: 0 1px 4px 1px rgba(0, 0, 0, .08);--xy-node-boxshadow-selected-default: 0 0 0 .5px #1a192b;--xy-node-border-radius-default: 3px;--xy-handle-background-color-default: #1a192b;--xy-handle-border-color-default: #fff;--xy-selection-background-color-default: rgba(0, 89, 220, .08);--xy-selection-border-default: 1px dotted rgba(0, 89, 220, .8);--xy-controls-button-background-color-default: #fefefe;--xy-controls-button-background-color-hover-default: #f4f4f4;--xy-controls-button-color-default: inherit;--xy-controls-button-color-hover-default: inherit;--xy-controls-button-border-color-default: #eee;--xy-controls-box-shadow-default: 0 0 2px 1px rgba(0, 0, 0, .08);--xy-edge-label-background-color-default: #ffffff;--xy-edge-label-color-default: inherit;--xy-resize-background-color-default: #3367d9}.react-flow.dark{--xy-edge-stroke-default: #3e3e3e;--xy-edge-stroke-width-default: 1;--xy-edge-stroke-selected-default: #727272;--xy-connectionline-stroke-default: #b1b1b7;--xy-connectionline-stroke-width-default: 1;--xy-attribution-background-color-default: rgba(150, 150, 150, .25);--xy-minimap-background-color-default: #141414;--xy-minimap-mask-background-color-default: rgba(60, 60, 60, .6);--xy-minimap-mask-stroke-color-default: transparent;--xy-minimap-mask-stroke-width-default: 1;--xy-minimap-node-background-color-default: #2b2b2b;--xy-minimap-node-stroke-color-default: transparent;--xy-minimap-node-stroke-width-default: 2;--xy-background-color-default: #141414;--xy-background-pattern-dots-color-default: #555;--xy-background-pattern-lines-color-default: #333;--xy-background-pattern-cross-color-default: #333;--xy-node-color-default: #f8f8f8;--xy-node-border-default: 1px solid #3c3c3c;--xy-node-background-color-default: #1e1e1e;--xy-node-group-background-color-default: rgba(240, 240, 240, .25);--xy-node-boxshadow-hover-default: 0 1px 4px 1px rgba(255, 255, 255, .08);--xy-node-boxshadow-selected-default: 0 0 0 .5px #999;--xy-handle-background-color-default: #bebebe;--xy-handle-border-color-default: #1e1e1e;--xy-selection-background-color-default: rgba(200, 200, 220, .08);--xy-selection-border-default: 1px dotted rgba(200, 200, 220, .8);--xy-controls-button-background-color-default: #2b2b2b;--xy-controls-button-background-color-hover-default: #3e3e3e;--xy-controls-button-color-default: #f8f8f8;--xy-controls-button-color-hover-default: #fff;--xy-controls-button-border-color-default: #5b5b5b;--xy-controls-box-shadow-default: 0 0 2px 1px rgba(0, 0, 0, .08);--xy-edge-label-background-color-default: #141414;--xy-edge-label-color-default: #f8f8f8}.react-flow__background{background-color:var(--xy-background-color-props, var(--xy-background-color, var(--xy-background-color-default)));pointer-events:none;z-index:-1}.react-flow__container{position:absolute;width:100%;height:100%;top:0;left:0}.react-flow__pane{z-index:1;touch-action:none}.react-flow__pane.draggable{cursor:grab}.react-flow__pane.dragging{cursor:grabbing}.react-flow__pane.selection{cursor:pointer}.react-flow__viewport{transform-origin:0 0;z-index:2;pointer-events:none}.react-flow__renderer{z-index:4}.react-flow__selection{z-index:6}.react-flow__nodesselection-rect:focus,.react-flow__nodesselection-rect:focus-visible{outline:none}.react-flow__edge-path{stroke:var(--xy-edge-stroke, var(--xy-edge-stroke-default));stroke-width:var(--xy-edge-stroke-width, var(--xy-edge-stroke-width-default));fill:none}.react-flow__connection-path{stroke:var(--xy-connectionline-stroke, var(--xy-connectionline-stroke-default));stroke-width:var(--xy-connectionline-stroke-width, var(--xy-connectionline-stroke-width-default));fill:none}.react-flow .react-flow__edges{position:absolute}.react-flow .react-flow__edges svg{overflow:visible;position:absolute;pointer-events:none}.react-flow__edge{pointer-events:visibleStroke}.react-flow__edge.selectable{cursor:pointer}.react-flow__edge.animated path{stroke-dasharray:5;animation:dashdraw .5s linear infinite}.react-flow__edge.animated path.react-flow__edge-interaction{stroke-dasharray:none;animation:none}.react-flow__edge.inactive{pointer-events:none}.react-flow__edge.selected,.react-flow__edge:focus,.react-flow__edge:focus-visible{outline:none}.react-flow__edge.selected .react-flow__edge-path,.react-flow__edge.selectable:focus .react-flow__edge-path,.react-flow__edge.selectable:focus-visible .react-flow__edge-path{stroke:var(--xy-edge-stroke-selected, var(--xy-edge-stroke-selected-default))}.react-flow__edge-textwrapper{pointer-events:all}.react-flow__edge .react-flow__edge-text{pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.react-flow__arrowhead polyline{stroke:var(--xy-edge-stroke, var(--xy-edge-stroke-default))}.react-flow__arrowhead polyline.arrowclosed{fill:var(--xy-edge-stroke, var(--xy-edge-stroke-default))}.react-flow__connection{pointer-events:none}.react-flow__connection .animated{stroke-dasharray:5;animation:dashdraw .5s linear infinite}svg.react-flow__connectionline{z-index:1001;overflow:visible;position:absolute}.react-flow__nodes{pointer-events:none;transform-origin:0 0}.react-flow__node{position:absolute;-webkit-user-select:none;-moz-user-select:none;user-select:none;pointer-events:all;transform-origin:0 0;box-sizing:border-box;cursor:default}.react-flow__node.selectable{cursor:pointer}.react-flow__node.draggable{cursor:grab;pointer-events:all}.react-flow__node.draggable.dragging{cursor:grabbing}.react-flow__nodesselection{z-index:3;transform-origin:left top;pointer-events:none}.react-flow__nodesselection-rect{position:absolute;pointer-events:all;cursor:grab}.react-flow__handle{position:absolute;pointer-events:none;min-width:5px;min-height:5px;width:6px;height:6px;background-color:var(--xy-handle-background-color, var(--xy-handle-background-color-default));border:1px solid var(--xy-handle-border-color, var(--xy-handle-border-color-default));border-radius:100%}.react-flow__handle.connectingfrom{pointer-events:all}.react-flow__handle.connectionindicator{pointer-events:all;cursor:crosshair}.react-flow__handle-bottom{top:auto;left:50%;bottom:0;transform:translate(-50%,50%)}.react-flow__handle-top{top:0;left:50%;transform:translate(-50%,-50%)}.react-flow__handle-left{top:50%;left:0;transform:translate(-50%,-50%)}.react-flow__handle-right{top:50%;right:0;transform:translate(50%,-50%)}.react-flow__edgeupdater{cursor:move;pointer-events:all}.react-flow__pane.selection .react-flow__panel{pointer-events:none}.react-flow__panel{position:absolute;z-index:5;margin:15px}.react-flow__panel.top{top:0}.react-flow__panel.bottom{bottom:0}.react-flow__panel.top.center,.react-flow__panel.bottom.center{left:50%;transform:translate(-15px) translate(-50%)}.react-flow__panel.left{left:0}.react-flow__panel.right{right:0}.react-flow__panel.left.center,.react-flow__panel.right.center{top:50%;transform:translateY(-15px) translateY(-50%)}.react-flow__attribution{font-size:10px;background:var(--xy-attribution-background-color, var(--xy-attribution-background-color-default));padding:2px 3px;margin:0}.react-flow__attribution a{text-decoration:none;color:#999}@keyframes dashdraw{0%{stroke-dashoffset:10}}.react-flow__edgelabel-renderer{position:absolute;width:100%;height:100%;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none;left:0;top:0}.react-flow__viewport-portal{position:absolute;width:100%;height:100%;left:0;top:0;-webkit-user-select:none;-moz-user-select:none;user-select:none}.react-flow__minimap{background:var( --xy-minimap-background-color-props, var(--xy-minimap-background-color, var(--xy-minimap-background-color-default)) )}.react-flow__minimap-svg{display:block}.react-flow__minimap-mask{fill:var( --xy-minimap-mask-background-color-props, var(--xy-minimap-mask-background-color, var(--xy-minimap-mask-background-color-default)) );stroke:var( --xy-minimap-mask-stroke-color-props, var(--xy-minimap-mask-stroke-color, var(--xy-minimap-mask-stroke-color-default)) );stroke-width:var( --xy-minimap-mask-stroke-width-props, var(--xy-minimap-mask-stroke-width, var(--xy-minimap-mask-stroke-width-default)) )}.react-flow__minimap-node{fill:var( --xy-minimap-node-background-color-props, var(--xy-minimap-node-background-color, var(--xy-minimap-node-background-color-default)) );stroke:var( --xy-minimap-node-stroke-color-props, var(--xy-minimap-node-stroke-color, var(--xy-minimap-node-stroke-color-default)) );stroke-width:var( --xy-minimap-node-stroke-width-props, var(--xy-minimap-node-stroke-width, var(--xy-minimap-node-stroke-width-default)) )}.react-flow__background-pattern.dots{fill:var( --xy-background-pattern-color-props, var(--xy-background-pattern-color, var(--xy-background-pattern-dots-color-default)) )}.react-flow__background-pattern.lines{stroke:var( --xy-background-pattern-color-props, var(--xy-background-pattern-color, var(--xy-background-pattern-lines-color-default)) )}.react-flow__background-pattern.cross{stroke:var( --xy-background-pattern-color-props, var(--xy-background-pattern-color, var(--xy-background-pattern-cross-color-default)) )}.react-flow__controls{display:flex;flex-direction:column;box-shadow:var(--xy-controls-box-shadow, var(--xy-controls-box-shadow-default))}.react-flow__controls.horizontal{flex-direction:row}.react-flow__controls-button{display:flex;justify-content:center;align-items:center;height:26px;width:26px;padding:4px;border:none;background:var(--xy-controls-button-background-color, var(--xy-controls-button-background-color-default));border-bottom:1px solid var( --xy-controls-button-border-color-props, var(--xy-controls-button-border-color, var(--xy-controls-button-border-color-default)) );color:var( --xy-controls-button-color-props, var(--xy-controls-button-color, var(--xy-controls-button-color-default)) );cursor:pointer;-webkit-user-select:none;-moz-user-select:none;user-select:none}.react-flow__controls-button svg{width:100%;max-width:12px;max-height:12px;fill:currentColor}.react-flow__edge.updating .react-flow__edge-path{stroke:#777}.react-flow__edge-text{font-size:10px}.react-flow__node.selectable:focus,.react-flow__node.selectable:focus-visible{outline:none}.react-flow__node-input,.react-flow__node-default,.react-flow__node-output,.react-flow__node-group{padding:10px;border-radius:var(--xy-node-border-radius, var(--xy-node-border-radius-default));width:150px;font-size:12px;color:var(--xy-node-color, var(--xy-node-color-default));text-align:center;border:var(--xy-node-border, var(--xy-node-border-default));background-color:var(--xy-node-background-color, var(--xy-node-background-color-default))}.react-flow__node-input.selectable:hover,.react-flow__node-default.selectable:hover,.react-flow__node-output.selectable:hover,.react-flow__node-group.selectable:hover{box-shadow:var(--xy-node-boxshadow-hover, var(--xy-node-boxshadow-hover-default))}.react-flow__node-input.selectable.selected,.react-flow__node-input.selectable:focus,.react-flow__node-input.selectable:focus-visible,.react-flow__node-default.selectable.selected,.react-flow__node-default.selectable:focus,.react-flow__node-default.selectable:focus-visible,.react-flow__node-output.selectable.selected,.react-flow__node-output.selectable:focus,.react-flow__node-output.selectable:focus-visible,.react-flow__node-group.selectable.selected,.react-flow__node-group.selectable:focus,.react-flow__node-group.selectable:focus-visible{box-shadow:var(--xy-node-boxshadow-selected, var(--xy-node-boxshadow-selected-default))}.react-flow__node-group{background-color:var(--xy-node-group-background-color, var(--xy-node-group-background-color-default))}.react-flow__nodesselection-rect,.react-flow__selection{background:var(--xy-selection-background-color, var(--xy-selection-background-color-default));border:var(--xy-selection-border, var(--xy-selection-border-default))}.react-flow__nodesselection-rect:focus,.react-flow__nodesselection-rect:focus-visible,.react-flow__selection:focus,.react-flow__selection:focus-visible{outline:none}.react-flow__controls-button:hover{background:var( --xy-controls-button-background-color-hover-props, var(--xy-controls-button-background-color-hover, var(--xy-controls-button-background-color-hover-default)) );color:var( --xy-controls-button-color-hover-props, var(--xy-controls-button-color-hover, var(--xy-controls-button-color-hover-default)) )}.react-flow__controls-button:disabled{pointer-events:none}.react-flow__controls-button:disabled svg{fill-opacity:.4}.react-flow__controls-button:last-child{border-bottom:none}.react-flow__controls.horizontal .react-flow__controls-button{border-bottom:none;border-right:1px solid var( --xy-controls-button-border-color-props, var(--xy-controls-button-border-color, var(--xy-controls-button-border-color-default)) )}.react-flow__controls.horizontal .react-flow__controls-button:last-child{border-right:none}.react-flow__resize-control{position:absolute}.react-flow__resize-control.left,.react-flow__resize-control.right{cursor:ew-resize}.react-flow__resize-control.top,.react-flow__resize-control.bottom{cursor:ns-resize}.react-flow__resize-control.top.left,.react-flow__resize-control.bottom.right{cursor:nwse-resize}.react-flow__resize-control.bottom.left,.react-flow__resize-control.top.right{cursor:nesw-resize}.react-flow__resize-control.handle{width:5px;height:5px;border:1px solid #fff;border-radius:1px;background-color:var(--xy-resize-background-color, var(--xy-resize-background-color-default));translate:-50% -50%}.react-flow__resize-control.handle.left{left:0;top:50%}.react-flow__resize-control.handle.right{left:100%;top:50%}.react-flow__resize-control.handle.top{left:50%;top:0}.react-flow__resize-control.handle.bottom{left:50%;top:100%}.react-flow__resize-control.handle.top.left,.react-flow__resize-control.handle.bottom.left{left:0}.react-flow__resize-control.handle.top.right,.react-flow__resize-control.handle.bottom.right{left:100%}.react-flow__resize-control.line{border-color:var(--xy-resize-background-color, var(--xy-resize-background-color-default));border-width:0;border-style:solid}.react-flow__resize-control.line.left,.react-flow__resize-control.line.right{width:1px;transform:translate(-50%);top:0;height:100%}.react-flow__resize-control.line.left{left:0;border-left-width:1px}.react-flow__resize-control.line.right{left:100%;border-right-width:1px}.react-flow__resize-control.line.top,.react-flow__resize-control.line.bottom{height:1px;transform:translateY(-50%);left:0;width:100%}.react-flow__resize-control.line.top{top:0;border-top-width:1px}.react-flow__resize-control.line.bottom{border-bottom-width:1px;top:100%}.react-flow__edge-textbg{fill:var(--xy-edge-label-background-color, var(--xy-edge-label-background-color-default))}.react-flow__edge-text{fill:var(--xy-edge-label-color, var(--xy-edge-label-color-default))}
|
|
2
2
|
/*# sourceMappingURL=bundle.css.map */
|