aimeat 1.16.2 → 1.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (281) hide show
  1. package/dist/.env.example +6 -1
  2. package/dist/locales/en.json +166 -4
  3. package/dist/locales/fi.json +166 -4
  4. package/dist/public/components/Card.js +17 -3
  5. package/dist/public/components/Collapsible.js +39 -0
  6. package/dist/public/components/CopyButton.js +55 -24
  7. package/dist/public/components/DataTable.js +57 -0
  8. package/dist/public/components/EmptyState.js +28 -0
  9. package/dist/public/components/KeyValueRow.js +37 -0
  10. package/dist/public/components/Modal.js +22 -5
  11. package/dist/public/components/Pagination.js +70 -0
  12. package/dist/public/components/SearchBar.js +44 -0
  13. package/dist/public/components/StatusDot.js +29 -0
  14. package/dist/public/components/TagList.js +53 -0
  15. package/dist/public/components/ToggleSwitch.js +28 -0
  16. package/dist/public/components/index.js +41 -1
  17. package/dist/public/css/components/tags.css +24 -0
  18. package/dist/public/css/style-testbed.css +135 -0
  19. package/dist/public/css/theme.css +556 -34
  20. package/dist/public/css/views/admin-agent-integration.css +2 -33
  21. package/dist/public/css/views/admin.css +730 -686
  22. package/dist/public/css/views/agents-detail.css +402 -14
  23. package/dist/public/css/views/help.css +2 -1
  24. package/dist/public/css/views/hobbies.css +53 -33
  25. package/dist/public/css/views/marketplace.css +73 -60
  26. package/dist/public/css/views/openclaw.css +12 -6
  27. package/dist/public/css/views/portal-classic.css +34 -26
  28. package/dist/public/css/views/portal-dev.css +41 -32
  29. package/dist/public/css/views/portal.css +14 -18
  30. package/dist/public/css/views/profile.css +252 -164
  31. package/dist/public/css/views/public-knowledge-viewer.css +18 -6
  32. package/dist/public/css/views/scheduler.css +100 -0
  33. package/dist/public/js/format.js +41 -0
  34. package/dist/public/js/services/agent-tasks.js +14 -1
  35. package/dist/public/js/services/generator-spec-validate.js +5 -1
  36. package/dist/public/js/services/schedules.js +53 -0
  37. package/dist/public/js/style-testbed.js +170 -0
  38. package/dist/public/js/theme.js +114 -0
  39. package/dist/public/spa.html +74 -16
  40. package/dist/public/style-testbed.html +420 -0
  41. package/dist/public/views/admin/agent-integration-tab.js +23 -38
  42. package/dist/public/views/admin/agent-tasks-tab.js +14 -21
  43. package/dist/public/views/admin/chat-instances-tab.js +1 -1
  44. package/dist/public/views/admin/config-tab.js +7 -2
  45. package/dist/public/views/admin/cortex-tab.js +20 -14
  46. package/dist/public/views/admin/csm-tab.js +22 -18
  47. package/dist/public/views/admin/directory-tab.js +3 -3
  48. package/dist/public/views/admin/email-tab.js +23 -28
  49. package/dist/public/views/admin/federation-tab.js +15 -5
  50. package/dist/public/views/admin/generator-debug-tab.js +10 -8
  51. package/dist/public/views/admin/genesis-tab.js +4 -4
  52. package/dist/public/views/admin/ghii-tab.js +3 -3
  53. package/dist/public/views/admin/knowledge-tab.js +15 -5
  54. package/dist/public/views/admin/matching-tab.js +3 -3
  55. package/dist/public/views/admin/memory-tab.js +16 -20
  56. package/dist/public/views/admin/msm-tab.js +30 -17
  57. package/dist/public/views/admin/overview-tab.js +7 -7
  58. package/dist/public/views/admin/packages-tab.js +10 -9
  59. package/dist/public/views/admin/portal-tab.js +14 -4
  60. package/dist/public/views/admin/prompts-tab.js +5 -5
  61. package/dist/public/views/admin/push-tab.js +15 -4
  62. package/dist/public/views/admin/realtime-tab.js +3 -3
  63. package/dist/public/views/admin/services-tab.js +18 -27
  64. package/dist/public/views/admin/shared.js +48 -58
  65. package/dist/public/views/admin/sharing-groups-tab.js +5 -10
  66. package/dist/public/views/admin/stats-tab.js +3 -3
  67. package/dist/public/views/guides.js +9 -13
  68. package/dist/public/views/help.js +3 -24
  69. package/dist/public/views/hobbies.js +47 -41
  70. package/dist/public/views/marketplace.js +42 -34
  71. package/dist/public/views/openclaw.js +0 -1
  72. package/dist/public/views/portal-classic.js +4 -15
  73. package/dist/public/views/portal-dev.js +28 -30
  74. package/dist/public/views/portal.js +16 -21
  75. package/dist/public/views/portfolio.js +11 -12
  76. package/dist/public/views/profile/access-tab.js +250 -1
  77. package/dist/public/views/profile/agents/agent-card.js +75 -4
  78. package/dist/public/views/profile/agents/tab-activity.js +15 -13
  79. package/dist/public/views/profile/agents/tab-agent-config.js +60 -6
  80. package/dist/public/views/profile/agents/tab-integration.js +37 -60
  81. package/dist/public/views/profile/agents/tab-messages.js +10 -1
  82. package/dist/public/views/profile/agents/tab-quality.js +25 -19
  83. package/dist/public/views/profile/agents/tab-schedules.js +110 -0
  84. package/dist/public/views/profile/agents-activity-subtab.js +4 -4
  85. package/dist/public/views/profile/agents-services-subtab.js +5 -4
  86. package/dist/public/views/profile/agents-tab.js +141 -37
  87. package/dist/public/views/profile/agents-tasks-subtab.js +221 -26
  88. package/dist/public/views/profile/calibrator-batch.js +5 -11
  89. package/dist/public/views/profile/calibrator-tab.js +4 -9
  90. package/dist/public/views/profile/chat-sessions-tab.js +9 -5
  91. package/dist/public/views/profile/email-tab.js +2 -2
  92. package/dist/public/views/profile/extensions-tab.js +27 -22
  93. package/dist/public/views/profile/federation-tab.js +4 -1
  94. package/dist/public/views/profile/foundry-detail.js +22 -23
  95. package/dist/public/views/profile/foundry-tab.js +12 -13
  96. package/dist/public/views/profile/generator-dashboard/DebugPanel.js +4 -7
  97. package/dist/public/views/profile/generator-dashboard/use-dashboard-core.js +4 -1
  98. package/dist/public/views/profile/generator-dashboard/use-edit-mode.js +3 -2
  99. package/dist/public/views/profile/generator-detail.js +26 -30
  100. package/dist/public/views/profile/generator-tab.js +5 -5
  101. package/dist/public/views/profile/knowledge-tab.js +12 -12
  102. package/dist/public/views/profile/landing-page.js +100 -149
  103. package/dist/public/views/profile/memory-tab.js +15 -11
  104. package/dist/public/views/profile/node-stats-tab.js +3 -3
  105. package/dist/public/views/profile/nodes-tab.js +10 -3
  106. package/dist/public/views/profile/notifications-tab.js +3 -3
  107. package/dist/public/views/profile/packages-tab.js +14 -14
  108. package/dist/public/views/profile/scheduler-tab.js +340 -0
  109. package/dist/public/views/profile/services-tab.js +1 -1
  110. package/dist/public/views/profile/shared.js +16 -12
  111. package/dist/public/views/profile/wallet-tab.js +27 -50
  112. package/dist/public/views/profile/work-tab.js +29 -31
  113. package/dist/public/views/profile.js +24 -0
  114. package/dist/public/views/public-knowledge-viewer.js +9 -18
  115. package/dist/src/auth/middleware.d.ts +3 -2
  116. package/dist/src/auth/middleware.d.ts.map +1 -1
  117. package/dist/src/auth/middleware.js +78 -3
  118. package/dist/src/auth/middleware.js.map +1 -1
  119. package/dist/src/cli/init-wizard.d.ts.map +1 -1
  120. package/dist/src/cli/init-wizard.js +13 -1
  121. package/dist/src/cli/init-wizard.js.map +1 -1
  122. package/dist/src/config.d.ts +6 -0
  123. package/dist/src/config.d.ts.map +1 -1
  124. package/dist/src/config.js +12 -1
  125. package/dist/src/config.js.map +1 -1
  126. package/dist/src/generated/api-types.d.ts +708 -8
  127. package/dist/src/generated/api-types.d.ts.map +1 -1
  128. package/dist/src/mcp/agent-schedules.d.ts +23 -0
  129. package/dist/src/mcp/agent-schedules.d.ts.map +1 -0
  130. package/dist/src/mcp/agent-schedules.js +175 -0
  131. package/dist/src/mcp/agent-schedules.js.map +1 -0
  132. package/dist/src/mcp/annotations.d.ts.map +1 -1
  133. package/dist/src/mcp/annotations.js +6 -0
  134. package/dist/src/mcp/annotations.js.map +1 -1
  135. package/dist/src/mcp/catalog/definitions.d.ts.map +1 -1
  136. package/dist/src/mcp/catalog/definitions.js +55 -0
  137. package/dist/src/mcp/catalog/definitions.js.map +1 -1
  138. package/dist/src/mcp/catalog/scopes.d.ts.map +1 -1
  139. package/dist/src/mcp/catalog/scopes.js +12 -0
  140. package/dist/src/mcp/catalog/scopes.js.map +1 -1
  141. package/dist/src/mcp/catalog/surfaces.d.ts.map +1 -1
  142. package/dist/src/mcp/catalog/surfaces.js +2 -0
  143. package/dist/src/mcp/catalog/surfaces.js.map +1 -1
  144. package/dist/src/mcp/index.d.ts.map +1 -1
  145. package/dist/src/mcp/index.js +2 -0
  146. package/dist/src/mcp/index.js.map +1 -1
  147. package/dist/src/models/agent-task-schemas.d.ts +6 -0
  148. package/dist/src/models/agent-task-schemas.d.ts.map +1 -1
  149. package/dist/src/models/agent-task-schemas.js +6 -0
  150. package/dist/src/models/agent-task-schemas.js.map +1 -1
  151. package/dist/src/models/schemas.d.ts +1 -0
  152. package/dist/src/models/schemas.d.ts.map +1 -1
  153. package/dist/src/models/schemas.js +4 -0
  154. package/dist/src/models/schemas.js.map +1 -1
  155. package/dist/src/routes/access-tokens.d.ts +17 -0
  156. package/dist/src/routes/access-tokens.d.ts.map +1 -0
  157. package/dist/src/routes/access-tokens.js +164 -0
  158. package/dist/src/routes/access-tokens.js.map +1 -0
  159. package/dist/src/routes/agent-tasks.d.ts +2 -0
  160. package/dist/src/routes/agent-tasks.d.ts.map +1 -1
  161. package/dist/src/routes/agent-tasks.js +118 -23
  162. package/dist/src/routes/agent-tasks.js.map +1 -1
  163. package/dist/src/routes/agents.d.ts.map +1 -1
  164. package/dist/src/routes/agents.js +46 -0
  165. package/dist/src/routes/agents.js.map +1 -1
  166. package/dist/src/routes/ai.d.ts +6 -9
  167. package/dist/src/routes/ai.d.ts.map +1 -1
  168. package/dist/src/routes/ai.js +26 -175
  169. package/dist/src/routes/ai.js.map +1 -1
  170. package/dist/src/routes/apps.d.ts.map +1 -1
  171. package/dist/src/routes/apps.js +104 -34
  172. package/dist/src/routes/apps.js.map +1 -1
  173. package/dist/src/routes/auth.d.ts.map +1 -1
  174. package/dist/src/routes/auth.js +77 -4
  175. package/dist/src/routes/auth.js.map +1 -1
  176. package/dist/src/routes/cortex.d.ts +2 -1
  177. package/dist/src/routes/cortex.d.ts.map +1 -1
  178. package/dist/src/routes/cortex.js +13 -8
  179. package/dist/src/routes/cortex.js.map +1 -1
  180. package/dist/src/routes/extensions.d.ts.map +1 -1
  181. package/dist/src/routes/extensions.js +85 -51
  182. package/dist/src/routes/extensions.js.map +1 -1
  183. package/dist/src/routes/generator.d.ts.map +1 -1
  184. package/dist/src/routes/generator.js +109 -43
  185. package/dist/src/routes/generator.js.map +1 -1
  186. package/dist/src/routes/ghii.d.ts.map +1 -1
  187. package/dist/src/routes/ghii.js +34 -13
  188. package/dist/src/routes/ghii.js.map +1 -1
  189. package/dist/src/routes/libs.d.ts +15 -0
  190. package/dist/src/routes/libs.d.ts.map +1 -1
  191. package/dist/src/routes/libs.js +178 -55
  192. package/dist/src/routes/libs.js.map +1 -1
  193. package/dist/src/routes/portal.d.ts.map +1 -1
  194. package/dist/src/routes/portal.js +1 -0
  195. package/dist/src/routes/portal.js.map +1 -1
  196. package/dist/src/routes/schedules.d.ts +33 -0
  197. package/dist/src/routes/schedules.d.ts.map +1 -0
  198. package/dist/src/routes/schedules.js +380 -0
  199. package/dist/src/routes/schedules.js.map +1 -0
  200. package/dist/src/server-bootstrap/config-init.js +2 -2
  201. package/dist/src/server-bootstrap/config-init.js.map +1 -1
  202. package/dist/src/server-bootstrap/routes-loader.d.ts.map +1 -1
  203. package/dist/src/server-bootstrap/routes-loader.js +7 -0
  204. package/dist/src/server-bootstrap/routes-loader.js.map +1 -1
  205. package/dist/src/server-bootstrap/service-init.d.ts.map +1 -1
  206. package/dist/src/server-bootstrap/service-init.js +2 -1
  207. package/dist/src/server-bootstrap/service-init.js.map +1 -1
  208. package/dist/src/services/access-token.d.ts +28 -0
  209. package/dist/src/services/access-token.d.ts.map +1 -0
  210. package/dist/src/services/access-token.js +37 -0
  211. package/dist/src/services/access-token.js.map +1 -0
  212. package/dist/src/services/ai-completion.d.ts +83 -0
  213. package/dist/src/services/ai-completion.d.ts.map +1 -0
  214. package/dist/src/services/ai-completion.js +187 -0
  215. package/dist/src/services/ai-completion.js.map +1 -0
  216. package/dist/src/services/config-schema.d.ts.map +1 -1
  217. package/dist/src/services/config-schema.js +3 -0
  218. package/dist/src/services/config-schema.js.map +1 -1
  219. package/dist/src/services/generator-prompt-seeds.d.ts.map +1 -1
  220. package/dist/src/services/generator-prompt-seeds.js +6 -3
  221. package/dist/src/services/generator-prompt-seeds.js.map +1 -1
  222. package/dist/src/services/generator-prompts/spec-validate.d.ts.map +1 -1
  223. package/dist/src/services/generator-prompts/spec-validate.js +6 -2
  224. package/dist/src/services/generator-prompts/spec-validate.js.map +1 -1
  225. package/dist/src/services/generator-registration.d.ts +12 -4
  226. package/dist/src/services/generator-registration.d.ts.map +1 -1
  227. package/dist/src/services/generator-registration.js +71 -0
  228. package/dist/src/services/generator-registration.js.map +1 -1
  229. package/dist/src/services/generator-validate.d.ts +10 -0
  230. package/dist/src/services/generator-validate.d.ts.map +1 -1
  231. package/dist/src/services/generator-validate.js +180 -36
  232. package/dist/src/services/generator-validate.js.map +1 -1
  233. package/dist/src/services/owner-session.d.ts +43 -0
  234. package/dist/src/services/owner-session.d.ts.map +1 -0
  235. package/dist/src/services/owner-session.js +175 -0
  236. package/dist/src/services/owner-session.js.map +1 -0
  237. package/dist/src/services/schedule-constraints.d.ts +65 -0
  238. package/dist/src/services/schedule-constraints.d.ts.map +1 -0
  239. package/dist/src/services/schedule-constraints.js +106 -0
  240. package/dist/src/services/schedule-constraints.js.map +1 -0
  241. package/dist/src/services/scheduler.d.ts +34 -0
  242. package/dist/src/services/scheduler.d.ts.map +1 -1
  243. package/dist/src/services/scheduler.js +266 -22
  244. package/dist/src/services/scheduler.js.map +1 -1
  245. package/dist/src/services/skill-bundle/generator.js +19 -0
  246. package/dist/src/services/skill-bundle/generator.js.map +1 -1
  247. package/dist/src/storage/interface.d.ts +48 -4
  248. package/dist/src/storage/interface.d.ts.map +1 -1
  249. package/dist/src/storage/interface.js.map +1 -1
  250. package/dist/src/storage/providers/mongodb/index.d.ts +31 -0
  251. package/dist/src/storage/providers/mongodb/index.d.ts.map +1 -1
  252. package/dist/src/storage/providers/mongodb/index.js +187 -9
  253. package/dist/src/storage/providers/mongodb/index.js.map +1 -1
  254. package/dist/src/storage/providers/sqlite/index.d.ts +31 -0
  255. package/dist/src/storage/providers/sqlite/index.d.ts.map +1 -1
  256. package/dist/src/storage/providers/sqlite/index.js +131 -8
  257. package/dist/src/storage/providers/sqlite/index.js.map +1 -1
  258. package/dist/src/storage/providers/sqlite/repos/agent-task.d.ts.map +1 -1
  259. package/dist/src/storage/providers/sqlite/repos/agent-task.js +6 -4
  260. package/dist/src/storage/providers/sqlite/repos/agent-task.js.map +1 -1
  261. package/dist/src/storage/providers/sqlite/schema.d.ts.map +1 -1
  262. package/dist/src/storage/providers/sqlite/schema.js +79 -8
  263. package/dist/src/storage/providers/sqlite/schema.js.map +1 -1
  264. package/dist/src/storage/repositories/pat.repository.d.ts +40 -0
  265. package/dist/src/storage/repositories/pat.repository.d.ts.map +1 -0
  266. package/dist/src/storage/repositories/pat.repository.js +14 -0
  267. package/dist/src/storage/repositories/pat.repository.js.map +1 -0
  268. package/dist/src/storage/repositories/scheduler.repository.d.ts +2 -0
  269. package/dist/src/storage/repositories/scheduler.repository.d.ts.map +1 -1
  270. package/dist/src/storage/repositories/session.repository.d.ts +51 -0
  271. package/dist/src/storage/repositories/session.repository.d.ts.map +1 -1
  272. package/dist/src/storage/repositories/session.repository.js +12 -0
  273. package/dist/src/storage/repositories/session.repository.js.map +1 -1
  274. package/dist/src/utils/env-config.d.ts.map +1 -1
  275. package/dist/src/utils/env-config.js +25 -1
  276. package/dist/src/utils/env-config.js.map +1 -1
  277. package/dist/src/utils/env-validator.d.ts.map +1 -1
  278. package/dist/src/utils/env-validator.js +4 -0
  279. package/dist/src/utils/env-validator.js.map +1 -1
  280. package/package.json +1 -1
  281. package/prisma/schema.prisma +48 -0
