pgserve 2.1.3 → 2.2.1

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 (235) hide show
  1. package/CHANGELOG.md +96 -0
  2. package/README.md +105 -1
  3. package/bin/autopg-wrapper.cjs +16 -0
  4. package/bin/pgserve-wrapper.cjs +32 -6
  5. package/bin/postgres-server.js +56 -0
  6. package/console/README.md +131 -0
  7. package/console/api.js +173 -0
  8. package/console/app.jsx +483 -0
  9. package/console/colors_and_type.css +227 -0
  10. package/console/components.jsx +167 -0
  11. package/console/console.css +1666 -0
  12. package/console/data.jsx +350 -0
  13. package/console/index.html +31 -0
  14. package/console/screens/databases.jsx +5 -0
  15. package/console/screens/health.jsx +5 -0
  16. package/console/screens/ingress.jsx +5 -0
  17. package/console/screens/optimizer.jsx +5 -0
  18. package/console/screens/rlm-sim.jsx +5 -0
  19. package/console/screens/rlm-trace.jsx +5 -0
  20. package/console/screens/security.jsx +5 -0
  21. package/console/screens/settings.jsx +611 -0
  22. package/console/screens/sql.jsx +5 -0
  23. package/console/screens/sync.jsx +5 -0
  24. package/console/screens/tables.jsx +5 -0
  25. package/console/tweaks-panel.jsx +425 -0
  26. package/package.json +14 -2
  27. package/scripts/postinstall.cjs +60 -0
  28. package/src/cli-config.cjs +310 -0
  29. package/src/cli-install.cjs +112 -11
  30. package/src/cli-restart.cjs +228 -0
  31. package/src/cli-ui.cjs +580 -0
  32. package/src/cluster.js +43 -38
  33. package/src/postgres.js +141 -19
  34. package/src/settings-loader.cjs +235 -0
  35. package/src/settings-migrate.cjs +212 -0
  36. package/src/settings-pg-args.cjs +146 -0
  37. package/src/settings-schema.cjs +422 -0
  38. package/src/settings-validator.cjs +416 -0
  39. package/src/settings-writer.cjs +288 -0
  40. package/src/upgrade/index.js +65 -0
  41. package/src/upgrade/runner.js +23 -0
  42. package/src/upgrade/steps/binary-cache-flush.js +67 -0
  43. package/src/upgrade/steps/consumer-signal.js +40 -0
  44. package/src/upgrade/steps/env-refresh.js +89 -0
  45. package/src/upgrade/steps/health-validate.js +53 -0
  46. package/src/upgrade/steps/plpgsql-resolve.js +66 -0
  47. package/src/upgrade/steps/port-reconcile.js +52 -0
  48. package/.claude/context/windows-debug.md +0 -119
  49. package/.genie/AGENTS.md +0 -15
  50. package/.genie/agents/README.md +0 -110
  51. package/.genie/agents/analyze.md +0 -176
  52. package/.genie/agents/forge.md +0 -290
  53. package/.genie/agents/garbage-cleaner.md +0 -324
  54. package/.genie/agents/garbage-collector.md +0 -596
  55. package/.genie/agents/github-issue-gc.md +0 -618
  56. package/.genie/agents/review.md +0 -380
  57. package/.genie/agents/semantic-analyzer/find-duplicates.md +0 -90
  58. package/.genie/agents/semantic-analyzer/find-orphans.md +0 -99
  59. package/.genie/agents/semantic-analyzer.md +0 -101
  60. package/.genie/agents/update.md +0 -182
  61. package/.genie/agents/wish.md +0 -357
  62. package/.genie/brainstorms/pgserve-v2/DESIGN.md +0 -174
  63. package/.genie/code/AGENTS.md +0 -694
  64. package/.genie/code/agents/audit/risk.md +0 -173
  65. package/.genie/code/agents/audit/security.md +0 -189
  66. package/.genie/code/agents/audit.md +0 -145
  67. package/.genie/code/agents/challenge.md +0 -230
  68. package/.genie/code/agents/change-reviewer.md +0 -295
  69. package/.genie/code/agents/code-garbage-collector.md +0 -425
  70. package/.genie/code/agents/code-quality.md +0 -410
  71. package/.genie/code/agents/commit-suggester.md +0 -255
  72. package/.genie/code/agents/commit.md +0 -124
  73. package/.genie/code/agents/consensus.md +0 -204
  74. package/.genie/code/agents/daily-standup.md +0 -722
  75. package/.genie/code/agents/docgen.md +0 -48
  76. package/.genie/code/agents/explore.md +0 -79
  77. package/.genie/code/agents/fix.md +0 -100
  78. package/.genie/code/agents/git/commit-advisory.md +0 -219
  79. package/.genie/code/agents/git/workflows/issue.md +0 -244
  80. package/.genie/code/agents/git/workflows/pr.md +0 -179
  81. package/.genie/code/agents/git/workflows/release.md +0 -460
  82. package/.genie/code/agents/git/workflows/report.md +0 -342
  83. package/.genie/code/agents/git.md +0 -432
  84. package/.genie/code/agents/implementor.md +0 -161
  85. package/.genie/code/agents/install.md +0 -515
  86. package/.genie/code/agents/issue-creator.md +0 -344
  87. package/.genie/code/agents/polish.md +0 -116
  88. package/.genie/code/agents/qa.md +0 -653
  89. package/.genie/code/agents/refactor.md +0 -294
  90. package/.genie/code/agents/release.md +0 -1129
  91. package/.genie/code/agents/roadmap.md +0 -885
  92. package/.genie/code/agents/tests.md +0 -557
  93. package/.genie/code/agents/tracer.md +0 -50
  94. package/.genie/code/agents/update/upstream-update.md +0 -85
  95. package/.genie/code/agents/update/versions/generic-update.md +0 -305
  96. package/.genie/code/agents/vibe.md +0 -1317
  97. package/.genie/code/spells/agent-configuration.md +0 -58
  98. package/.genie/code/spells/automated-rc-publishing.md +0 -106
  99. package/.genie/code/spells/branch-tracker-guidance.md +0 -28
  100. package/.genie/code/spells/debug.md +0 -320
  101. package/.genie/code/spells/emoji-naming-convention.md +0 -303
  102. package/.genie/code/spells/evidence-storage.md +0 -26
  103. package/.genie/code/spells/file-naming-rules.md +0 -35
  104. package/.genie/code/spells/forge-code-blueprints.md +0 -195
  105. package/.genie/code/spells/genie-integration.md +0 -153
  106. package/.genie/code/spells/publishing-protocol.md +0 -61
  107. package/.genie/code/spells/team-consultation-protocol.md +0 -284
  108. package/.genie/code/spells/tool-requirements.md +0 -20
  109. package/.genie/code/spells/triad-maintenance-protocol.md +0 -154
  110. package/.genie/code/teams/tech-council/council.md +0 -328
  111. package/.genie/code/teams/tech-council/jt.md +0 -352
  112. package/.genie/code/teams/tech-council/nayr.md +0 -305
  113. package/.genie/code/teams/tech-council/oettam.md +0 -375
  114. package/.genie/neurons/README.md +0 -193
  115. package/.genie/neurons/forge.md +0 -106
  116. package/.genie/neurons/genie.md +0 -63
  117. package/.genie/neurons/review.md +0 -106
  118. package/.genie/neurons/wish.md +0 -104
  119. package/.genie/product/README.md +0 -20
  120. package/.genie/product/cli-automation.md +0 -359
  121. package/.genie/product/environment.md +0 -60
  122. package/.genie/product/mission.md +0 -60
  123. package/.genie/product/roadmap.md +0 -44
  124. package/.genie/product/tech-stack.md +0 -34
  125. package/.genie/product/templates/context-template.md +0 -218
  126. package/.genie/product/templates/qa-done-report-template.md +0 -68
  127. package/.genie/product/templates/review-report-template.md +0 -89
  128. package/.genie/product/templates/wish-template.md +0 -120
  129. package/.genie/scripts/helpers/analyze-commit.js +0 -195
  130. package/.genie/scripts/helpers/bullet-counter.js +0 -194
  131. package/.genie/scripts/helpers/bullet-find.js +0 -289
  132. package/.genie/scripts/helpers/bullet-id.js +0 -244
  133. package/.genie/scripts/helpers/check-secrets.js +0 -237
  134. package/.genie/scripts/helpers/count-tokens.js +0 -200
  135. package/.genie/scripts/helpers/create-frontmatter.js +0 -456
  136. package/.genie/scripts/helpers/detect-markers.js +0 -293
  137. package/.genie/scripts/helpers/detect-todos.js +0 -267
  138. package/.genie/scripts/helpers/detect-unlabeled-blocks.js +0 -135
  139. package/.genie/scripts/helpers/embeddings.js +0 -344
  140. package/.genie/scripts/helpers/find-empty-sections.js +0 -158
  141. package/.genie/scripts/helpers/index.js +0 -319
  142. package/.genie/scripts/helpers/validate-frontmatter.js +0 -578
  143. package/.genie/scripts/helpers/validate-links.js +0 -207
  144. package/.genie/scripts/helpers/validate-paths.js +0 -373
  145. package/.genie/spells/README.md +0 -9
  146. package/.genie/spells/ace-protocol.md +0 -118
  147. package/.genie/spells/ask-one-at-a-time.md +0 -175
  148. package/.genie/spells/backup-analyzer.md +0 -542
  149. package/.genie/spells/blocker.md +0 -12
  150. package/.genie/spells/break-things-move-fast.md +0 -56
  151. package/.genie/spells/context-candidates.md +0 -72
  152. package/.genie/spells/context-critic.md +0 -51
  153. package/.genie/spells/defer-to-expertise.md +0 -278
  154. package/.genie/spells/delegate-dont-do.md +0 -292
  155. package/.genie/spells/error-investigation-protocol.md +0 -328
  156. package/.genie/spells/evidence-based-completion.md +0 -273
  157. package/.genie/spells/experiment.md +0 -65
  158. package/.genie/spells/file-creation-protocol.md +0 -229
  159. package/.genie/spells/forge-integration.md +0 -281
  160. package/.genie/spells/forge-orchestration.md +0 -514
  161. package/.genie/spells/gather-context.md +0 -18
  162. package/.genie/spells/global-health-check.md +0 -34
  163. package/.genie/spells/global-noop-roundtrip.md +0 -25
  164. package/.genie/spells/install-genie.md +0 -1232
  165. package/.genie/spells/install.md +0 -82
  166. package/.genie/spells/investigate-before-commit.md +0 -112
  167. package/.genie/spells/know-yourself.md +0 -288
  168. package/.genie/spells/learn.md +0 -828
  169. package/.genie/spells/mcp-diagnostic-protocol.md +0 -246
  170. package/.genie/spells/mcp-first.md +0 -124
  171. package/.genie/spells/multi-step-execution.md +0 -67
  172. package/.genie/spells/orchestration-boundary-protocol.md +0 -256
  173. package/.genie/spells/orchestrator-not-implementor.md +0 -189
  174. package/.genie/spells/prompt.md +0 -746
  175. package/.genie/spells/reflect.md +0 -404
  176. package/.genie/spells/routing-decision-matrix.md +0 -368
  177. package/.genie/spells/run-in-parallel.md +0 -12
  178. package/.genie/spells/session-state-updater-example.md +0 -196
  179. package/.genie/spells/session-state-updater.md +0 -220
  180. package/.genie/spells/track-long-running-tasks.md +0 -133
  181. package/.genie/spells/troubleshoot-infrastructure.md +0 -176
  182. package/.genie/spells/upgrade-genie.md +0 -415
  183. package/.genie/spells/url-presentation-protocol.md +0 -301
  184. package/.genie/spells/wish-initiation.md +0 -158
  185. package/.genie/spells/wish-issue-linkage.md +0 -410
  186. package/.genie/spells/wish-lifecycle.md +0 -100
  187. package/.genie/state/provider-status.json +0 -3
  188. package/.genie/state/version.json +0 -16
  189. package/.genie/wishes/canonical-pgserve-pm2-supervision/WISH.md +0 -290
  190. package/.genie/wishes/pgserve-v2/BRIEF-from-genie-pgserve.md +0 -99
  191. package/.genie/wishes/pgserve-v2/WISH.md +0 -442
  192. package/.genie/wishes/release-system-genie-pattern/WISH.md +0 -268
  193. package/.genie/wishes/release-system-genie-pattern/validation.md +0 -205
  194. package/.gitguardian.yaml +0 -29
  195. package/.gitguardianignore +0 -16
  196. package/.github/workflows/ci.yml +0 -122
  197. package/.github/workflows/release.yml +0 -289
  198. package/.github/workflows/version.yml +0 -228
  199. package/.husky/pre-commit +0 -2
  200. package/AGENTS.md +0 -433
  201. package/CLAUDE.md +0 -1
  202. package/Makefile +0 -285
  203. package/assets/icon.ico +0 -0
  204. package/bun.lock +0 -435
  205. package/bunfig.toml +0 -28
  206. package/ecosystem.config.cjs +0 -23
  207. package/eslint.config.js +0 -63
  208. package/examples/multi-tenant-demo.js +0 -104
  209. package/install.sh +0 -123
  210. package/knip.json +0 -9
  211. package/tests/audit.test.js +0 -189
  212. package/tests/backpressure.test.js +0 -167
  213. package/tests/benchmarks/runner.js +0 -1197
  214. package/tests/benchmarks/vector-generator.js +0 -368
  215. package/tests/cli-install.test.js +0 -322
  216. package/tests/control-db.test.js +0 -285
  217. package/tests/daemon-args.test.js +0 -86
  218. package/tests/daemon-control.test.js +0 -171
  219. package/tests/daemon-fingerprint-integration.test.js +0 -111
  220. package/tests/daemon-pr24-regression.test.js +0 -198
  221. package/tests/fingerprint.test.js +0 -263
  222. package/tests/fixtures/240-orphan-seed.sql +0 -30
  223. package/tests/multi-tenant.test.js +0 -374
  224. package/tests/orphan-cleanup.test.js +0 -390
  225. package/tests/pg-version-regex.test.js +0 -129
  226. package/tests/quick-bench.js +0 -135
  227. package/tests/router-handshake-retry.test.js +0 -119
  228. package/tests/router-handshake-watchdog.test.js +0 -110
  229. package/tests/sdk.test.js +0 -71
  230. package/tests/stale-postmaster-pid.test.js +0 -85
  231. package/tests/stress-test.js +0 -439
  232. package/tests/sync-perf-test.js +0 -150
  233. package/tests/tcp-listen.test.js +0 -368
  234. package/tests/tenancy.test.js +0 -403
  235. package/tests/wrapper-supervision.test.js +0 -107
