cg-code-graph 0.10.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (174) hide show
  1. cg_code_graph-0.10.1.dist-info/METADATA +678 -0
  2. cg_code_graph-0.10.1.dist-info/RECORD +174 -0
  3. cg_code_graph-0.10.1.dist-info/WHEEL +5 -0
  4. cg_code_graph-0.10.1.dist-info/entry_points.txt +3 -0
  5. cg_code_graph-0.10.1.dist-info/licenses/LICENSE +21 -0
  6. cg_code_graph-0.10.1.dist-info/top_level.txt +1 -0
  7. codegraph/__init__.py +2 -0
  8. codegraph/aitools.py +129 -0
  9. codegraph/apps.py +76 -0
  10. codegraph/blindspots.py +428 -0
  11. codegraph/bridges.py +1701 -0
  12. codegraph/cli.py +725 -0
  13. codegraph/concepts.py +362 -0
  14. codegraph/config.py +559 -0
  15. codegraph/core/__init__.py +0 -0
  16. codegraph/core/cache.py +375 -0
  17. codegraph/core/detect.py +80 -0
  18. codegraph/core/extractors.py +187 -0
  19. codegraph/core/fsutil.py +61 -0
  20. codegraph/core/generated.py +575 -0
  21. codegraph/core/model.py +174 -0
  22. codegraph/core/paths.py +175 -0
  23. codegraph/core/plugin.py +160 -0
  24. codegraph/core/store.py +80 -0
  25. codegraph/core/syntax_errors.py +132 -0
  26. codegraph/coverage.py +928 -0
  27. codegraph/doctor.py +453 -0
  28. codegraph/external.py +613 -0
  29. codegraph/indexer.py +336 -0
  30. codegraph/link.py +434 -0
  31. codegraph/lint_async.py +524 -0
  32. codegraph/mcp_server.py +1303 -0
  33. codegraph/parity.py +473 -0
  34. codegraph/parity_structure.py +307 -0
  35. codegraph/payload.py +321 -0
  36. codegraph/plans.py +1285 -0
  37. codegraph/platform_scan.py +643 -0
  38. codegraph/platforms.py +1369 -0
  39. codegraph/plugins/__init__.py +0 -0
  40. codegraph/plugins/cfamily/__init__.py +0 -0
  41. codegraph/plugins/cfamily/plugin.py +930 -0
  42. codegraph/plugins/cfamily/syntax.py +881 -0
  43. codegraph/plugins/dart/__init__.py +0 -0
  44. codegraph/plugins/dart/bridges.py +345 -0
  45. codegraph/plugins/dart/extractor/bin/extract.dart +717 -0
  46. codegraph/plugins/dart/extractor/pubspec.lock +149 -0
  47. codegraph/plugins/dart/extractor/pubspec.yaml +7 -0
  48. codegraph/plugins/dart/http.py +904 -0
  49. codegraph/plugins/dart/models.py +308 -0
  50. codegraph/plugins/dart/plugin.py +625 -0
  51. codegraph/plugins/dart/program.py +907 -0
  52. codegraph/plugins/django/__init__.py +0 -0
  53. codegraph/plugins/django/extras.py +378 -0
  54. codegraph/plugins/django/models.py +508 -0
  55. codegraph/plugins/django/plugin.py +728 -0
  56. codegraph/plugins/django/schemas.py +339 -0
  57. codegraph/plugins/django/shapes.py +216 -0
  58. codegraph/plugins/django/urls.py +603 -0
  59. codegraph/plugins/express/__init__.py +0 -0
  60. codegraph/plugins/express/plugin.py +428 -0
  61. codegraph/plugins/flutter/__init__.py +0 -0
  62. codegraph/plugins/flutter/plugin.py +538 -0
  63. codegraph/plugins/kotlin/__init__.py +0 -0
  64. codegraph/plugins/kotlin/exact.py +457 -0
  65. codegraph/plugins/kotlin/plugin.py +1961 -0
  66. codegraph/plugins/kotlin/reparse.py +234 -0
  67. codegraph/plugins/laravel/__init__.py +0 -0
  68. codegraph/plugins/laravel/broadcast.py +351 -0
  69. codegraph/plugins/laravel/plugin.py +863 -0
  70. codegraph/plugins/laravel/tests.py +262 -0
  71. codegraph/plugins/laravel/values.py +728 -0
  72. codegraph/plugins/native/__init__.py +0 -0
  73. codegraph/plugins/native/gates.py +286 -0
  74. codegraph/plugins/native/runner.py +183 -0
  75. codegraph/plugins/native/scipread.py +194 -0
  76. codegraph/plugins/native/ts.py +54 -0
  77. codegraph/plugins/nest/__init__.py +0 -0
  78. codegraph/plugins/nest/plugin.py +654 -0
  79. codegraph/plugins/nextjs/__init__.py +0 -0
  80. codegraph/plugins/nextjs/plugin.py +336 -0
  81. codegraph/plugins/nuxt/__init__.py +0 -0
  82. codegraph/plugins/nuxt/plugin.py +308 -0
  83. codegraph/plugins/php/__init__.py +0 -0
  84. codegraph/plugins/php/extractor/composer.json +5 -0
  85. codegraph/plugins/php/extractor/composer.lock +76 -0
  86. codegraph/plugins/php/extractor/extract.php +743 -0
  87. codegraph/plugins/php/gating.py +573 -0
  88. codegraph/plugins/php/plugin.py +668 -0
  89. codegraph/plugins/php/strings.py +197 -0
  90. codegraph/plugins/python/__init__.py +0 -0
  91. codegraph/plugins/python/aitools.py +664 -0
  92. codegraph/plugins/python/external.py +245 -0
  93. codegraph/plugins/python/fields.py +107 -0
  94. codegraph/plugins/python/plugin.py +1733 -0
  95. codegraph/plugins/python/refs.py +485 -0
  96. codegraph/plugins/python/roots.py +412 -0
  97. codegraph/plugins/python/socketio.py +210 -0
  98. codegraph/plugins/python/subproc.py +864 -0
  99. codegraph/plugins/python/tests.py +1040 -0
  100. codegraph/plugins/python/values.py +179 -0
  101. codegraph/plugins/pyweb/__init__.py +0 -0
  102. codegraph/plugins/pyweb/plugin.py +1334 -0
  103. codegraph/plugins/pyweb/values.py +68 -0
  104. codegraph/plugins/rust/__init__.py +0 -0
  105. codegraph/plugins/rust/cargo.py +226 -0
  106. codegraph/plugins/rust/plugin.py +980 -0
  107. codegraph/plugins/rust/syntax.py +678 -0
  108. codegraph/plugins/scip/__init__.py +0 -0
  109. codegraph/plugins/scip/importer.py +129 -0
  110. codegraph/plugins/scip/scip.proto +962 -0
  111. codegraph/plugins/scip/scip_pb2.py +97 -0
  112. codegraph/plugins/stubs/__init__.py +0 -0
  113. codegraph/plugins/stubs/plugins.py +38 -0
  114. codegraph/plugins/swift/__init__.py +0 -0
  115. codegraph/plugins/swift/baseurl.py +109 -0
  116. codegraph/plugins/swift/exact.py +415 -0
  117. codegraph/plugins/swift/indexstore.py +209 -0
  118. codegraph/plugins/swift/packages.py +174 -0
  119. codegraph/plugins/swift/plugin.py +2890 -0
  120. codegraph/plugins/ts/__init__.py +0 -0
  121. codegraph/plugins/ts/baseurl.py +185 -0
  122. codegraph/plugins/ts/extractor/extract.mjs +2652 -0
  123. codegraph/plugins/ts/extractor/fw.mjs +685 -0
  124. codegraph/plugins/ts/extractor/package-lock.json +205 -0
  125. codegraph/plugins/ts/extractor/package.json +9 -0
  126. codegraph/plugins/ts/plugin.py +480 -0
  127. codegraph/plugins/tsweb/__init__.py +0 -0
  128. codegraph/plugins/tsweb/common.py +290 -0
  129. codegraph/plugins/tsweb/data.py +276 -0
  130. codegraph/presets/__init__.py +146 -0
  131. codegraph/presets/c_cpp.yaml +9 -0
  132. codegraph/presets/common.yaml +66 -0
  133. codegraph/presets/dart.yaml +9 -0
  134. codegraph/presets/django-ninja.yaml +15 -0
  135. codegraph/presets/django.yaml +25 -0
  136. codegraph/presets/djangorestframework.yaml +17 -0
  137. codegraph/presets/express.yaml +17 -0
  138. codegraph/presets/kotlin.yaml +11 -0
  139. codegraph/presets/laravel.yaml +40 -0
  140. codegraph/presets/nest.yaml +11 -0
  141. codegraph/presets/nextjs.yaml +15 -0
  142. codegraph/presets/nuxt.yaml +9 -0
  143. codegraph/presets/php.yaml +5 -0
  144. codegraph/presets/python.yaml +10 -0
  145. codegraph/presets/rust.yaml +5 -0
  146. codegraph/presets/swift.yaml +10 -0
  147. codegraph/presets/typescript.yaml +13 -0
  148. codegraph/process_runs.py +328 -0
  149. codegraph/protocols/__init__.py +299 -0
  150. codegraph/protocols/builtin.py +67 -0
  151. codegraph/protocols/matchers.py +144 -0
  152. codegraph/protocols/view.py +334 -0
  153. codegraph/query.py +2089 -0
  154. codegraph/realtime.py +260 -0
  155. codegraph/roundtrip.py +346 -0
  156. codegraph/routes.py +442 -0
  157. codegraph/starters.py +218 -0
  158. codegraph/tests_index.py +117 -0
  159. codegraph/viz/__init__.py +0 -0
  160. codegraph/viz/graph.py +369 -0
  161. codegraph/viz/server.py +198 -0
  162. codegraph/viz/static/app.css +148 -0
  163. codegraph/viz/static/app.js +1082 -0
  164. codegraph/viz/static/index.html +81 -0
  165. codegraph/viz/static/layered.js +237 -0
  166. codegraph/viz/static/vendor/VERSIONS.txt +4 -0
  167. codegraph/viz/static/vendor/cose-base.js +3214 -0
  168. codegraph/viz/static/vendor/cytoscape-fcose.js +1549 -0
  169. codegraph/viz/static/vendor/cytoscape.min.js +31 -0
  170. codegraph/viz/static/vendor/layout-base.js +5230 -0
  171. codegraph/viz/tools/package-lock.json +303 -0
  172. codegraph/viz/tools/package.json +7 -0
  173. codegraph/viz/tools/shoot.mjs +165 -0
  174. codegraph/xcode.py +251 -0