@@ -1,7 +1,34 @@
1
1
  /* ═══════════════════════════════════════════════════════
2
- AIMEAT Unified Theme
3
- Single source of truth for all portal CSS variables,
4
- base styles, animations, and shared components.
2
+ @file theme.css
3
+ @description AIMEAT Unified Theme — single source of truth for all portal
4
+ CSS variables (tokens), base styles, animations, and shared components.
5
+ Defines the light theme in :root, a dark override in [data-theme="dark"],
6
+ and a drift-alias layer so undefined-but-referenced vars resolve.
7
+ @structure :root tokens, drift aliases, [data-theme="dark"] override,
8
+ base/reset, animations, topnav, buttons, cards, badges, inputs, modal,
9
+ toast, alert.
10
+ @usage Loaded first in spa.html <head>; the theme is toggled by /js/theme.js
11
+ which flips the data-theme attribute on <html>.
12
+ @version-history
13
+ v1.18.0 — 2026-06-02 — Component unification (#10 third toast pathway): tokenize the shared .toast color literals. Added a theme-invariant --toast-success-bg (green-500 #22C55E @ .95, the legacy toast green — deliberately NOT --success emerald, which would shift the hue), --toast-danger-bg (= --danger #EF4444 @ .95) and --toast-fg (white), same rationale as the badge palette. The base .toast and the .toast.error/.toast-error/.toast-success modifiers now reference these tokens instead of raw rgba()/#fff. Appearance-preserving: identical resolved values; solid saturated pills intentionally do not flip in dark mode. profile.js keeps its own showToast pathway (distinct .pf.toast-container wrapper + .toast.error markup) — left as a convergence candidate, NOT migrated, to avoid changing DOM/behavior.
14
+ v1.17.0 — 2026-06-02 — Component unification (#26 recipient badge): add a theme-invariant --badge-*-bg palette (wildcard→danger, ghii→purple, organism→success, gaii→blue; domain #F97316 / node #6B7280 kept as own invariant swatches as they have no palette match) + --badge-fg white, so the profile .badge-* recipient classifier can drop its hardcoded hex (#8b5cf6/#f97316/#6b7280/#3b82f6) and dead light-only fallbacks (var(--success,#22c55e)/var(--danger,#ef4444)). Appearance-preserving: values resolve identically and these solid swatches intentionally do not flip in dark mode.
15
+ v1.16.0 — 2026-06-02 — Component unification (#25 pill base): add a canonical token-only .pill shape primitive (inline-flex chip, --radius-full, compact padding, small bold text, pointer + opacity hover) — shape only, no colors; tints come from caller classes. Mirrors the shape the profile .vis-pill already used. The scoped .pf .vis-pill keeps its own shape declaration (the (0,2,0)-beats-bare-.pill specificity trap) but its radius was retokenized to the same --radius-full so the two stay in lockstep.
16
+ v1.15.0 — 2026-06-02 — Component unification (#23 collapsible): add canonical .collapsible / .collapsible-header / .collapsible-chevron (chevron rotates 180° via .open) / .collapsible-body block, backing /components/Collapsible.js. All colors are theme tokens so it flips in dark mode. Establishes the canonical expand/collapse section for the hand-rolled toggles (.expand-btn + .pf-chevron, .scope-advanced-toggle, .pkv-entry-arrow); those bespoke toggles are left in place where their expanded markup is wired into view state.
17
+ v1.14.0 — 2026-06-02 — Component unification (#24 search bar): add canonical .search-bar (flex row, gap, flex:1) + .search-bar-input (flex:1) shell, backing /components/SearchBar.js. The input reuses .input-field for all visuals, so the shell only owns layout. Consolidates the hand-rolled search inputs (.pkv-search / .cap-search-input / .pf-agd-search-input) and the profile .search-bar + .input-field combo; the profile-scoped .pf .search-bar (max-width) coexists.
18
+ v1.13.0 — 2026-06-02 — Component unification (#21 key/value rows): add canonical .kv-row / .kv-label / .kv-value (flex space-between, muted label, emphasized value, --border-subtle divider, last-child no border; .kv-value.mono for monospace ids/amounts), backing /components/KeyValueRow.js. Extracted as the common look of the admin .adm-erow/.adm-hrow and profile .pf-agd-info-row families. Existing per-view classes left in place where their look differs.
19
+ v1.12.0 — 2026-06-02 — Component unification (#13 tables): add canonical .data-table block (full-width collapsed table, uppercase muted header divided by --border, cells by --border-subtle, --bg-surface hover, .mono cell) + generic .scrollable wrapper, backing /components/DataTable.js. Extracted as the common look of .adm table + .pf .consent-table so both converge on tokens that flip in dark mode.
20
+ v1.11.0 — 2026-06-02 — Component unification (#16 tags): add --accent-border token (translucent accent hairline, light rgba(232,86,74,0.2) / dark rgba(255,111,98,0.30)) so tag/badge clones (mk-tag, hb-tag) can replace their hardcoded rgba(232,86,74,0.2) borders and flip in dark mode.
21
+ v1.10.0 — 2026-06-02 — Component unification (#17 pagination): add canonical .pagination (prev / "Page X / Y" / next, token-based) + .pagination-info + .load-more (centered load-more wrapper), backing /components/Pagination.js. Consolidates the .adm-mem-pagination shape and the centered load-more wrapper. The numbered .hb-pagination variant is intentionally left in place (different UI).
22
+ v1.9.0 — 2026-06-02 — Component unification (#18 category cards): add canonical .category-card / -icon / -name / -count (token-based, anchor- and div-safe) so the marketplace .mk-category-* and hobbies .hb-category-* clones converge. Tokenized the formerly hardcoded hover colors (#E8564A → var(--accent); 0 2px 8px rgba(0,0,0,0.06) → var(--shadow-md)) — dark-mode fix. Per-view *-categories-grid wrappers kept (column density differs).
23
+ v1.8.0 — 2026-06-02 — Component unification (#11 status dots): add canonical .status-dot base + semantic token modifiers (online/active/healthy/live → success; warn/degraded/syncing/pending → warn; error/offline/dead/down → danger; idle/inactive/detached/muted → text-muted), backing /components/StatusDot.js, so per-view dots (.peer-dot/.pn-status-dot/.ext-status-dot/.dv-dot/.live-dot) converge. Tokenized away hardcoded hex in the former .ext-status-dot (#4ade80/#9ca3af) so dots flip in dark mode.
24
+ v1.7.0 — 2026-06-02 — Component unification (#15 headers): add canonical .section-title/.section-desc (in-page accent header, lifted generic from .pf) + .page-title/.page-subtitle (top-of-view gradient header), all token-based, so per-view title/subtitle clones (mk-/hb-/cl-welcome-/adm-page-title) can converge.
25
+ v1.6.0 — 2026-06-02 — Component unification (#22): add .card-glass modifier (Card variant="glass") reproducing the former profile .pf-glass-card appearance, fully tokenized (--surface / --border), so profile's GlassCard folds into the canonical Card.
26
+ v1.5.0 — 2026-06-02 — Component unification (#6 stat cards): add canonical .stat-card-value tone (.accent/.success/.danger) + .mono modifiers and a .stat-grid wrapper, so per-view stat clones (mk-stat/hb-stat/dv-stat/wl-stat/...) converge onto .stat-card without losing accent-tint / earned-spent / monospace semantics.
27
+ v1.4.0 — 2026-06-02 — Component unification (#5 inputs): add canonical textarea.input-field (resize/min-height) + select.input-field (cursor) so .input-field works on all field types and views can drop per-view form-input/textarea/select clones (mk-form/hb-form/...).
28
+ v1.3.0 — 2026-06-02 — Component unification (#4): make canonical .btn-* anchor-safe (text-decoration:none) so views can drop their per-view <a>-button clones (mk-btn/hb-btn/...) and use the canonical classes.
29
+ v1.2.0 — 2026-06-02 — Tokenize shell component literals (semantic tints, scrollbar, overlay scrim, morsel pill, lang-btn active, input focus) so the whole shell flips for dark mode.
30
+ v1.1.0 — 2026-06-02 — Add dark theme override + drift-alias layer + .theme-toggle-btn.
31
+ v1.0.0 — prior — Light theme tokens, base styles, shared components.
5
32
  ═══════════════════════════════════════════════════════ */