@@ -0,0 +1,1666 @@
1
+ /* pgserve console — layout-specific styles
2
+ * Foundations live in ../../colors_and_type.css.
3
+ */
4
+
5
+ html, body, #root { height: 100%; margin: 0; }
6
+ body { overflow: hidden; }
7
+
8
+ /* ============================================================
9
+ * CRT overlay — layered above content, below tweaks panel
10
+ * Composes scanlines + vignette + subtle RGB chroma fringe.
11
+ * Driven entirely by --scanline-opacity / --crt-vignette / --crt-chroma
12
+ * which app.jsx flips when the user changes the CRT intensity tweak.
13
+ * ============================================================ */
14
+ .crt-overlay {
15
+ position: fixed; inset: 0;
16
+ pointer-events: none;
17
+ z-index: 1000;
18
+ }
19
+ .crt-overlay > * {
20
+ position: absolute; inset: 0;
21
+ pointer-events: none;
22
+ mix-blend-mode: screen;
23
+ }
24
+ .crt-overlay .crt-scan {
25
+ background-image: repeating-linear-gradient(
26
+ to bottom,
27
+ transparent 0,
28
+ transparent 2px,
29
+ color-mix(in oklab, var(--accent) 70%, transparent) 2px,
30
+ color-mix(in oklab, var(--accent) 70%, transparent) 3px
31
+ );
32
+ opacity: var(--scanline-opacity, 0);
33
+ }
34
+ .crt-overlay .crt-vig {
35
+ background:
36
+ radial-gradient(120% 90% at 50% 50%,
37
+ transparent 55%,
38
+ rgba(0,0,0,calc(var(--crt-vignette, 0) * 0.5)) 78%,
39
+ rgba(0,0,0,var(--crt-vignette, 0)) 100%);
40
+ mix-blend-mode: multiply;
41
+ }
42
+ .crt-overlay .crt-chroma {
43
+ background:
44
+ radial-gradient(circle at 0% 50%,
45
+ color-mix(in oklab, #ff3b6b calc(var(--crt-chroma, 0) * 22%), transparent) 0%,
46
+ transparent 22%),
47
+ radial-gradient(circle at 100% 50%,
48
+ color-mix(in oklab, #3bd6ff calc(var(--crt-chroma, 0) * 22%), transparent) 0%,
49
+ transparent 22%);
50
+ mix-blend-mode: screen;
51
+ }
52
+
53
+ /* heavy mode — slight barrel curve via filter on .main */
54
+ :root[data-crt="heavy"] .main {
55
+ filter: contrast(1.04) saturate(1.08);
56
+ }
57
+ :root[data-crt="heavy"] .crt-overlay::after {
58
+ content: ''; position: absolute; inset: 0;
59
+ background: radial-gradient(140% 100% at 50% 50%,
60
+ transparent 60%,
61
+ rgba(0,0,0,0.18) 92%,
62
+ rgba(0,0,0,0.32) 100%);
63
+ pointer-events: none;
64
+ }
65
+
66
+ /* phosphor glow — only when CRT is on; targets accent-colored text + dots.
67
+ * Applied via attribute selector so it's free when off (no recompute). */
68
+ :root[data-crt="subtle"] .topbar .wm .cur,
69
+ :root[data-crt="heavy"] .topbar .wm .cur,
70
+ :root[data-crt="subtle"] .footer .ok,
71
+ :root[data-crt="heavy"] .footer .ok,
72
+ :root[data-crt="subtle"] .topbar .pill .dot,
73
+ :root[data-crt="heavy"] .topbar .pill .dot,
74
+ :root[data-crt="subtle"] .stat .val .accent,
75
+ :root[data-crt="heavy"] .stat .val .accent,
76
+ :root[data-crt="subtle"] .swarm-prompt .glyph,
77
+ :root[data-crt="heavy"] .swarm-prompt .glyph,
78
+ :root[data-crt="subtle"] .cursor-blink::after,
79
+ :root[data-crt="heavy"] .cursor-blink::after {
80
+ text-shadow:
81
+ 0 0 var(--phosphor-glow, 0) var(--accent),
82
+ 0 0 calc(var(--phosphor-glow, 0) * 2) color-mix(in oklab, var(--accent) 40%, transparent);
83
+ }
84
+ :root[data-crt="heavy"] .topbar .pill .dot {
85
+ box-shadow:
86
+ 0 0 0 2px color-mix(in oklab, var(--accent) 24%, transparent),
87
+ 0 0 var(--phosphor-glow) var(--accent);
88
+ }
89
+
90
+ /* lumon override — phosphor glow & scanlines off in light mode regardless of tweak,
91
+ * because they read as wrong (CRT artifacts on a white page = visual nonsense).
92
+ * The vignette stays so heavy mode still feels different. */
93
+ :root[data-theme="lumon"] .crt-overlay .crt-scan,
94
+ :root[data-theme="lumon"] .crt-overlay .crt-chroma {
95
+ display: none;
96
+ }
97
+ :root[data-theme="lumon"][data-crt="subtle"] *,
98
+ :root[data-theme="lumon"][data-crt="heavy"] * {
99
+ text-shadow: none !important;
100
+ }
101
+
102
+ .app {
103
+ display: grid;
104
+ grid-template-rows: 44px 1fr 22px;
105
+ grid-template-columns: 240px 1fr;
106
+ grid-template-areas: "tb tb" "sb main" "sf sf";
107
+ height: 100vh;
108
+ background: var(--surface-canvas);
109
+ color: var(--text-primary);
110
+ }
111
+
112
+ /* topbar */
113
+ .topbar {
114
+ grid-area: tb;
115
+ display: flex; align-items: center; gap: 12px;
116
+ padding: 0 16px;
117
+ border-bottom: 1px solid var(--line);
118
+ background: var(--surface-canvas);
119
+ font-family: var(--font-mono); font-size: 12px;
120
+ }
121
+ .topbar .wm { font-weight: 600; font-size: 14px; letter-spacing: -0.01em; display: flex; gap: 4px; align-items: baseline;}
122
+ .topbar .wm .cur { color: var(--accent); animation: pgsv-blink 1.05s steps(2) infinite; }
123
+ .topbar .meta { color: var(--text-dim); display: flex; gap: 14px; align-items: center; white-space: nowrap; }
124
+ .topbar .meta > * { flex-shrink: 0; }
125
+ .topbar .meta .sep { color: var(--line-strong); }
126
+ .topbar .right { margin-left: auto; display: flex; gap: 8px; align-items: center; }
127
+ .topbar .pill {
128
+ border: 1px solid var(--line); padding: 3px 8px;
129
+ font-size: 11px; letter-spacing: 0.04em;
130
+ display: inline-flex; gap: 6px; align-items: center;
131
+ white-space: nowrap; flex-shrink: 0;
132
+ }
133
+ .topbar .pill .dot { width: 6px; height: 6px; background: var(--accent); border-radius: 50%; box-shadow: 0 0 0 2px color-mix(in oklab, var(--accent) 24%, transparent); }
134
+ .theme-switch { border: 1px solid var(--line); display: flex; }
135
+ .theme-switch button {
136
+ background: transparent; border: 0; color: var(--text-dim);
137
+ font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.06em;
138
+ padding: 4px 8px; cursor: pointer; text-transform: uppercase;
139
+ display: inline-flex; align-items: center; justify-content: center;
140
+ width: 28px; height: 22px; line-height: 0;
141
+ transition: color 120ms, background 120ms;
142
+ }
143
+ .theme-switch button:hover { color: var(--text-primary); }
144
+ .theme-switch button.on { background: var(--accent); color: var(--surface-canvas); }
145
+ .theme-switch button svg { display: block; }
146
+
147
+ /* sidebar */
148
+ .sidebar {
149
+ grid-area: sb;
150
+ border-right: 1px solid var(--line);
151
+ background: var(--surface-canvas);
152
+ padding: 14px 0;
153
+ overflow-y: auto;
154
+ font-family: var(--font-mono);
155
+ }
156
+ .sidebar .group { margin: 0 0 14px; }
157
+ .sidebar .group-label {
158
+ font-size: 10px; letter-spacing: 0.12em; text-transform: uppercase;
159
+ color: var(--text-dim);
160
+ padding: 0 18px 6px;
161
+ }
162
+ .sidebar .nav-item {
163
+ display: flex; align-items: center; gap: 10px;
164
+ padding: 6px 18px;
165
+ font-size: 13px; color: var(--text-secondary);
166
+ cursor: pointer; border-left: 2px solid transparent;
167
+ white-space: nowrap;
168
+ }
169
+ .sidebar .nav-item:hover { background: var(--surface-panel); color: var(--text-primary); }
170
+ .sidebar .nav-item.on {
171
+ background: var(--surface-panel); color: var(--text-primary);
172
+ border-left-color: var(--accent);
173
+ }
174
+ .sidebar .nav-item .glyph {
175
+ width: 16px; display: inline-flex; justify-content: center;
176
+ color: var(--text-dim); font-size: 13px;
177
+ }
178
+ .sidebar .nav-item.on .glyph { color: var(--accent); }
179
+ .sidebar .nav-item .count { margin-left: auto; color: var(--text-dim); font-size: 11px; }
180
+
181
+ /* main */
182
+ .main { grid-area: main; overflow: auto; }
183
+ .page { padding: 24px 28px 64px; max-width: 100%; }
184
+ .page-head { display: flex; align-items: baseline; gap: 16px; margin-bottom: 18px; }
185
+ .page-head h1 { font-family: var(--font-mono); font-weight: 500; font-size: 22px; letter-spacing: -0.02em; margin: 0; }
186
+ .page-head .crumb { color: var(--text-dim); font-family: var(--font-mono); font-size: 12px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }
187
+ .page-head .right { margin-left: auto; display: flex; gap: 8px; flex-shrink: 0; }
188
+
189
+ /* footer */
190
+ .footer {
191
+ grid-area: sf;
192
+ position: relative; /* anchor for .live-popover */
193
+ border-top: 1px solid var(--line);
194
+ background: var(--surface-canvas);
195
+ display: flex; align-items: center; gap: 16px;
196
+ padding: 0 16px;
197
+ font-family: var(--font-mono); font-size: 11px; color: var(--text-dim);
198
+ }
199
+ .footer .ok { color: var(--accent); }
200
+ .footer .sep { color: var(--line-strong); }
201
+
202
+ /* live-status button — sits at the right edge of the footer, click to
203
+ * open the health popover. Hover keeps the legacy native `title`. */
204
+ .live-btn {
205
+ background: transparent; border: 1px solid var(--line);
206
+ color: inherit; cursor: pointer;
207
+ padding: 3px 10px; height: 22px;
208
+ font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.04em;
209
+ display: inline-flex; align-items: center; gap: 6px;
210
+ transition: border-color 120ms, color 120ms;
211
+ }
212
+ .live-btn:hover { border-color: var(--accent); color: var(--text-primary); }
213
+ .live-btn.on { border-color: var(--accent); color: var(--accent); }
214
+ .live-btn.down { border-color: var(--status-error, #d66); color: var(--status-error, #d66); }
215
+ .live-btn .dot { width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
216
+
217
+ /* health popover — bottom-anchored above the .live-btn */
218
+ .live-popover {
219
+ position: absolute;
220
+ bottom: calc(100% + 6px); /* above the footer with a small gap */
221
+ right: 12px;
222
+ min-width: 280px; max-width: 360px;
223
+ background: var(--surface-canvas);
224
+ border: 1px solid var(--line);
225
+ box-shadow: 0 -6px 20px rgba(0, 0, 0, 0.35);
226
+ font-family: var(--font-mono); font-size: 11px; line-height: 1.55;
227
+ color: var(--text-primary);
228
+ z-index: 20;
229
+ }
230
+ .live-popover .head {
231
+ display: flex; align-items: center; justify-content: space-between;
232
+ padding: 8px 12px;
233
+ border-bottom: 1px solid var(--line);
234
+ color: var(--text-dim); text-transform: uppercase;
235
+ letter-spacing: 0.08em; font-size: 10px;
236
+ }
237
+ .live-popover .head .close {
238
+ background: transparent; border: 0; cursor: pointer;
239
+ color: var(--text-dim); font-size: 12px; padding: 0 4px;
240
+ }
241
+ .live-popover .head .close:hover { color: var(--text-primary); }
242
+ .live-popover pre {
243
+ margin: 0; padding: 10px 12px;
244
+ white-space: pre; overflow: auto;
245
+ font-family: var(--font-mono); font-size: 11px;
246
+ color: var(--text-secondary);
247
+ }
248
+
249
+ /* atoms */
250
+ .btn {
251
+ font-family: var(--font-mono); font-size: 12px; letter-spacing: 0.02em;
252
+ padding: 5px 12px; border: 1px solid var(--line);
253
+ background: var(--surface-panel); color: var(--text-primary);
254
+ cursor: pointer; height: 28px; display: inline-flex; align-items: center; gap: 6px;
255
+ border-radius: 2px;
256
+ transition: background var(--dur-micro) var(--ease), border-color var(--dur-micro) var(--ease);
257
+ }
258
+ .btn:hover { background: var(--surface-raised); }
259
+ .btn.primary { background: var(--accent); color: var(--surface-canvas); border-color: var(--accent); }
260
+ .btn.primary:hover { background: var(--accent-hover); border-color: var(--accent-hover); }
261
+ .btn.danger { color: var(--status-error); border-color: color-mix(in oklab, var(--status-error) 50%, var(--line)); }
262
+ .btn.danger:hover { background: color-mix(in oklab, var(--status-error) 12%, var(--surface-panel)); }
263
+ .btn.ghost { background: transparent; border-color: transparent; color: var(--text-secondary); }
264
+ .btn.ghost:hover { color: var(--text-primary); background: var(--surface-panel); }
265
+ .btn.sm { height: 22px; padding: 2px 8px; font-size: 11px; }
266
+
267
+ .tag {
268
+ display: inline-flex; align-items: center; gap: 4px;
269
+ font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.04em;
270
+ padding: 2px 6px; border: 1px solid var(--line); color: var(--text-secondary);
271
+ text-transform: uppercase;
272
+ }
273
+ .tag.ok { color: var(--accent); border-color: var(--accent-line); }
274
+ .tag.warn { color: var(--status-warn); border-color: color-mix(in oklab, var(--status-warn) 40%, var(--line));}
275
+ .tag.err { color: var(--status-error); border-color: color-mix(in oklab, var(--status-error) 50%, var(--line)); }
276
+ .tag.vec { color: var(--status-vector); border-color: color-mix(in oklab, var(--status-vector) 50%, var(--line)); }
277
+ .tag.audit { color: var(--status-audit); border-color: color-mix(in oklab, var(--status-audit) 50%, var(--line)); }
278
+ .tag.persist { color: var(--accent); border-color: var(--accent-line); }
279
+ .tag.ephemeral { color: var(--text-dim); }
280
+
281
+ .input {
282
+ font-family: var(--font-mono); font-size: 12px;
283
+ height: 28px; padding: 0 10px;
284
+ background: var(--surface-canvas); color: var(--text-primary);
285
+ border: 1px solid var(--line); border-radius: 2px;
286
+ outline: none;
287
+ transition: border-color var(--dur-micro) var(--ease);
288
+ }
289
+ .input:focus { border-color: var(--accent); }
290
+ .input.search { width: 280px; }
291
+
292
+ .bracket-h {
293
+ font-family: var(--font-mono); font-size: 11px;
294
+ letter-spacing: 0.1em; text-transform: uppercase;
295
+ color: var(--status-info);
296
+ margin: 0 0 8px;
297
+ }
298
+ .bracket-h .dim { color: var(--text-dim); margin-left: 8px; letter-spacing: 0.04em; }
299
+
300
+ .panel {
301
+ background: var(--surface-panel); border: 1px solid var(--line);
302
+ padding: 16px 20px;
303
+ }
304
+
305
+ /* stat tile */
306
+ .stat {
307
+ background: var(--surface-panel); border: 1px solid var(--line); padding: 14px 16px;
308
+ display: flex; flex-direction: column; gap: 6px;
309
+ }
310
+ .stat .lbl { font-family: var(--font-mono); font-size: 10px; color: var(--text-dim); letter-spacing: 0.1em; text-transform: uppercase; }
311
+ .stat .val { font-family: var(--font-mono); font-size: 28px; line-height: 1.05; letter-spacing: -0.02em; color: var(--text-primary); font-variant-numeric: tabular-nums slashed-zero; }
312
+ .stat .val .accent { color: var(--accent); }
313
+ .stat .sub { font-family: var(--font-mono); font-size: 11px; color: var(--text-dim); }
314
+ .stat .sub .ok { color: var(--accent); }
315
+ .stat .sub .warn { color: var(--status-warn); }
316
+ .stat .sub .err { color: var(--status-error); }
317
+
318
+ /* mini bar */
319
+ .mbar {
320
+ display: inline-flex; gap: 1px; align-items: center;
321
+ font-family: var(--font-mono); letter-spacing: -0.5px;
322
+ }
323
+ .mbar .blk { color: var(--accent); }
324
+ .mbar .blk.warn { color: var(--status-warn); }
325
+ .mbar .blk.err { color: var(--status-error); }
326
+ .mbar .empty { color: var(--text-dim); opacity: 0.6; }
327
+
328
+ /* table */
329
+ .tbl {
330
+ width: 100%; border-collapse: collapse;
331
+ font-family: var(--font-mono); font-size: 12px;
332
+ }
333
+ .tbl th {
334
+ text-align: left; font-weight: 400; color: var(--text-dim);
335
+ font-size: 10px; letter-spacing: 0.08em; text-transform: uppercase;
336
+ padding: 8px 12px; border-bottom: 1px solid var(--line);
337
+ background: var(--surface-canvas);
338
+ position: sticky; top: 0; z-index: 1;
339
+ }
340
+ .tbl td { padding: 8px 12px; border-bottom: 1px solid var(--line); height: 32px; vertical-align: middle; }
341
+ .tbl tr:hover td { background: var(--surface-panel); }
342
+ .tbl tr.on td { background: var(--accent-tint); }
343
+ .tbl td.num { text-align: right; }
344
+ .tbl td.fp { color: var(--accent); }
345
+ .tbl td .muted { color: var(--text-dim); }
346
+
347
+ /* log line */
348
+ .log-line {
349
+ display: grid; grid-template-columns: 88px 84px 1fr;
350
+ gap: 10px; padding: 4px 12px; font-family: var(--font-mono); font-size: 12px;
351
+ border-bottom: 1px dashed color-mix(in oklab, var(--line) 60%, transparent);
352
+ }
353
+ .log-line .ts { color: var(--text-dim); }
354
+ .log-line .lvl { letter-spacing: 0.06em; text-transform: uppercase; }
355
+ .log-line .lvl.info { color: var(--status-info); }
356
+ .log-line .lvl.warn { color: var(--status-warn); }
357
+ .log-line .lvl.err { color: var(--status-error); }
358
+ .log-line .lvl.audit { color: var(--status-audit); }
359
+ .log-line .msg { color: var(--text-primary); white-space: pre-wrap; word-break: break-word; }
360
+ .log-line .msg .acc { color: var(--accent); }
361
+ .log-line .msg .dim { color: var(--text-dim); }
362
+
363
+ /* spreadsheet */
364
+ .grid-table {
365
+ border: 1px solid var(--line); background: var(--surface-canvas);
366
+ font-family: var(--font-mono); font-size: 12px;
367
+ display: grid; overflow: auto;
368
+ }
369
+ .gt-row { display: contents; }
370
+ .gt-cell {
371
+ border-right: 1px solid var(--line);
372
+ border-bottom: 1px solid var(--line);
373
+ padding: 0 10px; height: 32px; display: flex; align-items: center; gap: 6px;
374
+ background: var(--surface-canvas); cursor: cell;
375
+ white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
376
+ }
377
+ .gt-cell.head {
378
+ background: var(--surface-panel); color: var(--text-dim);
379
+ font-size: 10px; letter-spacing: 0.08em; text-transform: uppercase;
380
+ cursor: default;
381
+ }
382
+ .gt-cell.head .type { color: var(--accent); font-size: 9px; margin-left: 4px; }
383
+ .gt-cell.head .type.vec { color: var(--status-vector); }
384
+ .gt-cell.editing { outline: 2px solid var(--accent); outline-offset: -2px; background: var(--accent-tint); }
385
+ .gt-cell.selected { background: var(--accent-tint); }
386
+ .gt-cell .nullv { color: var(--text-dim); font-style: italic; }
387
+ .gt-cell .vecv { color: var(--status-vector); }
388
+ .gt-cell.numc { justify-content: flex-end; }
389
+
390
+ /* code blocks */
391
+ .code-block {
392
+ background: var(--surface-canvas); border: 1px solid var(--line);
393
+ padding: 12px 14px; font-family: var(--font-mono); font-size: 12px;
394
+ color: var(--text-secondary); white-space: pre; overflow: auto;
395
+ line-height: 1.6;
396
+ }
397
+ .kw { color: var(--status-info); }
398
+ .lit { color: var(--accent); }
399
+ .fn { color: var(--status-vector); }
400
+ .cm { color: var(--text-dim); }
401
+
402
+ /* progress / threshold */
403
+ .threshold {
404
+ display: flex; align-items: center; gap: 10px; font-family: var(--font-mono); font-size: 11px;
405
+ }
406
+ .threshold .lbl { color: var(--text-dim); width: 110px; flex-shrink: 0; text-transform: uppercase; letter-spacing: 0.06em; font-size: 10px; }
407
+ .threshold .track { flex: 1; height: 4px; background: var(--surface-raised); position: relative; }
408
+ .threshold .fill { position: absolute; left: 0; top: 0; bottom: 0; background: var(--accent); }
409
+ .threshold .fill.warn { background: var(--status-warn); }
410
+ .threshold .fill.err { background: var(--status-error); }
411
+ .threshold .v { color: var(--text-primary); width: 80px; text-align: right; }
412
+
413
+ /* sparkline */
414
+ .spark { display: block; }
415
+
416
+ /* drawer */
417
+ .drawer {
418
+ position: fixed; right: 0; top: 44px; bottom: 22px;
419
+ width: 480px; background: var(--surface-panel);
420
+ border-left: 1px solid var(--line);
421
+ padding: 18px 22px; overflow: auto;
422
+ z-index: 5;
423
+ }
424
+
425
+ /* alert banner */
426
+ .alert {
427
+ border: 1px solid var(--line); border-left: 2px solid var(--status-warn);
428
+ background: var(--surface-panel);
429
+ padding: 10px 14px; font-family: var(--font-mono); font-size: 12px;
430
+ display: flex; align-items: center; gap: 10px;
431
+ margin-bottom: 14px;
432
+ }
433
+ .alert.err { border-left-color: var(--status-error); }
434
+ .alert.ok { border-left-color: var(--accent); }
435
+ .alert .lbl { color: var(--status-warn); text-transform: uppercase; letter-spacing: 0.08em; font-size: 10px; }
436
+ .alert.err .lbl { color: var(--status-error); }
437
+ .alert.ok .lbl { color: var(--accent); }
438
+ .alert .msg { color: var(--text-primary); flex: 1; }
439
+ .alert .actions { display: flex; gap: 6px; }
440
+
441
+ /* score chip */
442
+ .score {
443
+ font-family: var(--font-mono); font-size: 22px; letter-spacing: -0.02em;
444
+ display: inline-flex; align-items: baseline; gap: 3px;
445
+ font-variant-numeric: tabular-nums;
446
+ }
447
+ .score .max { color: var(--text-dim); font-size: 12px; }
448
+ .score.ok .v { color: var(--accent); }
449
+ .score.warn .v { color: var(--status-warn); }
450
+ .score.err .v { color: var(--status-error); }
451
+
452
+ /* segmented */
453
+ .seg { display: inline-flex; border: 1px solid var(--line); }
454
+ .seg button {
455
+ background: transparent; border: 0; color: var(--text-secondary);
456
+ font-family: var(--font-mono); font-size: 11px; padding: 4px 10px; cursor: pointer;
457
+ letter-spacing: 0.05em;
458
+ }
459
+ .seg button.on { background: var(--accent); color: var(--surface-canvas); }
460
+ .seg button + button { border-left: 1px solid var(--line); }
461
+ .seg button.on + button, .seg button + button.on { border-left-color: transparent; }
462
+
463
+
464
+ /* ============================================================
465
+ * RLM — Recursive Language Model trace
466
+ * Terminal-style chat: question → iterations → REPL cells → recursive sub-LM frames
467
+ * ============================================================ */
468
+
469
+ /* prompt strip — editable textarea */
470
+ .rlm-prompt {
471
+ border-bottom: 1px solid var(--line);
472
+ background: var(--surface-canvas);
473
+ padding: 14px 18px 12px;
474
+ display: grid; grid-template-columns: auto minmax(0, 1fr) auto; gap: 16px;
475
+ align-items: start;
476
+ }
477
+ .rlm-prompt .glyph { color: var(--accent); font-size: 18px; font-family: var(--font-mono); padding-top: 18px; }
478
+ .rlm-prompt .body { min-width: 0; display: flex; flex-direction: column; gap: 8px; }
479
+ .rlm-prompt .label {
480
+ font-family: var(--font-mono); font-size: 10px;
481
+ color: var(--text-dim); letter-spacing: 0.1em; text-transform: uppercase;
482
+ }
483
+ .rlm-prompt .actions { padding-top: 16px; display: flex; gap: 8px; flex-shrink: 0; }
484
+ .rlm-input {
485
+ width: 100%; resize: vertical; min-height: 44px;
486
+ background: var(--surface-panel); border: 1px solid var(--line);
487
+ color: var(--text-primary);
488
+ font-family: var(--font-sans); font-size: 16px; line-height: 1.4;
489
+ letter-spacing: -0.01em;
490
+ padding: 10px 12px;
491
+ outline: none;
492
+ }
493
+ .rlm-input:focus { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent-line); }
494
+ .rlm-prompt .suggestions { display: flex; gap: 8px; flex-wrap: wrap; align-items: baseline; }
495
+ .rlm-prompt .suggestions .lbl {
496
+ font-family: var(--font-mono); font-size: 10px;
497
+ color: var(--text-dim); letter-spacing: 0.06em; text-transform: uppercase;
498
+ }
499
+ .rlm-prompt .suggestions .sg {
500
+ font-family: var(--font-mono); font-size: 11px;
501
+ background: transparent; border: 1px solid var(--line);
502
+ color: var(--text-secondary); padding: 3px 8px;
503
+ cursor: pointer;
504
+ }
505
+ .rlm-prompt .suggestions .sg:hover { color: var(--accent); border-color: var(--accent-line); background: var(--accent-tint); }
506
+
507
+ /* status strip */
508
+ .rlm-status {
509
+ display: flex; align-items: center; gap: 14px;
510
+ padding: 8px 18px;
511
+ background: var(--surface-panel);
512
+ border-bottom: 1px solid var(--line);
513
+ font-family: var(--font-mono); font-size: 11px;
514
+ color: var(--text-secondary);
515
+ }
516
+ .rlm-status .m { display: inline-flex; align-items: baseline; gap: 6px; }
517
+ .rlm-status .k { color: var(--text-dim); letter-spacing: 0.04em; text-transform: uppercase; font-size: 10px; }
518
+ .rlm-status .v { color: var(--text-primary); font-variant-numeric: tabular-nums; }
519
+ .rlm-status .sep { color: var(--line-strong); }
520
+ .rlm-status .live-pill {
521
+ font-size: 10px; letter-spacing: 0.08em; text-transform: uppercase;
522
+ color: var(--accent); border: 1px solid var(--accent); background: var(--accent-tint);
523
+ padding: 2px 8px;
524
+ animation: rlm-blink 1.2s steps(2) infinite;
525
+ }
526
+ .rlm-status .ok-pill {
527
+ font-size: 10px; letter-spacing: 0.08em; text-transform: uppercase;
528
+ color: var(--accent); border: 1px solid var(--accent-line);
529
+ padding: 2px 8px;
530
+ }
531
+ @keyframes rlm-blink { 0%, 49% { opacity: 1; } 50%, 100% { opacity: 0.4; } }
532
+
533
+ /* trace scroll region */
534
+ .rlm-scroll {
535
+ overflow: auto;
536
+ padding: 18px 22px 24px;
537
+ font-family: var(--font-mono);
538
+ background: var(--surface-canvas);
539
+ }
540
+
541
+ /* the user's question, rendered chat-style at top */
542
+ .rlm-question {
543
+ display: grid; grid-template-columns: 70px 1fr; gap: 14px;
544
+ padding-bottom: 16px;
545
+ border-bottom: 1px solid var(--line);
546
+ margin-bottom: 16px;
547
+ }
548
+ .rlm-question .who {
549
+ font-family: var(--font-mono); font-size: 10px;
550
+ color: var(--text-dim); letter-spacing: 0.1em; text-transform: uppercase;
551
+ padding-top: 4px;
552
+ }
553
+ .rlm-question .body {
554
+ font-family: var(--font-sans); font-size: 16px;
555
+ color: var(--text-primary); letter-spacing: -0.01em; line-height: 1.45;
556
+ }
557
+
558
+ /* ── RLMTrace container ─────────────────────────────────── */
559
+ .rlm-trace { display: flex; flex-direction: column; gap: 8px; }
560
+ .rlm-trace.nested { gap: 6px; }
561
+
562
+ /* ── iteration card (root step) ───────────────────────── */
563
+ .rlm-iter {
564
+ border: 1px solid var(--line);
565
+ background: var(--surface-panel);
566
+ }
567
+ .rlm-iter.live { border-color: var(--accent); }
568
+ .rlm-iter.final { border-color: var(--accent-line); }
569
+
570
+ .rlm-iter-head {
571
+ width: 100%; display: grid;
572
+ grid-template-columns: 14px auto 1fr auto;
573
+ gap: 10px; align-items: baseline;
574
+ padding: 9px 12px;
575
+ background: transparent; border: 0;
576
+ font-family: var(--font-mono); font-size: 12px;
577
+ color: var(--text-secondary);
578
+ cursor: pointer; text-align: left;
579
+ border-bottom: 1px solid transparent;
580
+ }
581
+ .rlm-iter-head:hover { background: color-mix(in oklab, var(--accent) 4%, transparent); }
582
+ .rlm-iter-head .caret { color: var(--text-dim); }
583
+ .rlm-iter-head .step {
584
+ color: var(--accent); letter-spacing: 0.04em;
585
+ text-transform: uppercase; font-size: 11px;
586
+ }
587
+ .rlm-iter-head .title { color: var(--text-primary); }
588
+ .rlm-iter-head .meta {
589
+ display: inline-flex; gap: 10px; align-items: baseline;
590
+ font-size: 10px; color: var(--text-dim); letter-spacing: 0.04em;
591
+ }
592
+ .rlm-iter-head .meta .tok { font-variant-numeric: tabular-nums; }
593
+ .rlm-iter-head .meta .ms { color: var(--text-secondary); font-variant-numeric: tabular-nums; }
594
+ .rlm-iter-head .meta .cb { color: var(--status-vector); }
595
+ .rlm-iter-head .meta .live-pill {
596
+ color: var(--accent); border: 1px solid var(--accent); background: var(--accent-tint);
597
+ padding: 1px 6px; font-size: 9px; letter-spacing: 0.1em;
598
+ animation: rlm-blink 1.2s steps(2) infinite;
599
+ }
600
+ .rlm-iter-head .meta .final-pill {
601
+ color: var(--accent); border: 1px solid var(--accent);
602
+ padding: 1px 6px; font-size: 9px; letter-spacing: 0.1em;
603
+ }
604
+
605
+ .rlm-iter-body {
606
+ border-top: 1px solid var(--line);
607
+ padding: 10px 14px 12px 36px;
608
+ display: flex; flex-direction: column; gap: 10px;
609
+ background: var(--surface-canvas);
610
+ }
611
+
612
+ /* reasoning text — looks like LM output */
613
+ .rlm-reason {
614
+ font-family: var(--font-mono); font-size: 12px;
615
+ color: var(--text-secondary); line-height: 1.65;
616
+ white-space: pre-wrap;
617
+ border-left: 2px solid var(--line);
618
+ padding: 2px 0 2px 12px;
619
+ }
620
+ .rlm-reason p { margin: 0; }
621
+ .rlm-reason p + p { margin-top: 4px; }
622
+ .rlm-reason .cursor-blink {
623
+ display: inline-block; width: 7px; height: 12px;
624
+ background: var(--accent); margin-left: 2px;
625
+ vertical-align: text-bottom;
626
+ animation: rlm-blink 1s steps(2) infinite;
627
+ }
628
+
629
+ /* ── REPL code cell ───────────────────────────────────── */
630
+ .rlm-cell {
631
+ border: 1px solid var(--line);
632
+ background: var(--surface-panel);
633
+ }
634
+ .rlm-cell.live { border-color: var(--accent); }
635
+ .rlm-cell.err { border-color: var(--status-error); }
636
+
637
+ .rlm-cell-head {
638
+ width: 100%; display: grid;
639
+ grid-template-columns: 14px auto 1fr auto;
640
+ gap: 10px; align-items: baseline;
641
+ padding: 7px 11px;
642
+ background: transparent; border: 0;
643
+ font-family: var(--font-mono); font-size: 11px;
644
+ color: var(--text-secondary);
645
+ cursor: pointer; text-align: left;
646
+ }
647
+ .rlm-cell-head:hover { background: color-mix(in oklab, var(--accent) 4%, transparent); }
648
+ .rlm-cell-head .caret { color: var(--text-dim); }
649
+ .rlm-cell-head .prompt { color: var(--accent); font-variant-numeric: tabular-nums; }
650
+ .rlm-cell-head .title {
651
+ color: var(--text-dim); letter-spacing: 0.04em; text-transform: uppercase; font-size: 10px;
652
+ }
653
+ .rlm-cell-head .meta { display: inline-flex; gap: 10px; font-size: 10px; color: var(--text-dim); }
654
+ .rlm-cell-head .meta .ms { color: var(--text-secondary); font-variant-numeric: tabular-nums; }
655
+ .rlm-cell-head .meta .subs { color: var(--status-vector); }
656
+ .rlm-cell-head .meta .live-pill {
657
+ color: var(--accent); border: 1px solid var(--accent); background: var(--accent-tint);
658
+ padding: 1px 6px; font-size: 9px; letter-spacing: 0.1em;
659
+ animation: rlm-blink 1.2s steps(2) infinite;
660
+ }
661
+
662
+ .rlm-cell-body { border-top: 1px solid var(--line); }
663
+
664
+ /* python source */
665
+ .rlm-code {
666
+ margin: 0;
667
+ padding: 10px 14px;
668
+ font-family: var(--font-mono); font-size: 12px; line-height: 1.55;
669
+ color: var(--text-primary);
670
+ background: var(--surface-canvas);
671
+ overflow-x: auto;
672
+ white-space: pre;
673
+ }
674
+ .rlm-code .cm { color: var(--text-dim); font-style: italic; }
675
+ .rlm-code .lit { color: var(--status-warn); }
676
+ .rlm-code .kw { color: var(--accent); }
677
+ .rlm-code .fn { color: var(--status-vector); }
678
+ .rlm-code .num { color: var(--status-info); }
679
+
680
+ /* stdout / stderr */
681
+ .rlm-out {
682
+ background: var(--surface-canvas);
683
+ border-top: 1px dashed var(--line);
684
+ padding: 8px 14px;
685
+ }
686
+ .rlm-out-label {
687
+ font-family: var(--font-mono); font-size: 9px;
688
+ color: var(--text-dim); letter-spacing: 0.1em; text-transform: uppercase;
689
+ margin-bottom: 4px;
690
+ }
691
+ .rlm-out.err .rlm-out-label { color: var(--status-error); }
692
+ .rlm-out-body {
693
+ margin: 0;
694
+ font-family: var(--font-mono); font-size: 11px; line-height: 1.55;
695
+ color: var(--text-secondary);
696
+ white-space: pre-wrap;
697
+ }
698
+ .rlm-out.err .rlm-out-body { color: var(--status-error); }
699
+
700
+ /* sub-call container inside a cell */
701
+ .rlm-subs {
702
+ background: var(--surface-canvas);
703
+ border-top: 1px dashed var(--line);
704
+ padding: 8px 14px 10px;
705
+ display: flex; flex-direction: column; gap: 6px;
706
+ }
707
+
708
+ /* ── recursive_llm sub-call frame ──────────────────────── */
709
+ .rlm-sub {
710
+ border: 1px solid var(--line);
711
+ background: var(--surface-panel);
712
+ }
713
+ .rlm-sub.live { border-color: var(--accent); }
714
+ .rlm-sub.done { border-color: color-mix(in oklab, var(--accent) 35%, var(--line)); }
715
+
716
+ .rlm-sub-head {
717
+ width: 100%; display: flex; flex-wrap: wrap; gap: 4px; align-items: baseline;
718
+ padding: 6px 10px;
719
+ background: transparent; border: 0;
720
+ font-family: var(--font-mono); font-size: 11px;
721
+ color: var(--text-secondary);
722
+ cursor: pointer; text-align: left;
723
+ }
724
+ .rlm-sub-head:hover { background: color-mix(in oklab, var(--accent) 4%, transparent); }
725
+ .rlm-sub-head .caret { color: var(--text-dim); margin-right: 4px; }
726
+ .rlm-sub-head .fn { color: var(--status-vector); }
727
+ .rlm-sub-head .paren { color: var(--text-dim); }
728
+ .rlm-sub-head .qstr { color: var(--status-warn); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 360px; }
729
+ .rlm-sub-head .arg { color: var(--text-dim); font-style: italic; }
730
+ .rlm-sub-head .meta {
731
+ margin-left: auto; display: inline-flex; gap: 10px; align-items: baseline;
732
+ font-size: 10px; color: var(--text-dim); letter-spacing: 0.04em;
733
+ }
734
+ .rlm-sub-head .meta .depth {
735
+ color: var(--accent); border: 1px solid var(--accent-line);
736
+ padding: 0 5px; letter-spacing: 0.06em;
737
+ }
738
+ .rlm-sub-head .meta .model { color: var(--text-secondary); }
739
+ .rlm-sub-head .meta .tok { font-variant-numeric: tabular-nums; }
740
+ .rlm-sub-head .meta .ms { color: var(--text-secondary); font-variant-numeric: tabular-nums; }
741
+ .rlm-sub-head .meta .live-pill {
742
+ color: var(--accent); border: 1px solid var(--accent); background: var(--accent-tint);
743
+ padding: 1px 6px; font-size: 9px; letter-spacing: 0.1em;
744
+ animation: rlm-blink 1.2s steps(2) infinite;
745
+ }
746
+
747
+ .rlm-sub-body { border-top: 1px solid var(--line); padding: 8px 12px 10px; background: var(--surface-canvas); }
748
+
749
+ .rlm-sub-resp { }
750
+ .rlm-sub-resp-label {
751
+ font-family: var(--font-mono); font-size: 9px;
752
+ color: var(--text-dim); letter-spacing: 0.1em; text-transform: uppercase;
753
+ margin-bottom: 4px;
754
+ }
755
+ .rlm-sub-resp-body {
756
+ margin: 0;
757
+ font-family: var(--font-sans); font-size: 13px; line-height: 1.55;
758
+ color: var(--text-primary); letter-spacing: -0.005em;
759
+ white-space: pre-wrap;
760
+ }
761
+
762
+ /* nested trace inside a sub-call gets a faint left rail */
763
+ .rlm-sub-body .rlm-trace.nested {
764
+ border-left: 2px solid var(--accent-line);
765
+ padding-left: 10px;
766
+ margin-left: 2px;
767
+ }
768
+
769
+ /* ── final answer in last iteration ─────────────────────── */
770
+ .rlm-final {
771
+ border: 1px solid var(--accent);
772
+ background: color-mix(in oklab, var(--accent) 7%, var(--surface-canvas));
773
+ padding: 10px 14px;
774
+ }
775
+ .rlm-final-label {
776
+ font-family: var(--font-mono); font-size: 9px;
777
+ color: var(--accent); letter-spacing: 0.1em; text-transform: uppercase;
778
+ margin-bottom: 6px;
779
+ }
780
+ .rlm-final-body {
781
+ font-family: var(--font-sans); font-size: 14px;
782
+ color: var(--text-primary); letter-spacing: -0.005em; line-height: 1.5;
783
+ white-space: pre-wrap;
784
+ }
785
+
786
+ /* ── final answer block at bottom of trace ──────────────── */
787
+ .rlm-answer-block {
788
+ margin-top: 14px;
789
+ border: 1px solid var(--accent);
790
+ background: color-mix(in oklab, var(--accent) 6%, var(--surface-canvas));
791
+ padding: 14px 18px;
792
+ }
793
+ .rlm-answer-head {
794
+ display: flex; align-items: baseline; gap: 12px;
795
+ font-family: var(--font-mono); font-size: 11px;
796
+ color: var(--text-dim); letter-spacing: 0.06em; text-transform: uppercase;
797
+ margin-bottom: 10px;
798
+ }
799
+ .rlm-answer-head .who { color: var(--accent); }
800
+ .rlm-answer-head .lbl { color: var(--text-primary); }
801
+ .rlm-answer-head .meta { margin-left: auto; color: var(--text-secondary); }
802
+ .rlm-answer-body {
803
+ font-family: var(--font-sans); font-size: 14px; line-height: 1.55;
804
+ color: var(--text-primary); letter-spacing: -0.005em;
805
+ white-space: pre-wrap;
806
+ }
807
+ .rlm-answer-actions { margin-top: 12px; display: flex; gap: 6px; }
808
+
809
+ /* recent rail */
810
+ .rlm-recent {
811
+ border-left: 1px solid var(--line);
812
+ overflow: auto; background: var(--surface-canvas);
813
+ }
814
+ .rlm-recent .item {
815
+ padding: 12px 18px;
816
+ border-bottom: 1px solid var(--line);
817
+ cursor: pointer;
818
+ font-family: var(--font-mono);
819
+ display: flex; flex-direction: column; gap: 5px;
820
+ }
821
+ .rlm-recent .item:hover { background: var(--surface-panel); }
822
+ .rlm-recent .item .top {
823
+ display: flex; justify-content: space-between; font-size: 10px;
824
+ color: var(--text-dim); letter-spacing: 0.04em;
825
+ }
826
+ .rlm-recent .item .top .ok { color: var(--accent); }
827
+ .rlm-recent .item .top .cached { color: var(--status-info); }
828
+ .rlm-recent .item .top .asked { color: var(--status-warn); }
829
+ .rlm-recent .item .prompt {
830
+ font-family: var(--font-sans); font-size: 12px;
831
+ color: var(--text-primary); letter-spacing: -0.01em;
832
+ white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
833
+ }
834
+ .rlm-recent .item .meta { font-size: 10px; color: var(--text-dim); }
835
+ .rlm-recent .item .meta .cost { color: var(--text-secondary); }
836
+
837
+ /* ============================================================
838
+ * Ingress screen — dual auth-path diagram, funnel, live tail,
839
+ * tokens, denial breakdown, fingerprint inspector
840
+ * ============================================================ */
841
+
842
+ /* path diagram — two equal cards side-by-side at top */
843
+ .ing-paths {
844
+ display: grid;
845
+ grid-template-columns: 1fr 1fr;
846
+ gap: 12px;
847
+ margin-bottom: 18px;
848
+ }
849
+ .ing-path {
850
+ border: 1px solid var(--line);
851
+ background: var(--surface-raised);
852
+ padding: 14px 16px;
853
+ position: relative;
854
+ }
855
+ .ing-path-head {
856
+ display: flex;
857
+ align-items: baseline;
858
+ gap: 10px;
859
+ margin-bottom: 12px;
860
+ padding-bottom: 10px;
861
+ border-bottom: 1px dashed var(--line);
862
+ }
863
+ .ing-path-tag {
864
+ font-family: var(--font-mono);
865
+ font-size: 10px;
866
+ letter-spacing: 0.12em;
867
+ color: var(--text-dim);
868
+ text-transform: uppercase;
869
+ }
870
+ .ing-path-name {
871
+ font-size: 13px;
872
+ color: var(--text-primary);
873
+ font-weight: 500;
874
+ }
875
+ .ing-path-trust {
876
+ margin-left: auto;
877
+ font-family: var(--font-mono);
878
+ font-size: 10px;
879
+ letter-spacing: 0.06em;
880
+ padding: 2px 8px;
881
+ border: 1px solid var(--accent-line);
882
+ }
883
+ .ing-path-trust[data-trust="kernel"] {
884
+ color: var(--accent);
885
+ background: var(--accent-tint);
886
+ }
887
+ .ing-path-trust[data-trust="bearer"] {
888
+ color: var(--text-secondary);
889
+ border-color: var(--line);
890
+ background: var(--surface-canvas);
891
+ }
892
+ .ing-path-flow {
893
+ display: flex;
894
+ flex-wrap: wrap;
895
+ align-items: center;
896
+ gap: 6px 8px;
897
+ margin-bottom: 12px;
898
+ }
899
+ .ing-step {
900
+ font-family: var(--font-mono);
901
+ font-size: 11px;
902
+ padding: 4px 8px;
903
+ border: 1px solid var(--line);
904
+ background: var(--surface-canvas);
905
+ color: var(--text-secondary);
906
+ white-space: nowrap;
907
+ }
908
+ .ing-step-out {
909
+ border-color: var(--accent-line);
910
+ color: var(--accent);
911
+ background: var(--accent-tint);
912
+ }
913
+ .ing-arrow {
914
+ color: var(--text-dim);
915
+ font-family: var(--font-mono);
916
+ }
917
+ .ing-path-foot {
918
+ display: grid;
919
+ gap: 4px;
920
+ font-family: var(--font-mono);
921
+ font-size: 10.5px;
922
+ color: var(--text-secondary);
923
+ line-height: 1.5;
924
+ }
925
+ .ing-path-foot b {
926
+ color: var(--text-dim);
927
+ font-weight: 500;
928
+ text-transform: uppercase;
929
+ font-size: 10px;
930
+ letter-spacing: 0.06em;
931
+ margin-right: 6px;
932
+ }
933
+ .ing-path-foot code {
934
+ background: var(--surface-canvas);
935
+ padding: 1px 5px;
936
+ border: 1px solid var(--line);
937
+ font-size: 10.5px;
938
+ }
939
+
940
+ /* main grid: listeners left, funnel right */
941
+ .ing-grid {
942
+ display: grid;
943
+ grid-template-columns: 1.3fr 1fr;
944
+ gap: 18px;
945
+ }
946
+
947
+ /* listener cards */
948
+ .ing-listener {
949
+ padding: 14px 16px;
950
+ }
951
+ .ing-listener-head {
952
+ display: flex;
953
+ align-items: center;
954
+ gap: 10px;
955
+ margin-bottom: 10px;
956
+ }
957
+ .ing-proto {
958
+ font-family: var(--font-mono);
959
+ font-size: 9.5px;
960
+ letter-spacing: 0.12em;
961
+ text-transform: uppercase;
962
+ padding: 2px 7px;
963
+ border: 1px solid var(--line);
964
+ font-weight: 600;
965
+ flex-shrink: 0;
966
+ }
967
+ .ing-proto-unix {
968
+ color: var(--accent);
969
+ border-color: var(--accent-line);
970
+ background: var(--accent-tint);
971
+ }
972
+ .ing-proto-tcp {
973
+ color: var(--text-secondary);
974
+ border-color: var(--line);
975
+ background: var(--surface-canvas);
976
+ }
977
+ .ing-listener-path {
978
+ font-family: var(--font-mono);
979
+ font-size: 12px;
980
+ color: var(--text-primary);
981
+ }
982
+ .ing-listener-since {
983
+ margin-left: auto;
984
+ font-family: var(--font-mono);
985
+ font-size: 10.5px;
986
+ color: var(--text-dim);
987
+ white-space: nowrap;
988
+ flex-shrink: 0;
989
+ }
990
+ .ing-listener-body {
991
+ display: grid;
992
+ gap: 8px;
993
+ font-size: 11.5px;
994
+ }
995
+ .ing-listener-stats {
996
+ display: flex;
997
+ flex-wrap: wrap;
998
+ gap: 6px;
999
+ align-items: baseline;
1000
+ font-family: var(--font-mono);
1001
+ color: var(--text-secondary);
1002
+ }
1003
+ .ing-listener-stats b {
1004
+ color: var(--accent);
1005
+ font-weight: 600;
1006
+ }
1007
+ .ing-listener-auth {
1008
+ display: flex;
1009
+ flex-wrap: wrap;
1010
+ gap: 6px 10px;
1011
+ align-items: baseline;
1012
+ font-family: var(--font-mono);
1013
+ font-size: 10.5px;
1014
+ }
1015
+ .ing-listener-auth-label {
1016
+ color: var(--text-dim);
1017
+ text-transform: uppercase;
1018
+ font-size: 9.5px;
1019
+ letter-spacing: 0.08em;
1020
+ flex-shrink: 0;
1021
+ }
1022
+ .ing-listener-auth code {
1023
+ color: var(--text-primary);
1024
+ background: var(--surface-canvas);
1025
+ padding: 1px 6px;
1026
+ border: 1px solid var(--line);
1027
+ word-break: break-all;
1028
+ }
1029
+ .ing-listener-detail {
1030
+ font-family: var(--font-mono);
1031
+ font-size: 10.5px;
1032
+ margin-top: 2px;
1033
+ }
1034
+
1035
+ /* auth funnel — horizontal bars that taper as drops happen */
1036
+ .ing-funnel {
1037
+ display: grid;
1038
+ gap: 12px;
1039
+ }
1040
+ .ing-funnel-step {
1041
+ display: grid;
1042
+ gap: 4px;
1043
+ }
1044
+ .ing-funnel-row {
1045
+ display: grid;
1046
+ grid-template-columns: 1fr auto auto;
1047
+ gap: 10px;
1048
+ align-items: baseline;
1049
+ font-family: var(--font-mono);
1050
+ font-size: 11.5px;
1051
+ }
1052
+ .ing-funnel-label { color: var(--text-secondary); }
1053
+ .ing-funnel-kept { color: var(--text-primary); }
1054
+ .ing-funnel-drop { color: var(--text-dim); width: 50px; text-align: right; }
1055
+ .ing-funnel-drop-on { color: var(--status-error); }
1056
+ .ing-funnel-bar {
1057
+ height: 6px;
1058
+ background: var(--surface-canvas);
1059
+ border: 1px solid var(--line);
1060
+ position: relative;
1061
+ overflow: hidden;
1062
+ }
1063
+ .ing-funnel-bar-fill {
1064
+ height: 100%;
1065
+ background: var(--accent);
1066
+ opacity: 0.78;
1067
+ }
1068
+ .ing-funnel-note {
1069
+ font-family: var(--font-mono);
1070
+ font-size: 10px;
1071
+ color: var(--text-dim);
1072
+ margin-left: 2px;
1073
+ }
1074
+
1075
+ /* segmented proto filter on tail header */
1076
+ .ing-segs {
1077
+ display: inline-flex;
1078
+ border: 1px solid var(--line);
1079
+ background: var(--surface-canvas);
1080
+ }
1081
+ .ing-seg {
1082
+ font-family: var(--font-mono);
1083
+ font-size: 10px;
1084
+ letter-spacing: 0.08em;
1085
+ text-transform: uppercase;
1086
+ padding: 4px 10px;
1087
+ background: transparent;
1088
+ border: 0;
1089
+ border-right: 1px solid var(--line);
1090
+ color: var(--text-dim);
1091
+ cursor: pointer;
1092
+ }
1093
+ .ing-seg:last-child { border-right: 0; }
1094
+ .ing-seg:hover { color: var(--text-secondary); }
1095
+ .ing-seg.is-on {
1096
+ color: var(--accent);
1097
+ background: var(--accent-tint);
1098
+ }
1099
+
1100
+ /* live tail table */
1101
+ .ing-tail-header {
1102
+ display: flex;
1103
+ align-items: center;
1104
+ justify-content: space-between;
1105
+ gap: 16px;
1106
+ margin-bottom: 8px;
1107
+ }
1108
+ .ing-tail-controls {
1109
+ display: flex;
1110
+ align-items: center;
1111
+ gap: 8px;
1112
+ }
1113
+ .ing-tail {
1114
+ width: 100%;
1115
+ border-collapse: collapse;
1116
+ font-family: var(--font-mono);
1117
+ font-size: 11px;
1118
+ }
1119
+ .ing-tail thead th {
1120
+ position: sticky;
1121
+ top: 0;
1122
+ text-align: left;
1123
+ font-weight: 500;
1124
+ font-size: 9.5px;
1125
+ letter-spacing: 0.1em;
1126
+ text-transform: uppercase;
1127
+ color: var(--text-dim);
1128
+ padding: 8px 12px;
1129
+ background: var(--surface-canvas);
1130
+ border-bottom: 1px solid var(--line);
1131
+ z-index: 1;
1132
+ }
1133
+ .ing-tail tbody td {
1134
+ padding: 7px 12px;
1135
+ border-bottom: 1px solid color-mix(in oklab, var(--line) 60%, transparent);
1136
+ vertical-align: middle;
1137
+ }
1138
+ .ing-tail tbody tr.ing-tail-row { cursor: pointer; }
1139
+ .ing-tail tbody tr.ing-tail-row:hover { background: var(--accent-tint); }
1140
+ .ing-tail tbody tr.is-denied td { color: var(--status-error); }
1141
+ .ing-tail tbody tr.is-denied td.dim { color: color-mix(in oklab, var(--status-error) 60%, var(--text-dim)); }
1142
+
1143
+ .ing-evt {
1144
+ font-size: 10.5px;
1145
+ }
1146
+ .ing-evt-route { color: var(--accent); }
1147
+ .ing-evt-used { color: var(--accent); }
1148
+ .ing-evt-deny { color: var(--status-error); }
1149
+ .ing-deny-reason {
1150
+ color: var(--status-error);
1151
+ font-size: 10.5px;
1152
+ }
1153
+
1154
+ /* tokens table */
1155
+ .ing-tokens {
1156
+ width: 100%;
1157
+ border-collapse: collapse;
1158
+ font-size: 11.5px;
1159
+ }
1160
+ .ing-tokens thead th {
1161
+ text-align: left;
1162
+ font-weight: 500;
1163
+ font-size: 9.5px;
1164
+ letter-spacing: 0.1em;
1165
+ text-transform: uppercase;
1166
+ color: var(--text-dim);
1167
+ padding: 10px 12px;
1168
+ background: var(--surface-canvas);
1169
+ border-bottom: 1px solid var(--line);
1170
+ }
1171
+ .ing-tokens tbody td {
1172
+ padding: 10px 12px;
1173
+ border-bottom: 1px solid color-mix(in oklab, var(--line) 60%, transparent);
1174
+ vertical-align: middle;
1175
+ }
1176
+ .ing-tokens tbody tr:last-child td { border-bottom: 0; }
1177
+ .ing-tokens tbody tr.is-revoked td { opacity: 0.45; }
1178
+ .ing-tokens tbody tr.is-revoked td:nth-child(1),
1179
+ .ing-tokens tbody tr.is-revoked td:nth-child(2) { text-decoration: line-through; }
1180
+ .ing-tokens tbody tr.is-idle td { color: var(--text-secondary); }
1181
+ .ing-tokens .mono { font-family: var(--font-mono); }
1182
+
1183
+ /* freshly minted token block */
1184
+ .ing-mint {
1185
+ margin-top: 14px;
1186
+ border: 1px solid var(--accent-line);
1187
+ background: var(--accent-tint);
1188
+ padding: 12px 14px;
1189
+ }
1190
+ .ing-mint-head {
1191
+ display: flex;
1192
+ align-items: baseline;
1193
+ gap: 10px;
1194
+ margin-bottom: 10px;
1195
+ font-size: 11.5px;
1196
+ }
1197
+ .ing-mint-tag {
1198
+ font-family: var(--font-mono);
1199
+ font-size: 9.5px;
1200
+ letter-spacing: 0.12em;
1201
+ text-transform: uppercase;
1202
+ color: var(--accent);
1203
+ font-weight: 600;
1204
+ }
1205
+ .ing-mint-id { font-family: var(--font-mono); color: var(--text-secondary); }
1206
+ .ing-mint-id code { color: var(--text-primary); }
1207
+ .ing-mint-secret {
1208
+ display: flex;
1209
+ align-items: center;
1210
+ gap: 8px;
1211
+ background: var(--surface-canvas);
1212
+ border: 1px solid var(--line);
1213
+ padding: 8px 10px;
1214
+ margin-bottom: 8px;
1215
+ }
1216
+ .ing-mint-label {
1217
+ font-family: var(--font-mono);
1218
+ font-size: 9.5px;
1219
+ letter-spacing: 0.1em;
1220
+ text-transform: uppercase;
1221
+ color: var(--text-dim);
1222
+ }
1223
+ .ing-mint-value {
1224
+ flex: 1;
1225
+ font-family: var(--font-mono);
1226
+ font-size: 11px;
1227
+ color: var(--text-primary);
1228
+ overflow: hidden;
1229
+ text-overflow: ellipsis;
1230
+ white-space: nowrap;
1231
+ letter-spacing: 0.04em;
1232
+ }
1233
+ .ing-mint-value.is-masked {
1234
+ color: var(--text-dim);
1235
+ letter-spacing: 0.06em;
1236
+ }
1237
+ .ing-mint-foot {
1238
+ font-size: 10.5px;
1239
+ font-family: var(--font-mono);
1240
+ }
1241
+ .ing-mint-foot code {
1242
+ background: var(--surface-canvas);
1243
+ padding: 1px 5px;
1244
+ border: 1px solid var(--line);
1245
+ }
1246
+
1247
+ /* denial breakdown */
1248
+ .ing-deny {
1249
+ margin-bottom: 14px;
1250
+ }
1251
+ .ing-deny:last-of-type { margin-bottom: 8px; }
1252
+ .ing-deny-head {
1253
+ display: flex;
1254
+ justify-content: space-between;
1255
+ align-items: baseline;
1256
+ margin-bottom: 4px;
1257
+ }
1258
+ .ing-deny-code {
1259
+ font-size: 11px;
1260
+ color: var(--status-error);
1261
+ font-family: var(--font-mono);
1262
+ }
1263
+ .ing-deny-count {
1264
+ font-family: var(--font-mono);
1265
+ font-size: 11px;
1266
+ color: var(--text-secondary);
1267
+ }
1268
+ .ing-deny-bar {
1269
+ height: 4px;
1270
+ background: var(--surface-canvas);
1271
+ border: 1px solid var(--line);
1272
+ overflow: hidden;
1273
+ }
1274
+ .ing-deny-bar-fill {
1275
+ height: 100%;
1276
+ background: var(--status-error);
1277
+ opacity: 0.7;
1278
+ }
1279
+ .ing-deny-hint {
1280
+ font-family: var(--font-mono);
1281
+ font-size: 10px;
1282
+ margin-top: 4px;
1283
+ }
1284
+ .ing-deny-foot {
1285
+ margin-top: 12px;
1286
+ padding-top: 10px;
1287
+ border-top: 1px dashed var(--line);
1288
+ font-family: var(--font-mono);
1289
+ font-size: 10.5px;
1290
+ line-height: 1.55;
1291
+ }
1292
+ .ing-deny-foot code {
1293
+ background: var(--surface-canvas);
1294
+ padding: 1px 5px;
1295
+ border: 1px solid var(--line);
1296
+ }
1297
+
1298
+ /* fingerprint inspector */
1299
+ .ing-fp { display: grid; gap: 6px; }
1300
+ .ing-fp-row {
1301
+ display: grid;
1302
+ grid-template-columns: 90px 1fr;
1303
+ gap: 10px;
1304
+ align-items: baseline;
1305
+ font-size: 11px;
1306
+ }
1307
+ .ing-fp-key {
1308
+ font-family: var(--font-mono);
1309
+ font-size: 9.5px;
1310
+ letter-spacing: 0.1em;
1311
+ text-transform: uppercase;
1312
+ color: var(--text-dim);
1313
+ }
1314
+ .ing-fp-val {
1315
+ font-family: var(--font-mono);
1316
+ font-size: 11px;
1317
+ color: var(--text-primary);
1318
+ word-break: break-all;
1319
+ }
1320
+ .ing-fp-out { color: var(--accent); }
1321
+ .ing-fp-mono { letter-spacing: 0.06em; }
1322
+ .ing-fp-sample .ing-fp-val {
1323
+ color: var(--text-secondary);
1324
+ font-size: 10.5px;
1325
+ }
1326
+ .ing-fp-divider {
1327
+ height: 0;
1328
+ border-top: 1px dashed var(--line);
1329
+ margin: 8px 0 4px;
1330
+ }
1331
+
1332
+
1333
+ /* ============================================================
1334
+ * Health screen — htop-style live monitor
1335
+ * ============================================================ */
1336
+
1337
+ /* hero metric row — three breathing cards */
1338
+ .h-hero-row {
1339
+ display: grid;
1340
+ grid-template-columns: repeat(3, 1fr);
1341
+ gap: 12px;
1342
+ }
1343
+ .h-hero {
1344
+ background: var(--surface-panel);
1345
+ border: 1px solid var(--line);
1346
+ padding: 14px 16px 8px;
1347
+ display: flex; flex-direction: column; gap: 6px;
1348
+ position: relative;
1349
+ }
1350
+ .h-hero-head {
1351
+ display: flex; align-items: baseline; justify-content: space-between;
1352
+ font-family: var(--font-mono); font-size: 10px;
1353
+ text-transform: uppercase; letter-spacing: 0.12em;
1354
+ color: var(--text-dim);
1355
+ }
1356
+ .h-hero-label { color: var(--text-secondary); }
1357
+ .h-hero-delta { color: var(--text-dim); font-size: 10px; }
1358
+ .h-hero-value {
1359
+ display: flex; align-items: baseline; gap: 4px;
1360
+ font-family: var(--font-mono); color: var(--text-primary);
1361
+ margin: 2px 0 4px;
1362
+ }
1363
+ .h-hero-value .num {
1364
+ font-size: 38px; font-weight: 300; letter-spacing: -0.02em;
1365
+ font-variant-numeric: tabular-nums;
1366
+ color: var(--accent);
1367
+ text-shadow: 0 0 18px color-mix(in oklab, var(--accent) calc(var(--phosphor-glow, 0) * 60%), transparent);
1368
+ }
1369
+ .h-hero-value .unit { font-size: 12px; color: var(--text-dim); margin-left: 2px; }
1370
+
1371
+ /* generic grid layouts */
1372
+ .h-grid { display: grid; gap: 18px; }
1373
+ .h-2col { grid-template-columns: 2fr 1fr; }
1374
+ .h-3col { grid-template-columns: 1.2fr 1.4fr 1fr; }
1375
+
1376
+ /* connection pool */
1377
+ .h-pool { padding: 14px 16px; }
1378
+ .h-pool-stats {
1379
+ display: grid; grid-template-columns: repeat(4, 1fr);
1380
+ gap: 16px; margin-bottom: 14px;
1381
+ }
1382
+ .h-pool-stats .lbl {
1383
+ font-family: var(--font-mono); font-size: 10px;
1384
+ color: var(--text-dim); text-transform: uppercase; letter-spacing: 0.1em;
1385
+ }
1386
+ .h-pool-stats .num {
1387
+ font-family: var(--font-mono); font-size: 22px; font-weight: 300;
1388
+ font-variant-numeric: tabular-nums; color: var(--text-primary);
1389
+ }
1390
+ .h-pool-stats .num.accent { color: var(--accent); }
1391
+
1392
+ .h-pool-bar {
1393
+ display: grid; grid-template-columns: repeat(50, 1fr);
1394
+ gap: 2px; height: 22px; margin-bottom: 10px;
1395
+ }
1396
+ .h-pool-cell {
1397
+ background: var(--surface-canvas); border: 1px solid var(--line);
1398
+ border-radius: 1px;
1399
+ }
1400
+ .h-pool-cell.a {
1401
+ background: var(--accent);
1402
+ box-shadow: 0 0 6px color-mix(in oklab, var(--accent) calc(var(--phosphor-glow, 0) * 80%), transparent);
1403
+ }
1404
+ .h-pool-cell.i { background: color-mix(in oklab, var(--accent) 28%, var(--surface-canvas)); border-color: color-mix(in oklab, var(--accent) 40%, var(--line)); }
1405
+
1406
+ .h-pool-legend {
1407
+ display: flex; gap: 18px;
1408
+ font-family: var(--font-mono); font-size: 10px;
1409
+ color: var(--text-dim); text-transform: uppercase; letter-spacing: 0.08em;
1410
+ }
1411
+ .h-pool-legend .dot {
1412
+ display: inline-block; width: 8px; height: 8px;
1413
+ background: var(--surface-canvas); border: 1px solid var(--line);
1414
+ margin-right: 6px; vertical-align: middle;
1415
+ }
1416
+ .h-pool-legend .dot.a { background: var(--accent); border-color: var(--accent); }
1417
+ .h-pool-legend .dot.i { background: color-mix(in oklab, var(--accent) 28%, var(--surface-canvas)); border-color: color-mix(in oklab, var(--accent) 40%, var(--line)); }
1418
+
1419
+ /* server facts */
1420
+ .h-facts {
1421
+ display: grid; grid-template-columns: 1fr 1fr;
1422
+ gap: 8px 24px; padding: 14px 16px;
1423
+ font-family: var(--font-mono); font-size: 12px;
1424
+ }
1425
+ .h-facts > div { display: flex; justify-content: space-between; padding: 4px 0; border-bottom: 1px dashed var(--line); }
1426
+ .h-facts .k { color: var(--text-dim); text-transform: uppercase; letter-spacing: 0.06em; font-size: 10px; }
1427
+ .h-facts .v { color: var(--text-primary); font-variant-numeric: tabular-nums; }
1428
+ .h-facts .v.accent { color: var(--accent); }
1429
+ .h-facts .v.warn { color: var(--status-warn); }
1430
+
1431
+ /* backend waterfall */
1432
+ .h-waterfall { padding: 6px 0; }
1433
+ .h-wf-row {
1434
+ display: grid;
1435
+ grid-template-columns: 56px 100px 64px 1fr 60px 140px;
1436
+ align-items: center; gap: 10px;
1437
+ padding: 6px 16px;
1438
+ border-bottom: 1px solid color-mix(in oklab, var(--line) 60%, transparent);
1439
+ font-family: var(--font-mono); font-size: 11px;
1440
+ }
1441
+ .h-wf-row:last-child { border-bottom: none; }
1442
+ .h-wf-pid { color: var(--text-dim); }
1443
+ .h-wf-db { color: var(--text-secondary); }
1444
+ .h-wf-state .h-state {
1445
+ font-size: 9px; padding: 1px 6px;
1446
+ text-transform: uppercase; letter-spacing: 0.08em;
1447
+ border: 1px solid var(--line); display: inline-block;
1448
+ }
1449
+ .h-state-active { color: var(--accent); border-color: var(--accent); }
1450
+ .h-state-idle { color: var(--text-dim); }
1451
+ .h-state-waiting { color: var(--status-warn); border-color: var(--status-warn); }
1452
+
1453
+ .h-wf-track {
1454
+ height: 18px;
1455
+ background: color-mix(in oklab, var(--surface-canvas) 60%, transparent);
1456
+ border: 1px solid var(--line);
1457
+ position: relative; overflow: hidden;
1458
+ }
1459
+ .h-wf-bar {
1460
+ height: 100%;
1461
+ background: color-mix(in oklab, var(--accent) 22%, var(--surface-canvas));
1462
+ border-right: 1px solid var(--accent);
1463
+ display: flex; align-items: center;
1464
+ padding: 0 8px;
1465
+ transition: width 0.6s ease;
1466
+ position: relative;
1467
+ overflow: hidden;
1468
+ }
1469
+ .h-wf-bar::after {
1470
+ content: ''; position: absolute; right: 0; top: 0; bottom: 0;
1471
+ width: 2px; background: var(--accent);
1472
+ box-shadow: 0 0 8px color-mix(in oklab, var(--accent) calc(var(--phosphor-glow, 0) * 100%), transparent);
1473
+ }
1474
+ .h-wf-bar.is-waiting {
1475
+ background: color-mix(in oklab, var(--status-warn) 18%, var(--surface-canvas));
1476
+ border-right-color: var(--status-warn);
1477
+ }
1478
+ .h-wf-bar.is-waiting::after { background: var(--status-warn); }
1479
+ .h-wf-bar.is-idle {
1480
+ background: color-mix(in oklab, var(--text-dim) 10%, var(--surface-canvas));
1481
+ border-right-color: var(--text-dim);
1482
+ }
1483
+ .h-wf-bar.is-idle::after { background: var(--text-dim); box-shadow: none; }
1484
+ .h-wf-q {
1485
+ font-size: 10px; color: var(--text-secondary);
1486
+ white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
1487
+ font-family: var(--font-mono);
1488
+ }
1489
+ .h-wf-dur { color: var(--text-primary); text-align: right; font-variant-numeric: tabular-nums; }
1490
+ .h-wf-wait { color: var(--status-warn); font-size: 10px; }
1491
+
1492
+ /* lock waterfall */
1493
+ .h-locks { padding: 8px 0; }
1494
+ .h-lock-row {
1495
+ display: grid;
1496
+ grid-template-columns: 1fr 100px 60px;
1497
+ align-items: center; gap: 10px;
1498
+ padding: 8px 16px;
1499
+ border-bottom: 1px solid color-mix(in oklab, var(--line) 60%, transparent);
1500
+ font-family: var(--font-mono); font-size: 11px;
1501
+ position: relative;
1502
+ }
1503
+ .h-lock-row:last-child { border-bottom: none; }
1504
+ .h-lock-row.is-blocking { background: color-mix(in oklab, var(--status-error) 8%, transparent); }
1505
+ .h-lock-row.is-blocked { background: color-mix(in oklab, var(--status-warn) 6%, transparent); }
1506
+ .h-lock-meta { display: flex; gap: 8px; min-width: 0; }
1507
+ .h-lock-meta .pid { color: var(--text-dim); }
1508
+ .h-lock-meta .rel { color: var(--text-primary); }
1509
+ .h-lock-meta .mode {
1510
+ color: var(--text-secondary); font-size: 10px;
1511
+ margin-left: auto; padding: 1px 4px;
1512
+ border: 1px solid var(--line);
1513
+ }
1514
+ .h-lock-track {
1515
+ height: 8px;
1516
+ background: var(--surface-canvas); border: 1px solid var(--line);
1517
+ }
1518
+ .h-lock-bar {
1519
+ height: 100%;
1520
+ background: color-mix(in oklab, var(--accent) 30%, var(--surface-canvas));
1521
+ border-right: 1px solid var(--accent);
1522
+ transition: width 0.6s ease;
1523
+ }
1524
+ .h-lock-row.is-blocking .h-lock-bar { background: color-mix(in oklab, var(--status-error) 30%, var(--surface-canvas)); border-right-color: var(--status-error); }
1525
+ .h-lock-dur { color: var(--text-primary); text-align: right; font-variant-numeric: tabular-nums; }
1526
+ .h-lock-blocked, .h-lock-wait {
1527
+ grid-column: 1 / -1;
1528
+ font-size: 10px; color: var(--text-dim);
1529
+ padding-left: 12px; margin-top: 2px;
1530
+ border-left: 1px solid var(--status-warn);
1531
+ }
1532
+ .h-lock-blocked { color: var(--status-warn); }
1533
+
1534
+ /* vacuum lane */
1535
+ .h-vlane { padding: 12px 16px; position: relative; }
1536
+ .h-vlane-axis {
1537
+ display: flex; justify-content: space-between;
1538
+ font-family: var(--font-mono); font-size: 9px;
1539
+ color: var(--text-dim); text-transform: uppercase; letter-spacing: 0.08em;
1540
+ margin-bottom: 6px;
1541
+ }
1542
+ .h-vlane-track {
1543
+ position: relative; height: 78px;
1544
+ background: repeating-linear-gradient(
1545
+ 90deg,
1546
+ transparent 0,
1547
+ transparent calc(25% - 1px),
1548
+ color-mix(in oklab, var(--line) 80%, transparent) calc(25% - 1px),
1549
+ color-mix(in oklab, var(--line) 80%, transparent) 25%
1550
+ );
1551
+ border: 1px solid var(--line);
1552
+ background-color: var(--surface-canvas);
1553
+ }
1554
+ .h-vlane-block {
1555
+ position: absolute; height: 18px;
1556
+ padding: 0 6px;
1557
+ font-family: var(--font-mono); font-size: 9px;
1558
+ color: var(--text-primary);
1559
+ display: flex; align-items: center;
1560
+ border: 1px solid;
1561
+ white-space: nowrap; overflow: hidden;
1562
+ }
1563
+ .h-vlane-block.auto {
1564
+ background: color-mix(in oklab, var(--accent) 20%, var(--surface-panel));
1565
+ border-color: color-mix(in oklab, var(--accent) 50%, var(--line));
1566
+ }
1567
+ .h-vlane-block.analyze {
1568
+ background: color-mix(in oklab, var(--status-vector) 20%, var(--surface-panel));
1569
+ border-color: color-mix(in oklab, var(--status-vector) 50%, var(--line));
1570
+ }
1571
+ .h-vlane-block.is-running {
1572
+ border-color: var(--accent);
1573
+ box-shadow: 0 0 0 1px var(--accent), 0 0 10px color-mix(in oklab, var(--accent) calc(var(--phosphor-glow, 0) * 100%), transparent);
1574
+ animation: h-vlane-pulse 1.6s ease-in-out infinite;
1575
+ }
1576
+ @keyframes h-vlane-pulse {
1577
+ 0%,100% { background: color-mix(in oklab, var(--accent) 20%, var(--surface-panel)); }
1578
+ 50% { background: color-mix(in oklab, var(--accent) 38%, var(--surface-panel)); }
1579
+ }
1580
+ .h-vlane-block .lbl { overflow: hidden; text-overflow: ellipsis; }
1581
+ .h-vlane-legend {
1582
+ display: flex; gap: 14px; margin-top: 8px;
1583
+ font-family: var(--font-mono); font-size: 10px;
1584
+ color: var(--text-dim); text-transform: uppercase; letter-spacing: 0.08em;
1585
+ }
1586
+ .h-vlane-legend .sw {
1587
+ display: inline-block; width: 10px; height: 10px;
1588
+ margin-right: 4px; vertical-align: middle;
1589
+ border: 1px solid;
1590
+ }
1591
+ .h-vlane-legend .sw.auto { background: color-mix(in oklab, var(--accent) 20%, var(--surface-panel)); border-color: color-mix(in oklab, var(--accent) 50%, var(--line)); }
1592
+ .h-vlane-legend .sw.analyze { background: color-mix(in oklab, var(--status-vector) 20%, var(--surface-panel)); border-color: color-mix(in oklab, var(--status-vector) 50%, var(--line)); }
1593
+ .h-vlane-legend .sw.running { background: var(--accent); border-color: var(--accent); }
1594
+
1595
+ /* recall histogram */
1596
+ .h-recall { padding: 12px 16px; display: flex; flex-direction: column; gap: 12px; }
1597
+ .h-recall-bars {
1598
+ display: grid; grid-template-columns: repeat(7, 1fr);
1599
+ gap: 6px; height: 130px; align-items: end;
1600
+ }
1601
+ .h-recall-col { display: flex; flex-direction: column; align-items: center; gap: 4px; height: 100%; }
1602
+ .h-recall-bar-wrap {
1603
+ flex: 1; width: 100%;
1604
+ display: flex; flex-direction: column; justify-content: flex-end;
1605
+ position: relative;
1606
+ }
1607
+ .h-recall-bar {
1608
+ width: 100%;
1609
+ background: var(--accent);
1610
+ border-top: 2px solid var(--accent);
1611
+ box-shadow: 0 0 8px color-mix(in oklab, var(--accent) calc(var(--phosphor-glow, 0) * 60%), transparent) inset;
1612
+ transition: height 0.6s ease;
1613
+ min-height: 2px;
1614
+ }
1615
+ .h-recall-bar.is-low { background: color-mix(in oklab, var(--status-error) 80%, transparent); border-top-color: var(--status-error); }
1616
+ .h-recall-bar.is-mid { background: color-mix(in oklab, var(--status-warn) 80%, transparent); border-top-color: var(--status-warn); }
1617
+ .h-recall-count {
1618
+ position: absolute; top: -16px; left: 50%; transform: translateX(-50%);
1619
+ font-family: var(--font-mono); font-size: 10px;
1620
+ color: var(--text-primary);
1621
+ font-variant-numeric: tabular-nums;
1622
+ }
1623
+ .h-recall-bucket {
1624
+ font-family: var(--font-mono); font-size: 9px;
1625
+ color: var(--text-dim); letter-spacing: 0.04em;
1626
+ }
1627
+ .h-recall-foot {
1628
+ display: grid; grid-template-columns: 1fr 1fr 1fr;
1629
+ gap: 8px; padding-top: 10px;
1630
+ border-top: 1px solid var(--line);
1631
+ font-family: var(--font-mono); font-size: 11px;
1632
+ }
1633
+ .h-recall-foot > div { display: flex; flex-direction: column; gap: 2px; }
1634
+ .h-recall-foot .k { color: var(--text-dim); font-size: 9px; text-transform: uppercase; letter-spacing: 0.08em; }
1635
+ .h-recall-foot .v { color: var(--text-primary); font-variant-numeric: tabular-nums; }
1636
+ .h-recall-foot .v.accent { color: var(--accent); }
1637
+
1638
+ /* footer strip — pg internals */
1639
+ .h-strip {
1640
+ display: grid; grid-template-columns: repeat(6, 1fr);
1641
+ gap: 1px;
1642
+ background: var(--line);
1643
+ border: 1px solid var(--line);
1644
+ }
1645
+ .h-strip > div {
1646
+ background: var(--surface-panel);
1647
+ padding: 12px 14px;
1648
+ display: flex; flex-direction: column; gap: 4px;
1649
+ font-family: var(--font-mono);
1650
+ }
1651
+ .h-strip .k { font-size: 9px; color: var(--text-dim); text-transform: uppercase; letter-spacing: 0.1em; }
1652
+ .h-strip .v { font-size: 14px; color: var(--text-primary); font-variant-numeric: tabular-nums; }
1653
+ .h-strip .v.accent { color: var(--accent); }
1654
+ .h-strip .v.err { color: var(--status-error); }
1655
+
1656
+ /* responsive collapse */
1657
+ @media (max-width: 1280px) {
1658
+ .h-3col { grid-template-columns: 1fr 1fr; }
1659
+ .h-3col > div:last-child { grid-column: 1 / -1; }
1660
+ .h-recall-bars { height: 100px; }
1661
+ }
1662
+ @media (max-width: 980px) {
1663
+ .h-hero-row { grid-template-columns: 1fr; }
1664
+ .h-2col, .h-3col { grid-template-columns: 1fr; }
1665
+ .h-strip { grid-template-columns: repeat(2, 1fr); }
1666
+ }