@@ -0,0 +1,198 @@
1
+ """Local web UI over a code-graph DB: `python -m codegraph.cli serve --db out/combined.db [--port 8177]`.
2
+
3
+ Stdlib HTTP server, read-only. Static page + vendored Cytoscape.js/fcose (no CDN). JSON API:
4
+ /api/search?q=&kind=&fuzzy=1 node lookup (fuzzy: the query's characters in order)
5
+ /api/stats node / edge counts by kind, entry points by kind, edges by confidence (landing page)
6
+ /api/graph?mode=&spec=&spec=&min_conf=&sinks= subgraph = union of the query's evidence paths
7
+ /api/node?id= docblock, file:line, source snippet, in/out edges with evidence
8
+ /api/presets canned queries: --presets FILE or .cg.yaml viz.presets, the sample-app presets that
9
+ resolve in this graph, and starter queries derived from the graph
10
+ /api/graph?mode=plan&spec=<plan>[&verify=1] planned-change overlay (plans/<name>.yaml) + check report
11
+ /api/plans plan files
12
+ """
13
+ from __future__ import annotations
14
+
15
+ import json
16
+ import mimetypes
17
+ import threading
18
+ from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
19
+ from pathlib import Path
20
+ from urllib.parse import parse_qs, urlparse
21
+
22
+ from ..core.store import GraphStore
23
+ from . import graph as G
24
+
25
+ STATIC = Path(__file__).parent / "static"
26
+ # Canned queries for the bundled sample apps (examples/bookstore-*), shown when they resolve in the served graph. Your
27
+ # own project: .cg.yaml `viz.presets` or `serve --presets presets.json` (a JSON list of {id, label, mode, specs[, sinks]});
28
+ # starter queries derived from the graph (codegraph/starters.py) are always offered after them.
29
+ PRESETS = [
30
+ {"id": "warehouse_reaches", "label": "what reaches the warehouse connection / warehouse_stock (runtime vs operator vs gated)",
31
+ "mode": "reaches", "specs": ["connection:warehouse", "table:warehouse_stock"]},
32
+ {"id": "report_page_tables", "label": "report page -> backend -> tables (columns folded per table)", "mode": "downstream",
33
+ "specs": ["page:/reports/:id"], "sinks": ["table", "column"]},
34
+ {"id": "report_page_orders", "label": "path: report page -> ReportController::top -> table orders",
35
+ "mode": "path", "specs": ["page:/reports/:id", "ReportController::top", "table:orders"]},
36
+ {"id": "timezone_inputs", "label": "who reads request key 'timezone' (incl. resolutions)", "mode": "reaches",
37
+ "specs": ["request_key:timezone"]},
38
+ {"id": "plan_preorders", "label": "PLAN overlay: pre-orders (planned vs real graph, uncovered siblings)", "mode": "plan",
39
+ "specs": ["preorders"]},
40
+ {"id": "impact_report_top", "label": "impact of ReportController::top", "mode": "impact",
41
+ "specs": ["ReportController::top"]},
42
+ ]
43
+
44
+
45
+ class App:
46
+ def __init__(self, db: str, roots: dict[str, str] | None = None, plans: str | None = None, presets: str | None = None):
47
+ self.db = db
48
+ self.plans = plans
49
+ self.presets_file = presets
50
+ self.local = threading.local()
51
+ self.sources = G.Sources(GraphStore(db), roots)
52
+ self._presets = None
53
+
54
+ def st(self) -> GraphStore:
55
+ if not hasattr(self.local, "st"):
56
+ self.local.st = GraphStore(self.db)
57
+ return self.local.st
58
+
59
+ def api(self, path: str, qs: dict) -> object:
60
+ one = lambda k, d=None: (qs.get(k) or [d])[0] # noqa: E731
61
+ if path == "/api/search":
62
+ return G.search(self.st(), one("q", ""), one("kind") or None, int(one("limit", 30)), fuzzy=one("fuzzy") == "1")
63
+ if path == "/api/stats":
64
+ return G.stats(self.st())
65
+ if path == "/api/graph" and one("mode") == "plan":
66
+ return G.build_plan(self.st(), (qs.get("spec") or [""])[0], self.plans, verify=one("verify") == "1")
67
+ if path == "/api/plans":
68
+ from .. import plans as P
69
+ return P.list_plans(self.plans)
70
+ if path == "/api/graph":
71
+ sinks = [s for s in (one("sinks") or "").split(",") if s] or None
72
+ return G.build(self.st(), one("mode", "reaches"), qs.get("spec") or [], one("min_conf", "heuristic"), sinks)
73
+ if path == "/api/node":
74
+ return G.node_detail(self.st(), self.sources, one("id", ""))
75
+ if path == "/api/presets":
76
+ if self._presets is None:
77
+ self._presets = menu(self.st(), self.presets_file, self.plans)
78
+ return self._presets
79
+ if path == "/api/meta":
80
+ m = self.st().meta()
81
+ return {"project": m.get("project"), "repos": m.get("repos"), "indexed_at": m.get("indexed_at"), "db": self.db}
82
+ raise KeyError(path)
83
+
84
+
85
+ def _resolves(st: GraphStore, p: dict, plans: str | None) -> bool:
86
+ from .. import query as Q
87
+ if p.get("mode") == "plan":
88
+ from .. import plans as P
89
+ try:
90
+ return all(P.find_plan(s, plans) for s in p.get("specs") or [])
91
+ except P.PlanError:
92
+ return False
93
+ return bool(p.get("specs")) and all(Q.resolve_targets(st, s) for s in p["specs"])
94
+
95
+
96
+ def menu(st: GraphStore, presets_file: str | None = None, plans: str | None = None) -> list[dict]:
97
+ """Preset menu: the project's presets (--presets FILE, else .cg.yaml viz.presets), then the sample-app presets that
98
+ resolve in this graph, then the starter queries derived from it. Each entry carries `source`."""
99
+ from ..config import graph_configs
100
+ from ..starters import for_graph
101
+ own, src = [], None
102
+ if presets_file:
103
+ own, src = json.loads(Path(presets_file).read_text()), "--presets"
104
+ else:
105
+ for _, cfg, _ in graph_configs(st):
106
+ if (cfg.get("viz") or {}).get("presets"):
107
+ own, src = cfg["viz"]["presets"], cfg.get("file", ".cg.yaml")
108
+ break
109
+ out = [dict(p, source=src) for p in own]
110
+ out += [dict(p, source="examples") for p in PRESETS if _resolves(st, p, plans)]
111
+ out += [dict(p, source="starter") for p in for_graph(st)]
112
+ seen, menu_ = set(), []
113
+ for p in out:
114
+ if p.get("id") not in seen:
115
+ seen.add(p.get("id"))
116
+ menu_.append(p)
117
+ return menu_
118
+
119
+
120
+ def make_handler(app: App):
121
+ class H(BaseHTTPRequestHandler):
122
+ def log_message(self, fmt, *args): # quiet
123
+ pass
124
+
125
+ def _send(self, code, body: bytes, ctype="application/json"):
126
+ self.send_response(code)
127
+ self.send_header("Content-Type", ctype)
128
+ self.send_header("Content-Length", str(len(body)))
129
+ self.send_header("Cache-Control", "no-store")
130
+ self.end_headers()
131
+ self.wfile.write(body)
132
+
133
+ def do_GET(self): # noqa: N802
134
+ u = urlparse(self.path)
135
+ if u.path.startswith("/api/"):
136
+ try:
137
+ res = app.api(u.path, parse_qs(u.query))
138
+ self._send(200, json.dumps(res, default=str).encode())
139
+ except KeyError:
140
+ self._send(404, b'{"error":"not found"}')
141
+ except Exception as e: # noqa: BLE001
142
+ self._send(400, json.dumps({"error": str(e)}).encode())
143
+ return
144
+ rel = "index.html" if u.path in ("/", "") else u.path.lstrip("/")
145
+ p = (STATIC / rel).resolve()
146
+ if not str(p).startswith(str(STATIC.resolve())) or not p.is_file():
147
+ self._send(404, b"not found", "text/plain")
148
+ return
149
+ self._send(200, p.read_bytes(), mimetypes.guess_type(p.name)[0] or "application/octet-stream")
150
+ return H
151
+
152
+
153
+ def serve(db: str, host="127.0.0.1", port=8177, roots: dict[str, str] | None = None, plans: str | None = None,
154
+ presets: str | None = None):
155
+ app = App(str(Path(db).resolve()), roots, plans, presets)
156
+ httpd = ThreadingHTTPServer((host, port), make_handler(app))
157
+ print(f"code-graph view: http://{host}:{port}/ (db {app.db}; Ctrl-C to stop)", flush=True)
158
+ try:
159
+ httpd.serve_forever()
160
+ except KeyboardInterrupt:
161
+ pass
162
+
163
+
164
+ def export_plan_html(db: str, out: str, plan: str, plans_root=None, verify=False) -> str:
165
+ """Self-contained HTML of a plan overlay (same view as mode=plan in `serve`)."""
166
+ st = GraphStore(db)
167
+ g = G.build_plan(st, plan, plans_root, verify=verify)
168
+ return _write_html(st, g, out, f"plan {g['meta']['plan']}: {g['meta']['title']}")
169
+
170
+
171
+ def export_html(db: str, out: str, mode: str, specs: list[str], min_conf="heuristic", sinks=None, title=None) -> str:
172
+ """Self-contained HTML (data + vendored JS inlined) for one query; opens from disk without a server."""
173
+ st = GraphStore(db)
174
+ g = G.build(st, mode, specs, min_conf, sinks)
175
+ return _write_html(st, g, out, title or f"{mode} {' '.join(specs)}")
176
+
177
+
178
+ def _write_html(st: GraphStore, g: dict, out: str, title: str) -> str:
179
+ src = G.Sources(st)
180
+ details = {n["id"]: G.node_detail(st, src, n["id"], limit=12) for n in g["nodes"] if st.node(n["id"])}
181
+ for d in details.values(): # no local paths in a file meant to be shared
182
+ if d and d.get("snippet"):
183
+ d["snippet"].pop("abs", None)
184
+ html = (STATIC / "index.html").read_text()
185
+ for name in ("cytoscape.min.js", "layout-base.js", "cose-base.js", "cytoscape-fcose.js"):
186
+ js = (STATIC / "vendor" / name).read_text().replace("</script", "<\\/script")
187
+ html = html.replace(f'<script src="vendor/{name}"></script>', f"<script>{js}</script>")
188
+ js = (STATIC / "layered.js").read_text().replace("</script", "<\\/script")
189
+ html = html.replace('<script src="layered.js"></script>', f"<script>{js}</script>")
190
+ css = (STATIC / "app.css").read_text()
191
+ html = html.replace('<link rel="stylesheet" href="app.css">', f"<style>{css}</style>")
192
+ data = json.dumps({"graph": g, "details": details, "title": title}, default=str)
193
+ app_js = (STATIC / "app.js").read_text().replace("</script", "<\\/script")
194
+ data = data.replace("</", "<\\/")
195
+ html = html.replace('<script src="app.js"></script>', f"<script>window.__STATIC__ = {data};</script><script>{app_js}</script>")
196
+ Path(out).parent.mkdir(parents=True, exist_ok=True)
197
+ Path(out).write_text(html)
198
+ return out
@@ -0,0 +1,148 @@
1
+ * { box-sizing: border-box; }
2
+ :root { --panel: 420px; --hdr: 52px; }
3
+ @media (max-width: 1440px) { :root { --panel: 360px; } }
4
+ html, body { margin: 0; height: 100%; font: 13px/1.35 -apple-system, "Segoe UI", Roboto, "Noto Sans", sans-serif; color: #1d2330; background: #f6f7f9; }
5
+ header { position: relative; height: var(--hdr); display: flex; align-items: center; gap: 8px; padding: 0 10px; background: #1d2330; color: #fff; white-space: nowrap; }
6
+ header .brand { font-weight: 700; letter-spacing: .3px; color: #fff; text-decoration: none; flex: none; }
7
+ header .grp { display: flex; align-items: center; gap: 6px; flex: none; }
8
+ header .grp.query { flex: 1 1 auto; min-width: 0; }
9
+ header select, header input, header button { height: 30px; border-radius: 5px; border: 1px solid #3a4256; background: #2a3142; color: #fff; padding: 0 8px; font-size: 12.5px; white-space: nowrap; flex: none; }
10
+ header button { background: #3d6be0; border-color: #3d6be0; cursor: pointer; }
11
+ header .view button, header button.more { background: #2a3142; border-color: #3a4256; }
12
+ header .specbox { flex: 1 1 auto; min-width: 0; } header .specbox input { width: 100%; }
13
+ header button.more { display: none; font-size: 16px; line-height: 1; padding: 0 10px; }
14
+ @media (max-width: 1439px) {
15
+ header button.more { display: inline-block; }
16
+ header .grp.view { display: none; position: absolute; top: calc(var(--hdr) - 4px); right: 8px; z-index: 20; flex-direction: column; align-items: stretch;
17
+ padding: 8px; background: #1d2330; border: 1px solid #3a4256; border-radius: 6px; box-shadow: 0 4px 14px rgba(0,0,0,.25); }
18
+ header .grp.view.open { display: flex; }
19
+ }
20
+ main { position: absolute; top: var(--hdr); bottom: 0; left: 0; right: 0; }
21
+ #cy { position: absolute; top: 34px; bottom: 0; left: 0; right: var(--panel); background: #fff; }
22
+ #cy:focus { outline: none; } #cy:focus-visible { outline: 2px solid #3d6be0; outline-offset: -2px; }
23
+ #panel { position: absolute; top: 0; bottom: 0; right: 0; width: var(--panel); border-left: 1px solid #dde1e8; background: #fbfcfd; }
24
+ #panelbody { position: absolute; inset: 0; overflow: auto; padding: 0 14px 12px 16px; }
25
+ #panel .hint { color: #5c6577; }
26
+ #panel h2 { font-size: 15px; margin: 0 0 4px; word-break: break-all; }
27
+ #panel .kind { display: inline-block; padding: 1px 7px; border-radius: 9px; color: #fff; font-size: 11px; margin-right: 6px; }
28
+ #panel .loc { font-family: ui-monospace, Menlo, Consolas, monospace; font-size: 12px; color: #2f4b9a; word-break: break-all; }
29
+ #panel pre { background: #f0f2f6; padding: 8px; border-radius: 5px; overflow: auto; font-size: 11.5px; white-space: pre-wrap; }
30
+ #panel pre.code { white-space: pre; }
31
+ #panel pre.code .hl { background: #ffe9a8; display: block; }
32
+ #panel table { border-collapse: collapse; width: 100%; font-size: 11.5px; }
33
+ #panel td { border-top: 1px solid #e6e9ef; padding: 3px 4px; vertical-align: top; word-break: break-all; }
34
+ #panel td.k { white-space: nowrap; color: #5c6577; word-break: normal; }
35
+ #panel h3 { font-size: 12.5px; margin: 14px 0 4px; color: #384156; letter-spacing: .2px; }
36
+ #panel .badge { display: inline-block; border: 1px solid #c7cdd8; border-radius: 4px; padding: 0 5px; margin: 1px 3px 1px 0; font-size: 11px; background: #fff; }
37
+ #panel .badge.gated { border-color: #d64545; color: #b02a2a; }
38
+ #panel .badge.live { border-color: #2e9d57; color: #1e7a41; }
39
+ #panel a { color: #2f4b9a; cursor: pointer; text-decoration: none; } #panel a:hover { text-decoration: underline; }
40
+ #status { position: absolute; left: 0; top: 0; right: var(--panel); height: 34px; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; background: #f6f7f9; border-bottom: 1px solid #dde1e8; padding: 8px 10px; font-size: 12px; line-height: 1.3; }
41
+ #status b { color: #1d2330; }
42
+ #legendbox { position: absolute; left: 10px; bottom: 10px; max-width: calc(100% - var(--panel) - 20px); z-index: 5; background: rgba(255,255,255,.95); border: 1px solid #dde1e8; border-radius: 6px; font-size: 11.5px; }
43
+ #legendbox summary { cursor: pointer; padding: 4px 10px; color: #384156; font-weight: 600; }
44
+ #legend { padding: 4px 10px 8px; display: flex; flex-wrap: wrap; gap: 3px 12px; max-height: 40vh; overflow: auto; }
45
+ #legend .sw { display: inline-block; width: 10px; height: 10px; border-radius: 2px; margin-right: 3px; vertical-align: -1px; }
46
+ #legend .ln { display: inline-block; width: 26px; height: 0; border-top: 2px solid #555; margin-right: 4px; vertical-align: 3px; }
47
+ #fitall { position: absolute; top: 44px; right: calc(var(--panel) + 10px); z-index: 6; height: 28px; border-radius: 5px; border: 1px solid #3d6be0; background: #fff; color: #2f4b9a; font-size: 12px; cursor: pointer; padding: 0 10px; }
48
+ #tip { position: fixed; z-index: 30; pointer-events: none; max-width: 420px; background: #1d2330; color: #fff; border-radius: 5px; padding: 5px 8px; font-size: 12px; line-height: 1.35; box-shadow: 0 2px 8px rgba(0,0,0,.25); }
49
+ #tip .loc { font-family: ui-monospace, Menlo, Consolas, monospace; color: #c9d3ea; word-break: break-all; }
50
+ /* landing page: overview, search, starter queries */
51
+ #landing { position: absolute; top: 0; left: 0; bottom: 0; right: var(--panel); overflow: auto; background: #f6f7f9; padding: 28px 32px; z-index: 4; }
52
+ #landing h1 { font-size: 20px; margin: 0 0 2px; } #landing .sub { color: #5c6577; margin-bottom: 18px; }
53
+ #landing .stats { display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: 18px; }
54
+ #landing .stat { background: #fff; border: 1px solid #dde1e8; border-radius: 8px; padding: 10px 14px; min-width: 150px; }
55
+ #landing .stat .n { font-size: 20px; font-weight: 700; } #landing .stat .l { color: #5c6577; font-size: 12px; }
56
+ #landing .stat .kinds { color: #384156; font-size: 12px; margin-top: 4px; white-space: normal; max-width: 320px; }
57
+ #landing .search { position: relative; max-width: 760px; margin-bottom: 8px; }
58
+ #landing .search input { width: 100%; height: 44px; font-size: 16px; padding: 0 14px; border-radius: 8px; border: 1px solid #b9c2d3; background: #fff; }
59
+ #landing .search input:focus { outline: 2px solid #3d6be0; outline-offset: 0; border-color: #3d6be0; }
60
+ #landing .chips { display: flex; flex-wrap: wrap; gap: 6px; margin: 8px 0 4px; }
61
+ #landing .chip { border: 1px solid #b9c2d3; border-radius: 14px; background: #fff; padding: 2px 10px; font-size: 12px; cursor: pointer; color: #384156; }
62
+ #landing .chip[aria-pressed="true"] { background: #1d2330; color: #fff; border-color: #1d2330; }
63
+ #landing .hits { list-style: none; margin: 0; padding: 0; max-width: 760px; background: #fff; border: 1px solid #dde1e8; border-radius: 8px; }
64
+ #landing .hits:empty { display: none; }
65
+ #landing .hits li { padding: 6px 12px; border-top: 1px solid #eef0f4; cursor: pointer; display: flex; gap: 10px; align-items: baseline; }
66
+ #landing .hits li:first-child { border-top: 0; }
67
+ #landing .hits li[aria-selected="true"] { background: #e8eefc; }
68
+ #landing .hits .k { color: #5c6577; font-size: 11.5px; min-width: 70px; } #landing .hits .nm { font-weight: 600; }
69
+ #landing .hits .f { color: #5c6577; font-family: ui-monospace, Menlo, Consolas, monospace; font-size: 11.5px; overflow: hidden; text-overflow: ellipsis; }
70
+ #landing .hits .q { margin-left: auto; color: #2f4b9a; font-size: 11.5px; white-space: nowrap; }
71
+ #landing h2 { font-size: 14px; margin: 22px 0 8px; color: #384156; }
72
+ #landing .cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 10px; max-width: 1100px; }
73
+ #landing .card { text-align: left; background: #fff; border: 1px solid #dde1e8; border-radius: 8px; padding: 10px 12px; cursor: pointer; font: inherit; color: inherit; }
74
+ #landing .card:hover, #landing .card:focus-visible { border-color: #3d6be0; outline: none; box-shadow: 0 0 0 2px rgba(61,107,224,.25); }
75
+ #landing .card .t { font-weight: 600; margin-bottom: 3px; } #landing .card .w { color: #5c6577; font-size: 12px; }
76
+ #landing .card code { display: block; margin-top: 6px; font-size: 11px; color: #2f4b9a; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
77
+ #panel .planbox { margin: 6px 0; padding: 6px 8px; border-radius: 5px; border-left: 4px solid #8a93a6; background: #f3f4f7; }
78
+ #panel .planbox.p-missing { border-color: #d6006b; background: #fff0f6; } #panel .planbox.p-modified { border-color: #f59f00; background: #fff8e6; }
79
+ #panel .planbox.p-added { border-color: #2e9d57; background: #eefaf2; } #panel .planbox.p-forbidden { border-color: #d62828; background: #fff0f0; }
80
+ #panel .planbox.p-review { border-color: #b06ab3; } #panel .planbox.p-covered { border-color: #2e9d57; }
81
+ #panel pre.report { font-size: 10.5px; white-space: pre-wrap; }
82
+ #legend .chip { font: inherit; color: #1d2330; background: #fff; border: 1px solid #7d889c; border-radius: 10px; padding: 0 7px; cursor: pointer; }
83
+ #legend .chip[data-conf][aria-pressed="false"] { opacity: .5; text-decoration: line-through; }
84
+ #legend .kchip[aria-pressed="true"] { border: 2px solid #1d4ed8; font-weight: 600; }
85
+ #legend .chip:focus-visible { outline: 2px solid #1d4ed8; outline-offset: 1px; }
86
+ #help { position: absolute; top: 60px; left: 50%; transform: translateX(-50%); z-index: 20; background: #fff; color: #1d2330; border: 1px solid #7d889c; border-radius: 8px; padding: 12px 16px; box-shadow: 0 6px 24px rgba(0,0,0,.18); font-size: 13px; }
87
+ #help table { border-collapse: collapse; margin-top: 6px; } #help td { padding: 3px 10px 3px 0; vertical-align: top; }
88
+ #help kbd { border: 1px solid #7d889c; border-radius: 3px; padding: 0 4px; font-size: 12px; background: #f6f7f9; }
89
+ #helpclose { position: absolute; top: 4px; right: 6px; border: 0; background: none; font-size: 18px; cursor: pointer; color: #384156; }
90
+ #cy:focus-visible { outline: 3px solid #1d4ed8; outline-offset: -3px; }
91
+ #phandle { position: absolute; left: -4px; top: 0; bottom: 0; width: 8px; cursor: col-resize; z-index: 3; }
92
+ #phandle:hover, #phandle:focus-visible { background: rgba(29,78,216,.25); outline: none; }
93
+ #pcollapse { position: absolute; top: 6px; right: 6px; z-index: 4; width: 24px; height: 24px; border: 1px solid #7d889c; border-radius: 4px; background: #fff; cursor: pointer; color: #1d2330; }
94
+ body.pcollapsed #panelbody { display: none; }
95
+ #panel .phead { position: sticky; top: 0; background: #fbfcfd; padding: 12px 28px 6px 0; border-bottom: 1px solid #e6e9ef; z-index: 2; }
96
+ #panel .pacts { margin-top: 4px; }
97
+ #panel .pbtn { display: inline-block; font: inherit; font-size: 11px; color: #1d2330; background: #fff; border: 1px solid #7d889c; border-radius: 4px; padding: 1px 6px; margin: 2px 3px 0 0; cursor: pointer; text-decoration: none; }
98
+ #panel .pbtn:focus-visible, #ctxmenu button:focus-visible { outline: 2px solid #1d4ed8; outline-offset: 1px; }
99
+ #panel h3.src { display: flex; gap: 6px; align-items: baseline; } #panel h3.src .loc { flex: 1; min-width: 0; overflow: hidden; white-space: nowrap; }
100
+ #panel pre.code { overflow-x: auto; } #panel pre.code.wrap { white-space: pre-wrap; }
101
+ #panel details.egrp { margin: 2px 0 2px 4px; } #panel details.egrp summary { cursor: pointer; font-size: 12px; color: #384156; font-weight: 600; }
102
+ #panel .summary { margin: 8px 0; padding: 6px 8px; border: 1px solid #dde1e8; border-radius: 6px; background: #fff; }
103
+ #panel .summary h3 { margin-top: 0; } #panel table.bydepth td { text-align: center; } #panel table.bydepth td.k { text-align: left; }
104
+ #ctxmenu { position: fixed; z-index: 30; background: #fff; border: 1px solid #7d889c; border-radius: 6px; box-shadow: 0 4px 16px rgba(0,0,0,.18); padding: 4px 0; display: flex; flex-direction: column; }
105
+ #ctxmenu[hidden] { display: none; }
106
+ #ctxmenu button { font: inherit; font-size: 12.5px; text-align: left; border: 0; background: none; padding: 5px 14px; cursor: pointer; color: #1d2330; }
107
+ #ctxmenu button:hover { background: #eef1f6; }
108
+ /* dark theme (#82 item 13): data-theme="dark" on <html>, from prefers-color-scheme or the theme button */
109
+ :root[data-theme="dark"] { color-scheme: dark; }
110
+ :root[data-theme="dark"] body { color: #e6e9ef; background: #0d1117; }
111
+ :root[data-theme="dark"] #cy { background: #12161d; }
112
+ :root[data-theme="dark"] #status { background: #161b23; border-color: #2a3140; color: #c3cad6; }
113
+ :root[data-theme="dark"] #status b { color: #e6e9ef; }
114
+ :root[data-theme="dark"] #panel, :root[data-theme="dark"] #panel .phead { background: #161b23; border-color: #2a3140; }
115
+ :root[data-theme="dark"] #panel .hint, :root[data-theme="dark"] #panel td.k { color: #a8b0bf; }
116
+ :root[data-theme="dark"] #panel h3, :root[data-theme="dark"] #panel details.egrp summary { color: #c3cad6; }
117
+ :root[data-theme="dark"] #panel .loc, :root[data-theme="dark"] #panel a { color: #8fb3ff; }
118
+ :root[data-theme="dark"] #panel pre { background: #0d1117; color: #e6e9ef; }
119
+ :root[data-theme="dark"] #panel pre.code .hl { background: #4a3d10; }
120
+ :root[data-theme="dark"] #panel td { border-color: #2a3140; }
121
+ :root[data-theme="dark"] #panel .badge, :root[data-theme="dark"] #panel .pbtn, :root[data-theme="dark"] #panel .summary,
122
+ :root[data-theme="dark"] #legend .chip, :root[data-theme="dark"] #pcollapse { background: #1c222c; color: #e6e9ef; border-color: #8792a6; }
123
+ :root[data-theme="dark"] #legendbox { background: rgba(22,27,35,.96); border-color: #2a3140; }
124
+ :root[data-theme="dark"] #legendbox summary { color: #c3cad6; }
125
+ :root[data-theme="dark"] #fitall { background: #1c222c; color: #8fb3ff; border-color: #7aa7ff; }
126
+ :root[data-theme="dark"] #help, :root[data-theme="dark"] #ctxmenu { background: #161b23; color: #e6e9ef; border-color: #8792a6; }
127
+ :root[data-theme="dark"] #help kbd { background: #1c222c; border-color: #8792a6; }
128
+ :root[data-theme="dark"] #helpclose, :root[data-theme="dark"] #ctxmenu button { color: #e6e9ef; }
129
+ :root[data-theme="dark"] #ctxmenu button:hover { background: #222a36; }
130
+ :root[data-theme="dark"] #landing { background: #0d1117; }
131
+ :root[data-theme="dark"] #landing .stat, :root[data-theme="dark"] #landing .card, :root[data-theme="dark"] #landing .hits,
132
+ :root[data-theme="dark"] #landing .search input, :root[data-theme="dark"] #landing .chip { background: #161b23; border-color: #3a4256; color: #e6e9ef; }
133
+ :root[data-theme="dark"] #landing .sub, :root[data-theme="dark"] #landing .stat .l, :root[data-theme="dark"] #landing .card .w,
134
+ :root[data-theme="dark"] #landing .hits .k, :root[data-theme="dark"] #landing .hits .f { color: #a8b0bf; }
135
+ :root[data-theme="dark"] #landing .stat .kinds, :root[data-theme="dark"] #landing h2 { color: #c3cad6; }
136
+ :root[data-theme="dark"] #landing .hits li { border-color: #2a3140; } :root[data-theme="dark"] #landing .hits li[aria-selected="true"] { background: #1f2a44; }
137
+ :root[data-theme="dark"] #landing .hits .q { color: #8fb3ff; }
138
+ :root[data-theme="dark"] #landing .chip[aria-pressed="true"] { background: #e6e9ef; color: #12161d; }
139
+ :root[data-theme="dark"] #listview { background: #12161d; color: #e6e9ef; }
140
+ #listview { position: absolute; top: 34px; bottom: 0; left: 0; right: var(--panel); overflow: auto; background: #fff; z-index: 5; padding: 10px 16px; font-size: 13px; }
141
+ #listview[hidden] { display: none; }
142
+ #listview h3 { font-size: 13px; margin: 10px 0 4px; } #listview ul { margin: 0 0 0 4px; padding-left: 14px; }
143
+ #listview a { color: inherit; cursor: pointer; } #listview a:hover, #listview a:focus-visible { text-decoration: underline; }
144
+ #listview .k { color: #5c6577; font-size: 11.5px; margin-left: 6px; } :root[data-theme="dark"] #listview .k { color: #a8b0bf; }
145
+ #truncbanner { position: absolute; top: 40px; left: 50%; transform: translateX(-50%); z-index: 7; background: #fff4d6; color: #5c3d00; border: 1px solid #b26b00; border-radius: 6px; padding: 4px 12px; font-size: 12.5px; }
146
+ #truncbanner[hidden] { display: none; }
147
+ :root[data-theme="dark"] #truncbanner { background: #3a2c08; color: #ffd98a; border-color: #e09a2c; }
148
+ :root[data-theme="dark"] #landing .card code { color: #8fb3ff; }