6
33
 
7
34
  /* ── Reset ── */
@@ -28,6 +55,7 @@
28
55
  --accent-deep: #E8564A;
29
56
  --accent-glow: rgba(232, 86, 74, 0.3);
30
57
  --accent-subtle: rgba(232, 86, 74, 0.06);
58
+ --accent-border: rgba(232, 86, 74, 0.2); /* translucent accent hairline for tag/badge edges */
31
59
 
32
60
  /* Love palette (profile gradients — now coral-based) */
33
61
  --love1: #E8564A;
@@ -56,6 +84,32 @@
56
84
  --orange: #FB923C;
57
85
  --yellow: #FBBF24;
58
86
 
87
+ /* Recipient badge palette (profile permission-recipient classifier:
88
+ wildcard/ghii/organism/domain/node/gaii). Theme-INVARIANT on purpose —
89
+ these are saturated solid swatches carrying white text in both themes, so
90
+ they are defined only here and NOT re-overridden in [data-theme="dark"].
91
+ Four map onto existing palette tokens (identical values); domain/node have
92
+ no palette match and are kept as their own invariant swatches rather than
93
+ borrowed from --orange/--text-dim (which differ / flip in dark). */
94
+ --badge-wildcard-bg: var(--danger); /* #EF4444 */
95
+ --badge-ghii-bg: var(--purple); /* #8B5CF6 */
96
+ --badge-organism-bg: var(--success); /* #10B981 */
97
+ --badge-domain-bg: #F97316; /* no palette match (≠ --orange #FB923C) */
98
+ --badge-node-bg: #6B7280; /* invariant gray (≠ --text-dim, which flips dark) */
99
+ --badge-gaii-bg: var(--blue); /* #3B82F6 */
100
+ --badge-fg: #FFFFFF; /* white text on every saturated swatch */
101
+
102
+ /* Toast palette (floating notification pill). Theme-INVARIANT on purpose,
103
+ same rationale as the badge palette above: saturated solid fills carrying
104
+ white text read correctly on any background in both themes, so they are
105
+ defined only here and NOT re-overridden in [data-theme="dark"].
106
+ NOTE: --toast-success-bg is green-500 (#22C55E), the legacy toast green —
107
+ it is deliberately NOT --success (emerald #10B981); swapping would shift
108
+ the hue. --toast-danger-bg equals --danger at the legacy 0.95 alpha. */
109
+ --toast-success-bg: rgba(34, 197, 94, 0.95);
110
+ --toast-danger-bg: rgba(239, 68, 68, 0.95); /* = --danger #EF4444 @ .95 */
111
+ --toast-fg: #FFFFFF;
112
+
59
113
  /* Borders */
60
114
  --border: #E5E7EB;
61
115
  --border-subtle: #F3F4F6;
@@ -88,6 +142,121 @@
88
142
 
89
143
  /* Code */
90
144
  --code-bg: #F3F4F6;
145
+
146
+ /* Semantic tints (chip/banner backgrounds + readable text/border on them).
147
+ The accent semantic colors (--success/--warn/--danger/--info) keep their
148
+ meaning across themes; only these tint surfaces flip. */
149
+ --success-bg: #D1FAE5; --success-fg: #047857; --success-border: #A7F3D0;
150
+ --warn-bg: #FEF3C7; --warn-fg: #B45309; --warn-border: #FDE68A;
151
+ --danger-bg: #FEE2E2; --danger-fg: #DC2626; --danger-border: #FECACA;
152
+ --info-bg: #EFF6FF; --info-fg: #1D4ED8; --info-border: #BFDBFE;
153
+ --purple-bg: #F5F3FF; --purple-fg: #6D28D9; --purple-border: #DDD6FE;
154
+
155
+ /* Shell surfaces */
156
+ --scrollbar-thumb: #D1D5DB;
157
+ --overlay-scrim: rgba(26, 26, 46, 0.4);
158
+ --morsel-bg: linear-gradient(135deg, #FFF1F0, #FFE0DE);
159
+
160
+ /* Decorative view gradients (theme-aware) */
161
+ --pf-hero-gradient: linear-gradient(135deg, #FAFAF8 0%, #FFF1F0 40%, #EFF6FF 100%);
162
+ --pf-cta-gradient: linear-gradient(135deg, #FFF1F0, #EFF6FF);
163
+ --pf-callout-gradient: linear-gradient(135deg, #EEF0FF, #F8F0FF);
164
+
165
+ /* ── Drift-alias layer ──
166
+ Variables referenced across view CSS but never defined (rendered with no
167
+ fallback = broken). Defined here as aliases of the canonical tokens above,
168
+ so they (a) work now and (b) inherit the dark override automatically — no
169
+ entry needed in [data-theme="dark"]. The --sp-* scale is theme-invariant. */
170
+ --card: var(--bg-card);
171
+ --surface: var(--bg-surface);
172
+ --bg-dim: var(--bg-surface);
173
+ --bg-hover: var(--card-bg-hover);
174
+ --muted: var(--text-dim);
175
+ --error: var(--danger);
176
+ --warning: var(--warn);
177
+ --primary: var(--accent);
178
+ --accent-faint: var(--accent-subtle);
179
+ --accent-soft: var(--accent-subtle); /* highlight/hover surfaces (was #FFF0EE) */
180
+ --accent-dark: var(--accent-deep); /* darker coral for button gradients/hovers */
181
+ --border-soft: var(--border); /* was #f0f0ec */
182
+ --bg2: var(--bg-surface); /* secondary panel bg (was #f5f5f5) */
183
+ --surface-hover: var(--bg-surface); /* hover surface (had a stale dark #252540 fallback) */
184
+ --on-inverted: var(--bg); /* readable text on a var(--text) background — inverts opposite to --text */
185
+ --mono: var(--font-mono);
186
+ --sp-1: 4px;
187
+ --sp-2: 8px;
188
+ --sp-3: 12px;
189
+ --sp-4: 16px;
190
+ }
191
+
192
+ /* ── Dark Theme Override ──
193
+ Redefines only the color/depth variables that must flip for dark mode.
194
+ Brand identity (coral accent) preserved; accents brightened for dark
195
+ contrast. Text tiers verified WCAG-AA on both --bg and --bg-card.
196
+ Aliases above point at these tokens, so they invert automatically. */
197
+ [data-theme="dark"] {
198
+ /* Background */
199
+ --bg: #14151A;
200
+ --bg-surface: #23262F;
201
+ --bg-card: #1C1E26;
202
+ --bg-elevated: #23262F;
203
+
204
+ /* Cards & Surfaces */
205
+ --card-bg: #1C1E26;
206
+ --card-bg-hover: #23262F;
207
+ --card-bg-solid: #1C1E26;
208
+ --card-bg-alt: #23262F;
209
+ --card-border: #33363F;
210
+
211
+ /* Accent (coral heart — brightened for dark contrast, brand stays coral) */
212
+ --accent: #FF6F62;
213
+ --accent-bright: #FF7A6E;
214
+ --accent-deep: #E8564A;
215
+ --accent-glow: rgba(255, 111, 98, 0.35);
216
+ --accent-subtle: rgba(255, 111, 98, 0.10);
217
+ --accent-border: rgba(255, 111, 98, 0.30); /* translucent accent hairline for tag/badge edges */
218
+
219
+ /* Text */
220
+ --text: #EDEEF2;
221
+ --text-bright: #FFFFFF;
222
+ --text-dim: #A4A9B6;
223
+ --text-muted: #868C9B;
224
+
225
+ /* Borders */
226
+ --border: #33363F;
227
+ --border-subtle: #26282F;
228
+ --border-focus: #FF6F62;
229
+
230
+ /* Shadows (deeper/more opaque so elevation reads on dark surfaces) */
231
+ --shadow-sm: 0 1px 2px rgba(0,0,0,0.40);
232
+ --shadow-md: 0 4px 12px rgba(0,0,0,0.50);
233
+ --shadow-lg: 0 8px 24px rgba(0,0,0,0.55);
234
+ --shadow-xl: 0 16px 48px rgba(0,0,0,0.65);
235
+ --shadow-heart: 0 4px 14px rgba(255,111,98,0.40);
236
+
237
+ /* Input */
238
+ --bg-input: #1C1E26;
239
+ --bg-input-focus: #23262F;
240
+
241
+ /* Code */
242
+ --code-bg: #0E0F13;
243
+
244
+ /* Semantic tints (translucent so they read as native dark surfaces) */
245
+ --success-bg: rgba(16, 185, 129, 0.16); --success-fg: #6EE7B7; --success-border: rgba(16, 185, 129, 0.32);
246
+ --warn-bg: rgba(245, 158, 11, 0.16); --warn-fg: #FCD34D; --warn-border: rgba(245, 158, 11, 0.32);
247
+ --danger-bg: rgba(239, 68, 68, 0.16); --danger-fg: #FCA5A5; --danger-border: rgba(239, 68, 68, 0.34);
248
+ --info-bg: rgba(59, 130, 246, 0.16); --info-fg: #93C5FD; --info-border: rgba(59, 130, 246, 0.32);
249
+ --purple-bg: rgba(139, 92, 246, 0.18); --purple-fg: #C4B5FD; --purple-border: rgba(139, 92, 246, 0.34);
250
+
251
+ /* Shell surfaces */
252
+ --scrollbar-thumb: #3A3D47;
253
+ --overlay-scrim: rgba(0, 0, 0, 0.6);
254
+ --morsel-bg: rgba(255, 111, 98, 0.16);
255
+
256
+ /* Decorative view gradients — subtle dark tints matching the light intent */
257
+ --pf-hero-gradient: linear-gradient(135deg, #16151A 0%, #201820 45%, #15191F 100%);
258
+ --pf-cta-gradient: linear-gradient(135deg, #231A1E, #1A1F28);
259
+ --pf-callout-gradient: linear-gradient(135deg, #1C1A29, #221A29);
91
260
  }
92
261
 
93
262
  /* ── Base ── */
@@ -221,8 +390,8 @@ a { color: inherit; text-decoration: none; }
221
390
  gap: 2px;
222
391
  padding: 3px 10px;
223
392
  border-radius: var(--radius-full);
224
- border: 1px solid rgba(232, 86, 74, 0.15);
225
- background: linear-gradient(135deg, #FFF1F0, #FFE0DE);
393
+ border: 1px solid var(--accent-glow);
394
+ background: var(--morsel-bg);
226
395
  color: var(--accent);
227
396
  font-size: 0.75rem;
228
397
  font-weight: 700;
@@ -277,13 +446,13 @@ a { color: inherit; text-decoration: none; }
277
446
 
278
447
  .topnav-right a.active {
279
448
  color: var(--accent);
280
- background: rgba(232, 86, 74, 0.06);
449
+ background: var(--accent-subtle);
281
450
  }
282
451
 
283
452
  .topnav-right .profile-link {
284
453
  display: none;
285
454
  color: var(--accent);
286
- background: rgba(232, 86, 74, 0.06);
455
+ background: var(--accent-subtle);
287
456
  }
288
457
 
289
458
  .topnav-right .profile-link.visible { display: inline-flex; }
@@ -293,6 +462,42 @@ a { color: inherit; text-decoration: none; }
293
462
  align-items: center;
294
463
  }
295
464
 
465
+ /* ── Header nav: desktop inline; mobile = hamburger + dropdown (see @media) ── */
466
+ .topnav-menu { display: flex; align-items: center; gap: 0.75rem; }
467
+ .topnav-burger { display: none; }
468
+ /* Truncate a long GHII in the gold pill so it never blows out the bar (desktop). */
469
+ .aimeat-auth-ghii { max-width: 240px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
470
+
471
+ /* Collapse the header to a hamburger well before the full inline nav (links +
472
+ theme/lang + gold pill, wider still for operators with the Admin link) runs
473
+ out of room — otherwise the pill overflows in the ~900–1180px band. */
474
+ @media (max-width: 1180px) {
475
+ .topnav { padding: 0 0.5rem; }
476
+ .topnav-right { gap: 0.5rem; }
477
+ /* Free up bar width so the gold pill never overflows — the morsel count is
478
+ still shown in the profile dashboard. */
479
+ .brand-morsels { display: none !important; }
480
+ .topnav-burger {
481
+ display: inline-flex; align-items: center; justify-content: center;
482
+ width: 38px; height: 34px; padding: 0; font-size: 1.2rem; line-height: 1;
483
+ background: none; color: var(--text); border: 1px solid var(--border);
484
+ border-radius: var(--radius-xs); cursor: pointer;
485
+ }
486
+ .topnav-menu {
487
+ display: none; position: absolute; top: var(--nav-height); left: 0; right: 0;
488
+ flex-direction: column; align-items: stretch; gap: 0;
489
+ background: var(--bg-card); border-bottom: 1px solid var(--border);
490
+ box-shadow: var(--shadow-lg, 0 8px 24px rgba(0,0,0,.18)); padding: 0.4rem;
491
+ }
492
+ .topnav-menu.open { display: flex; }
493
+ .topnav-menu a { width: 100%; padding: 0.7rem 0.9rem; font-size: 0.95rem; border-radius: var(--radius-xs); }
494
+ .topnav-menu .topnav-center { width: fit-content; margin: 0.45rem 0.6rem 0.2rem; }
495
+ /* Compact gold pill: keep the green dot + Logout, drop the wordy label + GHII. */
496
+ .aimeat-auth-pill .aimeat-auth-label,
497
+ .aimeat-auth-pill .aimeat-auth-ghii { display: none !important; }
498
+ .aimeat-auth-pill { padding: 5px 11px !important; gap: 6px !important; }
499
+ }
500
+
296
501
  /* ── Language Buttons ── */
297
502
  .lang-btn {
298
503
  padding: 4px 10px;
@@ -310,7 +515,7 @@ a { color: inherit; text-decoration: none; }
310
515
 
311
516
  .lang-btn.active {
312
517
  background: var(--text);
313
- color: #FFFFFF;
518
+ color: var(--on-inverted);
314
519
  box-shadow: none;
315
520
  }
316
521
 
@@ -319,7 +524,37 @@ a { color: inherit; text-decoration: none; }
319
524
  background: var(--bg-surface);
320
525
  }
321
526
 
527
+ /* ── Theme Toggle ── */
528
+ .theme-toggle-btn {
529
+ display: inline-flex;
530
+ align-items: center;
531
+ justify-content: center;
532
+ width: 30px;
533
+ height: 26px;
534
+ padding: 0;
535
+ border: none;
536
+ border-right: 1px solid var(--border);
537
+ background: transparent;
538
+ color: var(--text-dim);
539
+ font-size: 0.95rem;
540
+ line-height: 1;
541
+ cursor: pointer;
542
+ transition: all 0.15s;
543
+ font-family: var(--font);
544
+ }
545
+
546
+ .theme-toggle-btn:hover {
547
+ color: var(--accent);
548
+ background: var(--bg-surface);
549
+ }
550
+
322
551
  /* ── Buttons ── */
552
+ /* Button classes are anchor-safe: applied to <a> they render as buttons,
553
+ not underlined links (lets views use canonical .btn-* on link-buttons). */
554
+ .btn-primary, .btn-outline, .btn-ghost, .btn-danger, .btn-danger-solid,
555
+ .btn-success, .btn-info {
556
+ text-decoration: none;
557
+ }
323
558
  .btn-primary {
324
559
  padding: 8px 20px;
325
560
  background: linear-gradient(135deg, #E8564A 0%, #FF6B6B 100%);
@@ -419,9 +654,9 @@ a { color: inherit; text-decoration: none; }
419
654
  }
420
655
 
421
656
  .btn-danger {
422
- background: #FEE2E2;
423
- color: var(--danger);
424
- border: 1px solid #FECACA;
657
+ background: var(--danger-bg);
658
+ color: var(--danger-fg);
659
+ border: 1px solid var(--danger-border);
425
660
  }
426
661
 
427
662
  .btn-ghost {
@@ -467,6 +702,24 @@ a { color: inherit; text-decoration: none; }
467
702
  padding: 1.5rem;
468
703
  }
469
704
 
705
+ /* Glass variant (Card variant="glass") — reproduces the former profile
706
+ .pf-glass-card appearance, fully tokenized. Overrides .card defaults
707
+ (2rem padding, var(--radius), shadow) with the glass card's flatter geometry. */
708
+ .card-glass {
709
+ padding: 16px;
710
+ border-radius: 8px;
711
+ background: var(--surface);
712
+ border: 1px solid var(--border);
713
+ margin-bottom: 1rem;
714
+ box-shadow: none;
715
+ }
716
+ /* Glass card is flat — neutralize the generic .card:hover lift so it looks
717
+ identical to the former static .pf-glass-card. */
718
+ .card-glass:hover {
719
+ box-shadow: none;
720
+ transform: none;
721
+ }
722
+
470
723
  /* ── Content Group Container ── */
471
724
  .content-group {
472
725
  position: relative;
@@ -507,6 +760,29 @@ a { color: inherit; text-decoration: none; }
507
760
  font-weight: 800;
508
761
  margin-top: 0.15rem;
509
762
  }
763
+ /* Value tone + mono modifiers — let accent-tinted / earned-spent / monospace stat
764
+ clones converge onto canonical .stat-card-value without losing their semantics. */
765
+ .stat-card-value.accent { color: var(--accent); }
766
+ .stat-card-value.success { color: var(--success-fg); }
767
+ .stat-card-value.danger { color: var(--danger-fg); }
768
+ .stat-card-value.mono { font-family: var(--font-mono, monospace); }
769
+ /* Shared responsive stat grid wrapper. */
770
+ .stat-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: 12px; margin-bottom: 32px; }
771
+
772
+ /* ── Category Card ── */
773
+ /* Canonical clickable directory tile (icon + name + optional count) shared by the
774
+ marketplace category grid and the hobbies interest grid. Works on both <a> and
775
+ <div> (text-decoration:none keeps anchors un-underlined). The grid wrapper stays
776
+ per-view because column density differs (marketplace 160px / hobbies 200px min). */
777
+ .category-card {
778
+ background: var(--bg-card); border: 1px solid var(--border);
779
+ border-radius: var(--radius); padding: 20px; text-align: center; text-decoration: none;
780
+ transition: all 0.2s; cursor: pointer;
781
+ }
782
+ .category-card:hover { background: var(--bg-surface); border-color: var(--accent); box-shadow: var(--shadow-md); }
783
+ .category-icon { font-size: 2rem; margin-bottom: 8px; }
784
+ .category-name { font-size: 0.95rem; font-weight: 600; color: var(--text); }
785
+ .category-count { font-size: 0.78rem; color: var(--text-muted); margin-top: 4px; }
510
786
 
511
787
  /* ── Badges ── */
512
788
  .badge {
@@ -519,21 +795,211 @@ a { color: inherit; text-decoration: none; }
519
795
  letter-spacing: 0.3px;
520
796
  }
521
797
 
522
- .badge-success { background: #D1FAE5; color: #047857; }
523
- .badge-warn { background: #FEF3C7; color: #B45309; }
524
- .badge-danger { background: #FEE2E2; color: #DC2626; }
525
- .badge-info { background: #EFF6FF; color: #1D4ED8; }
798
+ .badge-success { background: var(--success-bg); color: var(--success-fg); }
799
+ .badge-warn { background: var(--warn-bg); color: var(--warn-fg); }
800
+ .badge-danger { background: var(--danger-bg); color: var(--danger-fg); }
801
+ .badge-info { background: var(--info-bg); color: var(--info-fg); }
802
+
803
+ /* ── Pill (canonical shape primitive) ──
804
+ The common pill-chip *shape* only — no colors. Small inline-flex chip with
805
+ pill radius, compact padding, small bold text, pointer cursor and a soft
806
+ opacity hover. Colors are supplied by the caller's own tint classes (e.g.
807
+ .vis-public / .vis-private) so this base stays theme-neutral. Matches the
808
+ shape the profile visibility pill (.vis-pill) already used. New pill-shaped
809
+ chips should build on this base + a tint class instead of re-declaring the
810
+ shape. Note: the profile pills are styled via the higher-specificity
811
+ `.pf .vis-pill`, which keeps its own shape declaration to avoid the
812
+ scoped-override specificity trap; it now references the same --radius-full
813
+ token so the two stay in lockstep. */
814
+ .pill {
815
+ display: inline-flex;
816
+ align-items: center;
817
+ border: none;
818
+ cursor: pointer;
819
+ padding: 2px 8px;
820
+ border-radius: var(--radius-full);
821
+ font-size: 0.7rem;
822
+ font-weight: 600;
823
+ transition: opacity 0.15s;
824
+ }
825
+ .pill:hover { opacity: 0.8; }
526
826
 
527
- /* ── Live dot ── */
528
- .live-dot {
827
+ /* ── Status dot (canonical) ──
828
+ Small circle whose color is driven by a semantic status token. Consolidates
829
+ the bespoke per-view dots (.live-dot, .peer-dot, .pn-status-dot,
830
+ .ext-status-dot, .dv-dot). Component: /components/StatusDot.js.
831
+ All colors are theme tokens so the dot flips correctly in dark mode. */
832
+ .status-dot {
833
+ display: inline-block;
529
834
  width: 8px;
530
835
  height: 8px;
531
836
  border-radius: 50%;
532
- background: var(--success);
837
+ flex-shrink: 0;
838
+ background: var(--text-muted);
839
+ }
840
+ .status-dot--online,
841
+ .status-dot--active,
842
+ .status-dot--healthy,
843
+ .status-dot--alive,
844
+ .status-dot--live { background: var(--success); }
845
+ .status-dot--warn,
846
+ .status-dot--degraded,
847
+ .status-dot--syncing,
848
+ .status-dot--pending { background: var(--warn); }
849
+ .status-dot--error,
850
+ .status-dot--offline,
851
+ .status-dot--dead,
852
+ .status-dot--down { background: var(--danger); }
853
+ .status-dot--idle,
854
+ .status-dot--inactive,
855
+ .status-dot--detached,
856
+ .status-dot--muted { background: var(--text-muted); }
857
+ /* Online keeps the soft glow the former .pn-status-dot.online had */
858
+ .status-dot--online { box-shadow: 0 0 6px rgba(34, 197, 94, 0.4); }
859
+ /* Live additionally pulses (matches former .live-dot behaviour) */
860
+ .status-dot--live {
533
861
  box-shadow: 0 0 8px rgba(34, 197, 94, 0.6);
534
862
  animation: livePulse 1.5s ease-in-out infinite;
535
863
  }
536
864
 
865
+ /* ── Key/value detail row (canonical) ──
866
+ Backed by /components/KeyValueRow.js. A label/value pair laid out flex
867
+ space-between: muted label on the left, emphasized value on the right,
868
+ separated by a subtle bottom border (none on the last row). Consolidates the
869
+ common label+value-pair shape (admin .adm-erow / .adm-hrow, profile
870
+ .pf-agd-info-row). All colors are theme tokens so it flips correctly in dark
871
+ mode. `.kv-value.mono` renders the value in the monospace font (ids, hashes,
872
+ amounts). The existing per-view classes are intentionally left in place where
873
+ their look differs. */
874
+ .kv-row {
875
+ display: flex;
876
+ align-items: center;
877
+ justify-content: space-between;
878
+ gap: 0.5rem;
879
+ padding: 7px 0;
880
+ border-bottom: 1px solid var(--border-subtle);
881
+ font-size: 0.84rem;
882
+ }
883
+ .kv-row:last-child { border-bottom: none; }
884
+ .kv-label {
885
+ color: var(--text-dim);
886
+ flex-shrink: 0;
887
+ }
888
+ .kv-value {
889
+ color: var(--text);
890
+ font-weight: 600;
891
+ text-align: right;
892
+ word-break: break-word;
893
+ }
894
+ .kv-value.mono {
895
+ font-family: var(--font-mono);
896
+ font-size: 0.81rem;
897
+ }
898
+
899
+ /* ── Pagination + Load more (canonical) ──
900
+ Backed by /components/Pagination.js. `.pagination` is the prev / "Page X / Y"
901
+ / next control (arrow buttons + disabled ends); `.load-more` centers a single
902
+ "load more" button. Consolidates the near-identical .adm-mem-pagination shape
903
+ and the centered load-more wrapper. All colors are theme tokens so both flip
904
+ correctly in dark mode. The numbered .hb-pagination variant is intentionally
905
+ left in place (different UI). */
906
+ .pagination {
907
+ display: flex;
908
+ align-items: center;
909
+ justify-content: center;
910
+ gap: 12px;
911
+ margin-top: 8px;
912
+ }
913
+ .pagination-info {
914
+ font-size: 0.85rem;
915
+ color: var(--text-dim);
916
+ }
917
+ .load-more {
918
+ text-align: center;
919
+ margin-top: 1.5rem;
920
+ }
921
+
922
+ /* ── Collapsible (canonical) ──
923
+ Backed by /components/Collapsible.js. A clickable header (title + a chevron
924
+ that rotates 180° when open) with the body shown only while open. This is the
925
+ canonical shape for the hand-rolled expand/collapse toggles scattered across
926
+ views (.expand-btn + .pf-chevron, .scope-advanced-toggle, .pkv-entry-arrow).
927
+ All colors are theme tokens so it flips correctly in dark mode. Callers own
928
+ the open state (controlled component). The bespoke per-view toggles are left
929
+ in place where their expanded markup is wired into view state; this block is
930
+ the target for new collapsible sections. */
931
+ .collapsible {
932
+ border: 1px solid var(--border);
933
+ border-radius: var(--radius-sm);
934
+ margin-bottom: 0.75rem;
935
+ }
936
+ .collapsible-header {
937
+ display: flex;
938
+ align-items: center;
939
+ justify-content: space-between;
940
+ gap: 0.5rem;
941
+ width: 100%;
942
+ padding: 0.6rem 0.85rem;
943
+ background: none;
944
+ border: none;
945
+ border-radius: var(--radius-sm);
946
+ color: var(--text);
947
+ font-family: var(--font);
948
+ font-size: 0.85rem;
949
+ font-weight: 600;
950
+ text-align: left;
951
+ cursor: pointer;
952
+ transition: color 0.2s;
953
+ }
954
+ .collapsible-header:hover {
955
+ color: var(--accent);
956
+ }
957
+ .collapsible-chevron {
958
+ display: inline-block;
959
+ flex-shrink: 0;
960
+ font-size: 0.7rem;
961
+ color: var(--text-dim);
962
+ transition: transform 0.2s;
963
+ }
964
+ .collapsible-chevron.open {
965
+ transform: rotate(180deg);
966
+ }
967
+ .collapsible-body {
968
+ padding: 0 0.85rem 0.75rem;
969
+ }
970
+
971
+ /* ── Data table (canonical) ──
972
+ Generic table look backed by /components/DataTable.js. Extracted as the common
973
+ denominator of the admin `.adm table` and profile `.pf .consent-table` /
974
+ `.audit-table` shapes: full-width collapsed borders, an uppercase muted header
975
+ row divided by `--border`, cells divided by `--border-subtle`, a subtle hover,
976
+ and a `.mono` cell modifier. All colors are theme tokens so the table flips
977
+ correctly in dark mode. The `.scrollable` wrapper caps height (admin reuses its
978
+ own `.adm .scrollable`; this generic one applies outside `.adm`). Callers supply
979
+ their own container (`.card` / `.adm-card`); this block adds none. */
980
+ .data-table { width: 100%; border-collapse: collapse; font-size: .81rem; }
981
+ .data-table th {
982
+ text-align: left;
983
+ color: var(--text-muted);
984
+ font-weight: 600;
985
+ padding: 8px 10px;
986
+ border-bottom: 1px solid var(--border);
987
+ white-space: nowrap;
988
+ font-size: .69rem;
989
+ text-transform: uppercase;
990
+ letter-spacing: .3px;
991
+ }
992
+ .data-table td {
993
+ padding: 8px 10px;
994
+ border-bottom: 1px solid var(--border-subtle);
995
+ color: var(--text-dim);
996
+ }
997
+ .data-table tr:hover td { background: var(--bg-surface); }
998
+ .data-table .mono { font-family: var(--font-mono); font-size: .78rem; }
999
+ /* Generic scrollable wrapper (the admin-scoped `.adm .scrollable` already exists
1000
+ for admin tables; this one covers DataTable used outside `.adm`). */
1001
+ .scrollable { max-height: 600px; overflow-y: auto; }
1002
+
537
1003
  /* ── Section divider ── */
538
1004
  .section-divider {
539
1005
  position: relative;
@@ -562,9 +1028,31 @@ a { color: inherit; text-decoration: none; }
562
1028
 
563
1029
  .input-field:focus {
564
1030
  border-color: var(--accent);
565
- box-shadow: 0 0 0 3px rgba(232, 86, 74, 0.1);
566
- background: #FFFFFF;
1031
+ box-shadow: 0 0 0 3px var(--accent-subtle);
1032
+ background: var(--bg-input-focus);
1033
+ }
1034
+
1035
+ /* Textarea + select behavior so .input-field works on all field types (lets views
1036
+ drop per-view form-input/textarea/select clones). */
1037
+ textarea.input-field { resize: vertical; min-height: 80px; }
1038
+ select.input-field { cursor: pointer; }
1039
+
1040
+ /* ── Search bar (canonical shell) ──
1041
+ Backed by /components/SearchBar.js. `.search-bar` is the flex row that wraps a
1042
+ single `type="search"` input; the input itself reuses `.input-field` so all
1043
+ visuals (border, focus ring, placeholder, dark-mode flip) are token-driven and
1044
+ need no per-view restyling. `.search-bar-input` only makes the input grow to
1045
+ fill the row. Consolidates the hand-rolled search inputs (.pkv-search,
1046
+ .cap-search-input, .pf-agd-search-input) and the profile .search-bar +
1047
+ .input-field combo. The profile-scoped `.pf .search-bar` rule (with max-width)
1048
+ coexists; this base provides the layout everywhere else. */
1049
+ .search-bar {
1050
+ display: flex;
1051
+ align-items: center;
1052
+ gap: 0.5rem;
1053
+ flex: 1;
567
1054
  }
1055
+ .search-bar-input { flex: 1; }
568
1056
 
569
1057
  .prompt-box {
570
1058
  width: 100%;
@@ -585,7 +1073,7 @@ a { color: inherit; text-decoration: none; }
585
1073
 
586
1074
  .prompt-box:focus {
587
1075
  border-color: var(--accent);
588
- box-shadow: 0 0 0 3px rgba(232, 86, 74, 0.1);
1076
+ box-shadow: 0 0 0 3px var(--accent-subtle);
589
1077
  }
590
1078
 
591
1079
  /* ── Spinner ── */
@@ -607,11 +1095,29 @@ a { color: inherit; text-decoration: none; }
607
1095
  color: var(--text-muted);
608
1096
  font-style: italic;
609
1097
  }
1098
+ /* Optional icon for the canonical EmptyState component (#9). */
1099
+ .empty-icon { display: block; font-size: 2.5rem; opacity: 0.4; margin-bottom: 0.5rem; font-style: normal; }
1100
+
1101
+ /* ── Toggle Switch (canonical /components/ToggleSwitch.js, #14) ── */
1102
+ .toggle { display: flex; align-items: center; gap: 10px; cursor: pointer; }
1103
+ .toggle-input { position: absolute; opacity: 0; width: 0; height: 0; }
1104
+ .toggle-slider {
1105
+ position: relative; display: inline-block; width: 44px; height: 24px;
1106
+ background: var(--border); border-radius: 12px; transition: background 0.2s;
1107
+ }
1108
+ .toggle-slider::after {
1109
+ content: ''; position: absolute; top: 2px; left: 2px;
1110
+ width: 20px; height: 20px; border-radius: 50%; background: #fff;
1111
+ transition: transform 0.2s; box-shadow: 0 1px 3px rgba(0,0,0,0.15);
1112
+ }
1113
+ .toggle-input:checked + .toggle-slider { background: var(--success); }
1114
+ .toggle-input:checked + .toggle-slider::after { transform: translateX(20px); }
1115
+ .toggle-label { font-size: .85rem; color: var(--text); }
610
1116
 
611
1117
  /* ── Scrollbar ── */
612
1118
  ::-webkit-scrollbar { width: 6px; }
613
1119
  ::-webkit-scrollbar-track { background: transparent; }
614
- ::-webkit-scrollbar-thumb { background: #D1D5DB; border-radius: 4px; }
1120
+ ::-webkit-scrollbar-thumb { background: var(--scrollbar-thumb); border-radius: 4px; }
615
1121
 
616
1122
  /* ── Footer ── */
617
1123
  .footer {
@@ -639,7 +1145,7 @@ a { color: inherit; text-decoration: none; }
639
1145
  /* ── Responsive ── */
640
1146
  @media (max-width: 480px) {
641
1147
  .content-group { margin-top: 2rem; padding: 1.5rem 1rem; }
642
- .topnav { padding: 0 0.75rem; }
1148
+ .topnav { padding: 0 0.4rem; }
643
1149
  }
644
1150
 
645
1151
  /* ═══════════════════════════════════════════════════════
@@ -656,10 +1162,10 @@ a { color: inherit; text-decoration: none; }
656
1162
  .alert-msg { flex: 1; }
657
1163
  .alert-close { background: none; border: none; color: inherit; cursor: pointer; font-size: 1rem; padding: 0 0.25rem; opacity: 0.7; }
658
1164
  .alert-close:hover { opacity: 1; }
659
- .alert-success { background: #D1FAE5; color: #047857; border: 1px solid #A7F3D0; }
660
- .alert-error { background: #FEE2E2; color: #DC2626; border: 1px solid #FECACA; }
661
- .alert-warn { background: #FEF3C7; color: #B45309; border: 1px solid #FDE68A; }
662
- .alert-info { background: #EFF6FF; color: #1D4ED8; border: 1px solid #BFDBFE; }
1165
+ .alert-success { background: var(--success-bg); color: var(--success-fg); border: 1px solid var(--success-border); }
1166
+ .alert-error { background: var(--danger-bg); color: var(--danger-fg); border: 1px solid var(--danger-border); }
1167
+ .alert-warn { background: var(--warn-bg); color: var(--warn-fg); border: 1px solid var(--warn-border); }
1168
+ .alert-info { background: var(--info-bg); color: var(--info-fg); border: 1px solid var(--info-border); }
663
1169
 
664
1170
  /* ── Toast ── */
665
1171
  .toast {
@@ -667,19 +1173,19 @@ a { color: inherit; text-decoration: none; }
667
1173
  z-index: 9999; max-width: min(90vw, 420px); width: fit-content;
668
1174
  padding: 0.75rem 1.25rem; border-radius: var(--radius-xs);
669
1175
  font-size: 0.85rem; font-weight: 600;
670
- background: rgba(34, 197, 94, 0.95); color: #fff;
1176
+ background: var(--toast-success-bg); color: var(--toast-fg);
671
1177
  animation: toastIn 0.3s ease, toastOut 0.4s ease 2.4s forwards;
672
1178
  pointer-events: auto; box-sizing: border-box;
673
1179
  }
674
- .toast.error, .toast-error { background: rgba(239, 68, 68, 0.95); color: #fff; }
675
- .toast-success { background: rgba(34, 197, 94, 0.95); color: #fff; }
1180
+ .toast.error, .toast-error { background: var(--toast-danger-bg); color: var(--toast-fg); }
1181
+ .toast-success { background: var(--toast-success-bg); color: var(--toast-fg); }
676
1182
  @keyframes toastIn { from { opacity: 0; transform: translateX(-50%) translateY(16px); } to { opacity: 1; transform: translateX(-50%) translateY(0); } }
677
1183
  @keyframes toastOut { from { opacity: 1; } to { opacity: 0; pointer-events: none; } }
678
1184
 
679
1185
  /* ── Modal ── */
680
1186
  .modal-overlay {
681
1187
  position: fixed; inset: 0; z-index: 1000;
682
- background: rgba(26, 26, 46, 0.4); backdrop-filter: blur(8px);
1188
+ background: var(--overlay-scrim); backdrop-filter: blur(8px);
683
1189
  display: flex; align-items: center; justify-content: center;
684
1190
  padding: 24px;
685
1191
  animation: fadeIn 0.2s ease;
@@ -711,6 +1217,22 @@ a { color: inherit; text-decoration: none; }
711
1217
 
712
1218
  /* ── Loading text ── */
713
1219
  .loading-text { margin-left: 0.5rem; color: var(--text-dim); font-size: 0.85rem; }
714
-
715
- /* ── Accessibility ── */
716
- .visually-hidden { position:absolute; width:1px; height:1px; padding:0; margin:-1px; overflow:hidden; clip:rect(0,0,0,0); white-space:nowrap; border:0; }
1220
+
1221
+ /* ── Section & page headers (canonical title + subtitle pairs) ──
1222
+ Single source of truth for the "title + supporting copy" header that every
1223
+ view re-implements. Use .section-title/.section-desc for in-page section
1224
+ headers (accent title) and .page-title/.page-subtitle for top-of-view page
1225
+ headers (gradient title). All values are theme tokens so they flip with
1226
+ dark/light mode. Per-view clones (mk-/hb-/cl-/adm-page-title) are
1227
+ token-equivalent and should converge onto these over time. */
1228
+ .section-title { font-size: 1.15rem; font-weight: 700; margin-bottom: 0.4rem; color: var(--accent); }
1229
+ .section-desc { color: var(--text-dim); font-size: 0.85rem; margin-bottom: 1.25rem; line-height: 1.5; max-width: 700px; }
1230
+ .page-title {
1231
+ font-size: 1.8rem; font-weight: 700; margin-bottom: 8px;
1232
+ background: linear-gradient(135deg, var(--accent), var(--accent-deep));
1233
+ -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text;
1234
+ }
1235
+ .page-subtitle { color: var(--text-dim); font-size: 1rem; margin-bottom: 32px; }
1236
+
1237
+ /* ── Accessibility ── */
1238
+ .visually-hidden { position:absolute; width:1px; height:1px; padding:0; margin:-1px; overflow:hidden; clip:rect(0,0,0,0); white-space:nowrap; border:0; }