@vellumai/assistant 0.10.9 → 0.10.10-dev.202607162206.d08e98e

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 (456) hide show
  1. package/ARCHITECTURE.md +1 -1
  2. package/Dockerfile +8 -0
  3. package/docs/activation-funnel-telemetry.md +13 -7
  4. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/package.json +1 -0
  5. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/__tests__/redacted-credential.test.ts +200 -0
  6. package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/redacted-credential.ts +226 -0
  7. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/package.json +1 -0
  8. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/__tests__/redacted-credential.test.ts +200 -0
  9. package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/redacted-credential.ts +226 -0
  10. package/node_modules/@vellumai/service-contracts/package.json +1 -0
  11. package/node_modules/@vellumai/service-contracts/src/__tests__/redacted-credential.test.ts +200 -0
  12. package/node_modules/@vellumai/service-contracts/src/redacted-credential.ts +226 -0
  13. package/openapi.yaml +530 -107
  14. package/package.json +1 -1
  15. package/scripts/generate-openapi.ts +8 -0
  16. package/src/__tests__/activation-early-marking.test.ts +6 -5
  17. package/src/__tests__/agent-loop-override-profile.test.ts +22 -25
  18. package/src/__tests__/agent-wake-override-profile.test.ts +21 -48
  19. package/src/__tests__/app-builder-tool-scripts.test.ts +0 -1
  20. package/src/__tests__/app-bundler.test.ts +4 -12
  21. package/src/__tests__/app-executors.test.ts +2 -49
  22. package/src/__tests__/app-routes-csp.test.ts +114 -146
  23. package/src/__tests__/auth-fallback-events-store.test.ts +8 -1
  24. package/src/__tests__/build-persisted-content.test.ts +96 -0
  25. package/src/__tests__/bundle-scanner.test.ts +27 -1
  26. package/src/__tests__/call-controller.test.ts +291 -0
  27. package/src/__tests__/call-site-routing-connection-auto-resolve.test.ts +165 -0
  28. package/src/__tests__/chat-credential-redaction.test.ts +1395 -0
  29. package/src/__tests__/chat-reveal-guard-priming.test.ts +791 -0
  30. package/src/__tests__/compaction.benchmark.test.ts +2 -1
  31. package/src/__tests__/compactor-image-manifest-trust.test.ts +50 -0
  32. package/src/__tests__/config-loader-backfill.test.ts +9 -4
  33. package/src/__tests__/config-schema-cmd.test.ts +10 -11
  34. package/src/__tests__/config-schema.test.ts +190 -257
  35. package/src/__tests__/conversation-agent-loop-fatal-cleanup.test.ts +208 -0
  36. package/src/__tests__/conversation-agent-loop-overflow.test.ts +5 -19
  37. package/src/__tests__/conversation-agent-loop.test.ts +22 -9
  38. package/src/__tests__/conversation-error.test.ts +31 -0
  39. package/src/__tests__/conversation-load-history-repair.test.ts +110 -0
  40. package/src/__tests__/conversation-process-callsite.test.ts +12 -19
  41. package/src/__tests__/conversation-routes-slash-commands.test.ts +7 -21
  42. package/src/__tests__/conversation-summarize-route.test.ts +36 -44
  43. package/src/__tests__/conversation-surfaces-action-delivery.test.ts +1 -0
  44. package/src/__tests__/conversation-surfaces-activation-emit.test.ts +7 -7
  45. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +0 -1
  46. package/src/__tests__/conversation-tool-setup-attribution.test.ts +0 -1
  47. package/src/__tests__/conversation-usage.test.ts +4 -12
  48. package/src/__tests__/credential-routes.test.ts +250 -0
  49. package/src/__tests__/credential-security-invariants.test.ts +3 -0
  50. package/src/__tests__/db-migration-rollback.test.ts +22 -0
  51. package/src/__tests__/empty-response-hook.test.ts +186 -1
  52. package/src/__tests__/external-plugin-loader.test.ts +11 -5
  53. package/src/__tests__/heartbeat-service.test.ts +0 -28
  54. package/src/__tests__/host-shell-tool.test.ts +2 -0
  55. package/src/__tests__/inactive-tool-error-messages.test.ts +2 -2
  56. package/src/__tests__/inference-no-mode-boot-e2e.test.ts +52 -8
  57. package/src/__tests__/internal-telemetry-routes.test.ts +23 -4
  58. package/src/__tests__/invite-routes-http.test.ts +12 -16
  59. package/src/__tests__/list-all-apps.test.ts +0 -4
  60. package/src/__tests__/llm-context-resolution.test.ts +32 -56
  61. package/src/__tests__/llm-request-log-turn-query.test.ts +109 -0
  62. package/src/__tests__/llm-resolver-override-or-default.test.ts +3 -52
  63. package/src/__tests__/llm-resolver.test.ts +342 -602
  64. package/src/__tests__/llm-schema.test.ts +79 -37
  65. package/src/__tests__/max-tokens-continue-hook.test.ts +19 -0
  66. package/src/__tests__/media-stream-output.test.ts +259 -3
  67. package/src/__tests__/media-stream-server-integration.test.ts +22 -1
  68. package/src/__tests__/media-stream-stt-session.test.ts +47 -0
  69. package/src/__tests__/memory-jobs-worker-cleanup-cadence.test.ts +33 -0
  70. package/src/__tests__/memory-recall-log-store.test.ts +47 -13
  71. package/src/__tests__/mock-gateway-ipc.ts +46 -1
  72. package/src/__tests__/mtime-cache.test.ts +61 -0
  73. package/src/__tests__/navigate-settings-tab.test.ts +2 -0
  74. package/src/__tests__/normalize-onboarding.test.ts +33 -0
  75. package/src/__tests__/onboarding-persona-write.test.ts +26 -0
  76. package/src/__tests__/plugin-api-resolve-credential.test.ts +140 -0
  77. package/src/__tests__/plugin-app-serve-routes.test.ts +166 -14
  78. package/src/__tests__/plugin-import-boundary-reverse-guard.test.ts +2 -0
  79. package/src/__tests__/post-turn-tool-result-truncation.test.ts +38 -0
  80. package/src/__tests__/provider-commit-message-generator.test.ts +27 -20
  81. package/src/__tests__/provider-connections-backfill.test.ts +138 -0
  82. package/src/__tests__/provider-platform-proxy-integration.test.ts +10 -31
  83. package/src/__tests__/provider-registry-ollama.test.ts +8 -18
  84. package/src/__tests__/provider-send-message-override-profile.test.ts +23 -23
  85. package/src/__tests__/provider-usage-tracking.test.ts +9 -19
  86. package/src/__tests__/prune-old-conversations-job.test.ts +12 -0
  87. package/src/__tests__/published-app-updater.test.ts +22 -16
  88. package/src/__tests__/registry.test.ts +5 -16
  89. package/src/__tests__/retry-openrouter-only-normalization.test.ts +22 -23
  90. package/src/__tests__/retry-thinking-adaptive-only.test.ts +43 -48
  91. package/src/__tests__/retry-thinking-tool-choice.test.ts +57 -66
  92. package/src/__tests__/retry-verbosity-normalization.test.ts +24 -23
  93. package/src/__tests__/reveal-success-registry.test.ts +123 -0
  94. package/src/__tests__/run-conversation-turn-persistence.test.ts +130 -0
  95. package/src/__tests__/secret-fixtures.ts +9 -0
  96. package/src/__tests__/server-history-render.test.ts +28 -0
  97. package/src/__tests__/skills.test.ts +9 -4
  98. package/src/__tests__/slack-share-routes.test.ts +0 -1
  99. package/src/__tests__/stt-stream-session.test.ts +6 -5
  100. package/src/__tests__/subagent-call-site-routing.test.ts +69 -95
  101. package/src/__tests__/subagent-disposal.test.ts +2 -0
  102. package/src/__tests__/subagent-fork-notifications.test.ts +2 -0
  103. package/src/__tests__/subagent-fork-spawn.test.ts +2 -0
  104. package/src/__tests__/subagent-manager-notify.test.ts +2 -0
  105. package/src/__tests__/subagent-role-registry.test.ts +37 -0
  106. package/src/__tests__/subagent-spawn-and-await.test.ts +1 -0
  107. package/src/__tests__/subagent-terminal-message.test.ts +50 -0
  108. package/src/__tests__/subagent-tool-gate-mode.test.ts +78 -5
  109. package/src/__tests__/surface-completion-nudge-hook.test.ts +19 -0
  110. package/src/__tests__/telemetry-routes.test.ts +99 -19
  111. package/src/__tests__/tool-audit.test.ts +34 -4
  112. package/src/__tests__/tool-executor-lifecycle-events.test.ts +1 -1
  113. package/src/__tests__/tool-profiler.test.ts +72 -1
  114. package/src/__tests__/tool-result-spool.test.ts +49 -4
  115. package/src/__tests__/tool-side-effects-slack-dm.test.ts +0 -1
  116. package/src/__tests__/ui-channel-variants.test.ts +108 -0
  117. package/src/__tests__/ui-shape-teaching.test.ts +255 -0
  118. package/src/__tests__/usage-attribution.test.ts +18 -41
  119. package/src/__tests__/user-plugin-loader.test.ts +4 -4
  120. package/src/__tests__/voice-config-update.test.ts +46 -0
  121. package/src/__tests__/voice-session-bridge.test.ts +216 -84
  122. package/src/__tests__/workspace-migration-131-drop-web-fetch-mode.test.ts +120 -0
  123. package/src/agent/loop.ts +4 -3
  124. package/src/api/events/open-conversation.test.ts +64 -0
  125. package/src/api/events/open-conversation.ts +33 -0
  126. package/src/api/index.ts +6 -0
  127. package/src/api/responses/conversation-message.ts +5 -0
  128. package/src/apps/app-store.ts +25 -35
  129. package/src/bundler/app-bundler.ts +34 -48
  130. package/src/bundler/app-compiler.ts +39 -4
  131. package/src/bundler/bundle-scanner.ts +13 -0
  132. package/src/bundler/manifest.ts +1 -1
  133. package/src/calls/__tests__/voice-session-bridge.test.ts +47 -0
  134. package/src/calls/call-constants.ts +5 -0
  135. package/src/calls/call-controller.ts +100 -32
  136. package/src/calls/call-transport.ts +9 -0
  137. package/src/calls/media-stream-output.ts +107 -4
  138. package/src/calls/media-stream-server.ts +29 -9
  139. package/src/calls/media-stream-stt-session.ts +7 -1
  140. package/src/calls/media-turn-detector.ts +11 -1
  141. package/src/calls/voice-session-bridge.ts +84 -63
  142. package/src/cli/commands/__tests__/inference-providers.test.ts +270 -33
  143. package/src/cli/commands/__tests__/notifications.test.ts +24 -3
  144. package/src/cli/commands/config.help.ts +6 -6
  145. package/src/cli/commands/credentials.help.ts +13 -0
  146. package/src/cli/commands/credentials.ts +6 -1
  147. package/src/cli/commands/email.help.ts +7 -0
  148. package/src/cli/commands/email.ts +35 -1
  149. package/src/cli/commands/inference-providers.ts +168 -107
  150. package/src/cli/commands/inference.help.ts +118 -46
  151. package/src/cli/commands/memory/index.help.ts +23 -0
  152. package/src/cli/commands/memory/nodes.ts +146 -0
  153. package/src/cli/commands/notifications.help.ts +10 -10
  154. package/src/cli/commands/oauth/connect-surface-guidance.test.ts +40 -0
  155. package/src/cli/commands/oauth/connect-surface-guidance.ts +54 -0
  156. package/src/cli/commands/oauth/connect.test.ts +126 -0
  157. package/src/cli/commands/oauth/connect.ts +29 -6
  158. package/src/cli/commands/oauth/index.help.ts +7 -1
  159. package/src/cli/commands/oauth/status.test.ts +69 -3
  160. package/src/cli/commands/oauth/status.ts +50 -12
  161. package/src/cli/commands/plugins.help.ts +13 -2
  162. package/src/cli/commands/plugins.ts +61 -7
  163. package/src/cli/commands/telemetry.help.ts +13 -0
  164. package/src/cli/commands/telemetry.ts +45 -5
  165. package/src/cli/lib/__tests__/plugin-catalog-local.test.ts +8 -2
  166. package/src/cli/lib/__tests__/upgrade-plugin.test.ts +213 -9
  167. package/src/cli/lib/bundled-marketplace.json +93 -36
  168. package/src/cli/lib/inspect-plugin.ts +5 -1
  169. package/src/cli/lib/install-from-github.ts +68 -4
  170. package/src/cli/lib/plugin-catalog-local.ts +6 -2
  171. package/src/cli/lib/plugin-fingerprint.ts +3 -3
  172. package/src/cli/lib/upgrade-plugin.ts +236 -35
  173. package/src/config/__tests__/default-profile-catalog.test.ts +8 -12
  174. package/src/config/__tests__/plugin-resident-skill-discovery.test.ts +137 -0
  175. package/src/config/__tests__/profile-materialization.test.ts +1 -88
  176. package/src/config/bundled-skills/AGENTS.md +3 -30
  177. package/src/config/bundled-skills/app-builder/SKILL.md +5 -3
  178. package/src/config/bundled-skills/app-builder/TOOLS.json +23 -0
  179. package/src/config/bundled-skills/app-builder/tools/app-open.ts +32 -0
  180. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +1 -1
  181. package/src/config/bundled-skills/phone-calls/references/CONFIG.md +7 -7
  182. package/src/config/bundled-skills/schedule/SKILL.md +1 -1
  183. package/src/config/bundled-skills/schedule/TOOLS.json +1 -1
  184. package/src/config/bundled-skills/settings/TOOLS.json +3 -1
  185. package/src/config/bundled-skills/settings/tools/navigate-settings-tab.ts +2 -0
  186. package/src/config/bundled-skills/settings/tools/voice-config-update.ts +18 -10
  187. package/src/config/bundled-skills/subagent/SKILL.md +2 -0
  188. package/src/config/bundled-skills/subagent/TOOLS.json +1 -1
  189. package/src/config/call-site-defaults.ts +3 -3
  190. package/src/config/feature-flag-registry.json +24 -39
  191. package/src/config/llm-resolver.ts +88 -475
  192. package/src/config/profile-materialization.ts +11 -11
  193. package/src/config/schema.ts +93 -127
  194. package/src/config/schemas/__tests__/live-voice.test.ts +24 -6
  195. package/src/config/schemas/__tests__/stt.test.ts +31 -3
  196. package/src/config/schemas/live-voice.ts +10 -4
  197. package/src/config/schemas/llm.ts +52 -15
  198. package/src/config/schemas/memory-lifecycle.ts +1 -1
  199. package/src/config/schemas/memory-retrospective.ts +8 -0
  200. package/src/config/schemas/memory-v2.ts +2 -2
  201. package/src/config/schemas/memory-v3.ts +1 -1
  202. package/src/config/schemas/services.ts +6 -3
  203. package/src/config/schemas/stt.ts +38 -21
  204. package/src/config/schemas/tts.ts +13 -18
  205. package/src/config/skills.ts +31 -21
  206. package/src/context/compactor.ts +44 -7
  207. package/src/context/post-turn-tool-result-truncation.ts +4 -2
  208. package/src/context/tool-result-spool.ts +26 -5
  209. package/src/conversations/__tests__/message-consolidation.test.ts +48 -0
  210. package/src/conversations/message-consolidation.ts +22 -2
  211. package/src/daemon/__tests__/conversation-tool-setup.test.ts +5 -12
  212. package/src/daemon/app-source-watcher.ts +17 -23
  213. package/src/daemon/chat-credential-redaction.ts +1365 -0
  214. package/src/daemon/conversation-agent-loop-handlers.ts +627 -34
  215. package/src/daemon/conversation-agent-loop.ts +71 -31
  216. package/src/daemon/conversation-error.ts +36 -14
  217. package/src/daemon/conversation-process.ts +22 -0
  218. package/src/daemon/conversation-store.ts +35 -0
  219. package/src/daemon/conversation-surfaces.ts +25 -25
  220. package/src/daemon/conversation-tool-setup.ts +33 -7
  221. package/src/daemon/conversation.ts +55 -5
  222. package/src/daemon/handlers/shared.ts +33 -2
  223. package/src/daemon/lifecycle.ts +4 -4
  224. package/src/daemon/message-types/conversations.ts +6 -17
  225. package/src/daemon/providers-setup.ts +8 -0
  226. package/src/daemon/tool-setup-types.ts +7 -1
  227. package/src/daemon/wake-conversation-ops.ts +10 -1
  228. package/src/hooks/types.ts +9 -0
  229. package/src/ipc/__tests__/email-ipc.test.ts +90 -0
  230. package/src/ipc/gateway-client.test.ts +59 -0
  231. package/src/ipc/gateway-client.ts +70 -27
  232. package/src/live-voice/__tests__/live-voice-events.test.ts +14 -2
  233. package/src/live-voice/__tests__/live-voice-integration.test.ts +116 -2
  234. package/src/live-voice/__tests__/live-voice-vad.test.ts +804 -13
  235. package/src/live-voice/__tests__/protocol.test.ts +122 -0
  236. package/src/live-voice/live-voice-session.ts +443 -40
  237. package/src/live-voice/protocol.ts +143 -1
  238. package/src/monitoring/__tests__/plugin-source-watch.test.ts +3 -1
  239. package/src/monitoring/plugin-source-watch.ts +3 -62
  240. package/src/notifications/README.md +1 -1
  241. package/src/permissions/checker.ts +8 -4
  242. package/src/persistence/__tests__/db-init-migrations-ok.test.ts +26 -0
  243. package/src/persistence/conversation-crud.ts +104 -2
  244. package/src/persistence/db-init.ts +14 -3
  245. package/src/persistence/job-handlers/cleanup.ts +15 -7
  246. package/src/persistence/llm-request-log-store.ts +88 -52
  247. package/src/persistence/migrations/298-move-memory-jobs-to-memory-db.ts +7 -31
  248. package/src/persistence/migrations/305-drop-contact-acl-columns.ts +3 -2
  249. package/src/persistence/migrations/326-move-injection-events-to-memory-db.ts +8 -34
  250. package/src/persistence/migrations/336-move-memory-v2-activation-logs-to-memory-db.ts +90 -0
  251. package/src/persistence/migrations/337-move-memory-recall-logs-to-memory-db.ts +114 -0
  252. package/src/persistence/migrations/338-move-memory-v3-selections-to-memory-db.ts +84 -0
  253. package/src/persistence/migrations/339-move-activation-sessions-to-memory-db.ts +52 -0
  254. package/src/persistence/migrations/__tests__/run-migrations.test.ts +155 -0
  255. package/src/persistence/migrations/helpers/relocation.ts +44 -1
  256. package/src/persistence/migrations/run-migrations.ts +25 -1
  257. package/src/persistence/schema/infrastructure.ts +9 -0
  258. package/src/persistence/schema/memory-core.ts +3 -0
  259. package/src/persistence/schema/memory-injection.ts +2 -0
  260. package/src/persistence/steps.ts +36 -0
  261. package/src/platform/client.test.ts +1 -44
  262. package/src/platform/client.ts +10 -20
  263. package/src/platform/consent-cache.test.ts +89 -23
  264. package/src/platform/consent-cache.ts +71 -33
  265. package/src/plugin-api/constants.ts +12 -0
  266. package/src/plugin-api/conversation-turn.ts +37 -14
  267. package/src/plugin-api/index.ts +11 -1
  268. package/src/plugin-api/resolve-credential.ts +75 -0
  269. package/src/plugin-api/vision-support.test.ts +8 -19
  270. package/src/plugin-api/vision-support.ts +26 -17
  271. package/src/plugins/collect-source-versions.ts +77 -0
  272. package/src/plugins/defaults/compaction/compact.ts +6 -0
  273. package/src/plugins/defaults/compaction/window-manager.ts +9 -0
  274. package/src/plugins/defaults/empty-response/hooks/post-model-call.ts +18 -24
  275. package/src/plugins/defaults/empty-response/hooks/user-prompt-submit.ts +38 -0
  276. package/src/plugins/defaults/empty-response/refusal-quarantine.ts +99 -0
  277. package/src/plugins/defaults/image-fallback/__tests__/caption-cache-persistence.test.ts +7 -3
  278. package/src/plugins/defaults/index.ts +8 -1
  279. package/src/plugins/defaults/max-tokens-continue/hooks/post-model-call.ts +4 -1
  280. package/src/plugins/defaults/memory/__tests__/activation-session-store.test.ts +48 -6
  281. package/src/plugins/defaults/memory/__tests__/db-memory-attach.test.ts +28 -22
  282. package/src/plugins/defaults/memory/__tests__/memory-log-stores-degraded.test.ts +148 -0
  283. package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +80 -8
  284. package/src/plugins/defaults/memory/__tests__/memory-retrospective-prompt.test.ts +202 -0
  285. package/src/plugins/defaults/memory/__tests__/memory-v2-activation-log-store.test.ts +64 -25
  286. package/src/plugins/defaults/memory/__tests__/memory-v2-concept-frequency.test.ts +24 -11
  287. package/src/plugins/defaults/memory/__tests__/prompt-override.test.ts +70 -6
  288. package/src/plugins/defaults/memory/__tests__/table-relocation.test.ts +278 -0
  289. package/src/plugins/defaults/memory/activation-session-store.ts +27 -20
  290. package/src/plugins/defaults/memory/context-search/sources/memory-v2.ts +2 -9
  291. package/src/plugins/defaults/memory/context-search/sources/workspace.ts +1 -8
  292. package/src/plugins/defaults/memory/graph/retriever.test.ts +6 -6
  293. package/src/plugins/defaults/memory/graph/store.ts +114 -0
  294. package/src/plugins/defaults/memory/graph/tool-handlers.ts +36 -1
  295. package/src/plugins/defaults/memory/graph/tools.ts +47 -13
  296. package/src/plugins/defaults/memory/graph-topology/build-memory-graph.ts +16 -35
  297. package/src/plugins/defaults/memory/jobs-worker.ts +10 -1
  298. package/src/plugins/defaults/memory/memory-db.ts +3 -2
  299. package/src/plugins/defaults/memory/memory-recall-log-store.ts +129 -66
  300. package/src/plugins/defaults/memory/memory-retrospective-constants.ts +8 -0
  301. package/src/plugins/defaults/memory/memory-retrospective-job.ts +11 -122
  302. package/src/plugins/defaults/memory/memory-retrospective-prompt.ts +216 -0
  303. package/src/plugins/defaults/memory/memory-v2-activation-log-store.ts +84 -46
  304. package/src/plugins/defaults/memory/memory-v2-concept-frequency.ts +42 -32
  305. package/src/plugins/defaults/memory/path-containment.ts +21 -0
  306. package/src/plugins/defaults/memory/prompt-override.ts +51 -13
  307. package/src/plugins/defaults/memory/tools.test.ts +34 -0
  308. package/src/plugins/defaults/memory/tools.ts +12 -2
  309. package/src/plugins/defaults/memory/v2/__tests__/harness-compare.test.ts +19 -15
  310. package/src/plugins/defaults/memory/v2/__tests__/harness-oracle.test.ts +24 -19
  311. package/src/plugins/defaults/memory/v2/__tests__/harness-replay-input.test.ts +19 -15
  312. package/src/plugins/defaults/memory/v2/__tests__/injection.test.ts +22 -2
  313. package/src/plugins/defaults/memory/v2/__tests__/prompts-consolidation.test.ts +5 -3
  314. package/src/plugins/defaults/memory/v2/harness/oracle.ts +59 -41
  315. package/src/plugins/defaults/memory/v2/harness/replay-input.ts +29 -25
  316. package/src/plugins/defaults/memory/v2/migration.ts +46 -16
  317. package/src/plugins/defaults/memory/v2/prompts/consolidation.ts +4 -0
  318. package/src/plugins/defaults/memory/v3/__tests__/carry-integration.test.ts +17 -15
  319. package/src/plugins/defaults/memory/v3/__tests__/gate.test.ts +24 -22
  320. package/src/plugins/defaults/memory/v3/__tests__/injection.test.ts +9 -5
  321. package/src/plugins/defaults/memory/v3/__tests__/orchestrate.test.ts +277 -10
  322. package/src/plugins/defaults/memory/v3/__tests__/selection-log-store.test.ts +57 -5
  323. package/src/plugins/defaults/memory/v3/__tests__/shadow-integration.test.ts +9 -7
  324. package/src/plugins/defaults/memory/v3/__tests__/shadow-plugin.test.ts +38 -7
  325. package/src/plugins/defaults/memory/v3/hot-set.test.ts +36 -18
  326. package/src/plugins/defaults/memory/v3/hot-set.ts +12 -14
  327. package/src/plugins/defaults/memory/v3/learned-edges.test.ts +47 -27
  328. package/src/plugins/defaults/memory/v3/learned-edges.ts +12 -14
  329. package/src/plugins/defaults/memory/v3/orchestrate.ts +139 -22
  330. package/src/plugins/defaults/memory/v3/prune.test.ts +10 -3
  331. package/src/plugins/defaults/memory/v3/prune.ts +17 -11
  332. package/src/plugins/defaults/memory/v3/selection-log-store.ts +23 -11
  333. package/src/plugins/defaults/memory/v3/shadow-plugin.ts +70 -53
  334. package/src/plugins/defaults/surface-completion-nudge/hooks/post-model-call.ts +9 -6
  335. package/src/plugins/external-plugin-loader.ts +15 -15
  336. package/src/plugins/mtime-cache.ts +47 -0
  337. package/src/plugins/pipeline.ts +9 -1
  338. package/src/plugins/plugin-execution-context.ts +44 -0
  339. package/src/plugins/plugin-tree-walk.ts +31 -24
  340. package/src/plugins/source-fingerprint.ts +3 -4
  341. package/src/prompts/normalize-onboarding.ts +12 -0
  342. package/src/prompts/persona-resolver.ts +8 -0
  343. package/src/prompts/templates/BOOTSTRAP-ACTIVATION-RAIL.md +1 -1
  344. package/src/providers/__tests__/dispatch-connection-routing.test.ts +6 -9
  345. package/src/providers/__tests__/registry-native-web-search.test.ts +4 -10
  346. package/src/providers/__tests__/retry-callsite.test.ts +235 -215
  347. package/src/providers/__tests__/satellite-connection-routing.test.ts +8 -16
  348. package/src/providers/atlascloud/client.ts +10 -49
  349. package/src/providers/baseten/client.ts +43 -0
  350. package/src/providers/call-site-routing.ts +26 -13
  351. package/src/providers/connection-resolution.ts +9 -11
  352. package/src/providers/fetch-provider-catalog.ts +4 -2
  353. package/src/providers/inference/__tests__/adapter-factory-openai-compatible.test.ts +29 -4
  354. package/src/providers/inference/__tests__/connection-availability-keyless.test.ts +78 -0
  355. package/src/providers/inference/adapter-factory.ts +27 -6
  356. package/src/providers/inference/auth.ts +29 -1
  357. package/src/providers/inference/backfill.ts +61 -10
  358. package/src/providers/inference/connection-availability.ts +3 -2
  359. package/src/providers/inference/resolve-auth.ts +9 -1
  360. package/src/providers/model-catalog.ts +37 -0
  361. package/src/providers/openai/__tests__/api-error-normalization.test.ts +24 -2
  362. package/src/providers/openai/api-key-validation.ts +70 -0
  363. package/src/providers/retry.ts +2 -0
  364. package/src/providers/types.ts +11 -4
  365. package/src/providers/vellum-model-routing.test.ts +26 -0
  366. package/src/providers/vellum-model-routing.ts +30 -0
  367. package/src/providers/voice-error-copy.ts +47 -0
  368. package/src/runtime/agent-wake.ts +40 -24
  369. package/src/runtime/for-chat-mint-registry.ts +118 -0
  370. package/src/runtime/reveal-nonce.ts +49 -0
  371. package/src/runtime/reveal-success-registry.ts +306 -0
  372. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +88 -3
  373. package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +161 -30
  374. package/src/runtime/routes/__tests__/migration-vellum-metadata-reconcile.test.ts +7 -0
  375. package/src/runtime/routes/__tests__/schedule-worker-routes.test.ts +15 -0
  376. package/src/runtime/routes/app-management-routes.ts +152 -45
  377. package/src/runtime/routes/app-routes.ts +16 -77
  378. package/src/runtime/routes/canned-message-complete.ts +16 -16
  379. package/src/runtime/routes/conversation-management-routes.ts +17 -14
  380. package/src/runtime/routes/conversation-query-routes.ts +54 -6
  381. package/src/runtime/routes/conversation-routes.ts +48 -2
  382. package/src/runtime/routes/credential-routes.ts +116 -3
  383. package/src/runtime/routes/email-routes.ts +17 -1
  384. package/src/runtime/routes/inbound-stages/transcribe-audio.test.ts +33 -5
  385. package/src/runtime/routes/inbound-stages/transcribe-audio.ts +6 -5
  386. package/src/runtime/routes/inference-provider-connection-routes.ts +77 -28
  387. package/src/runtime/routes/inference-send-routes.ts +1 -1
  388. package/src/runtime/routes/internal-telemetry-routes.ts +7 -6
  389. package/src/runtime/routes/plugins-routes.ts +37 -6
  390. package/src/runtime/routes/publish-routes.ts +15 -18
  391. package/src/runtime/routes/schedule-worker-routes.ts +9 -0
  392. package/src/runtime/routes/secret-routes.ts +10 -0
  393. package/src/runtime/routes/telemetry-routes.ts +149 -45
  394. package/src/schedule/__tests__/schedule-timezone.test.ts +101 -0
  395. package/src/schedule/__tests__/worker-watchdog.test.ts +209 -0
  396. package/src/schedule/schedule-store.ts +12 -1
  397. package/src/schedule/schedule-timezone.ts +63 -0
  398. package/src/schedule/scheduler.ts +100 -6
  399. package/src/schedule/worker-control.ts +19 -0
  400. package/src/security/auth-fallback-events-store.ts +7 -6
  401. package/src/security/secret-scanner.ts +26 -1
  402. package/src/services/published-app-updater.ts +6 -11
  403. package/src/stt/stt-stream-session.ts +36 -16
  404. package/src/subagent/manager.ts +34 -8
  405. package/src/telemetry/AGENTS.md +30 -1
  406. package/src/telemetry/__tests__/config-setting-snapshot.test.ts +18 -0
  407. package/src/telemetry/__tests__/outbox-test-harness.ts +5 -3
  408. package/src/telemetry/config-setting-snapshot.ts +44 -10
  409. package/src/telemetry/telemetry-event-sources.test.ts +124 -30
  410. package/src/telemetry/telemetry-event-sources.ts +137 -83
  411. package/src/telemetry/telemetry-events-outbox.test.ts +46 -1
  412. package/src/telemetry/telemetry-events-outbox.ts +60 -9
  413. package/src/telemetry/telemetry-wire-source.json +1 -1
  414. package/src/telemetry/telemetry-wire-validation.ts +39 -2
  415. package/src/telemetry/telemetry-wire.generated.ts +8 -0
  416. package/src/telemetry/tool-audit.ts +15 -9
  417. package/src/telemetry/tool-executed-events-store.test.ts +1 -1
  418. package/src/telemetry/turn-events-store.ts +20 -0
  419. package/src/telemetry/types.ts +45 -12
  420. package/src/telemetry/usage-telemetry-reporter.test.ts +294 -25
  421. package/src/telemetry/usage-telemetry-reporter.ts +117 -18
  422. package/src/telemetry/watchdog-direct-emit.test.ts +11 -3
  423. package/src/telemetry/watchdog-direct-emit.ts +11 -6
  424. package/src/tools/apps/executors.ts +11 -36
  425. package/src/tools/executor.ts +14 -1
  426. package/src/tools/host-terminal/host-shell.ts +6 -2
  427. package/src/tools/network/__tests__/web-fetch-firecrawl.test.ts +1 -1
  428. package/src/tools/network/__tests__/web-fetch-metadata.test.ts +25 -0
  429. package/src/tools/network/web-fetch.ts +6 -2
  430. package/src/tools/skills/sandbox-runner.ts +5 -2
  431. package/src/tools/subagent/spawn.ts +7 -11
  432. package/src/tools/terminal/shell.ts +5 -2
  433. package/src/tools/tool-manifest.ts +0 -2
  434. package/src/tools/tool-profiler.ts +37 -6
  435. package/src/tools/ui-surface/channel-variants.ts +101 -0
  436. package/src/tools/ui-surface/definitions.ts +23 -67
  437. package/src/tools/ui-surface/surface-shape-docs.ts +229 -0
  438. package/src/tts/__tests__/provider-adapters.test.ts +18 -0
  439. package/src/tts/provider-catalog.ts +2 -4
  440. package/src/tts/providers/deepgram-provider.ts +10 -1
  441. package/src/types/onboarding-context.ts +8 -0
  442. package/src/usage/attribution.ts +18 -112
  443. package/src/{config/bundled-skills/messaging/tools/gmail-mime-helpers.ts → util/mime-type.ts} +4 -1
  444. package/src/util/provider-error-patterns.ts +7 -1
  445. package/src/util/worker-process.ts +105 -0
  446. package/src/watcher/__tests__/telemetry.test.ts +17 -4
  447. package/src/watcher/telemetry.ts +5 -5
  448. package/src/workspace/migrations/131-drop-web-fetch-mode.ts +61 -0
  449. package/src/workspace/migrations/registry.ts +2 -0
  450. package/src/workspace/provider-commit-message-generator.ts +6 -4
  451. package/src/__tests__/app-open-proxy.test.ts +0 -67
  452. package/src/onboarding/onboarding-research-events-store.test.ts +0 -230
  453. package/src/onboarding/onboarding-research-events-store.ts +0 -104
  454. package/src/runtime/routes/assets/vellum-design-system.css +0 -2236
  455. package/src/tools/apps/definitions.ts +0 -73
  456. package/src/tools/apps/open-proxy.ts +0 -43
@@ -1,2236 +0,0 @@
1
- /* ============================================================
2
- Vellum Design System — CSS Tokens & Components
3
- Translated from SwiftUI DesignSystem (ColorTokens, VColor,
4
- VSpacing, VRadius, VShadow, VAnimation, VFont)
5
- ============================================================
6
- Wrapped in @layer so app-authored CSS always wins (un-layered
7
- styles beat layered styles regardless of specificity/order).
8
- ============================================================ */
9
-
10
- @layer vellum-design-system {
11
- /* ─── Reset ──────────────────────────────────────────────────── */
12
-
13
- *,
14
- *::before,
15
- *::after {
16
- box-sizing: border-box;
17
- }
18
-
19
- /* ─── Layer 1: Tokens ────────────────────────────────────────── */
20
-
21
- :root {
22
- /* ── Semantic Colors (Light Mode — default) ─────────────────── */
23
- --v-primary-disabled: #d4d1c1;
24
- --v-primary-base: #516748;
25
- --v-primary-hover: #657d5b;
26
- --v-primary-active: #7a8b6f;
27
- --v-surface-base: #e8e6da;
28
- --v-surface-overlay: #f5f3eb;
29
- --v-surface-active: #d4d1c1;
30
- --v-surface-lift: #ffffff;
31
- --v-border-disabled: #d4d1c1;
32
- --v-border-base: #bdb9a9;
33
- --v-border-hover: #a1a096;
34
- --v-border-active: #7a8b6f;
35
- --v-content-emphasized: #20201e;
36
- --v-content-default: #2a2a28;
37
- --v-content-secondary: #4a4a46;
38
- --v-content-tertiary: #a1a096;
39
- --v-content-disabled: #bdb9a9;
40
- --v-content-background: #d4d1c1;
41
- --v-content-inset: #ffffff;
42
- --v-system-positive-strong: #516748;
43
- --v-system-positive-weak: #d4dfd0;
44
- --v-system-negative-strong: #da491a;
45
- --v-system-negative-hover: #e86b40;
46
- --v-system-negative-weak: #f7dac9;
47
- --v-system-mid-strong: #f1b21e;
48
- --v-system-mid-weak: #fcf3dd;
49
- --v-aux-white: #ffffff;
50
-
51
- /* ── Shorthand Aliases (referenced by app-builder SKILL.md) ── */
52
- --v-bg: var(--v-surface-overlay);
53
- --v-surface: var(--v-surface-base);
54
- --v-surface-border: var(--v-border-base);
55
- --v-text: var(--v-content-default);
56
- --v-text-secondary: var(--v-content-secondary);
57
- --v-text-muted: var(--v-content-tertiary);
58
- --v-accent: var(--v-primary-base);
59
- --v-accent-hover: var(--v-primary-hover);
60
- --v-success: var(--v-system-positive-strong);
61
- --v-danger: var(--v-system-negative-strong);
62
- --v-warning: var(--v-system-mid-strong);
63
-
64
- /* ── Palette Scales (Tailwind-style, referenced by SKILL.md) ─ */
65
- --v-slate-50: #f8fafc;
66
- --v-slate-100: #f1f5f9;
67
- --v-slate-200: #e2e8f0;
68
- --v-slate-300: #cbd5e1;
69
- --v-slate-400: #94a3b8;
70
- --v-slate-500: #64748b;
71
- --v-slate-600: #475569;
72
- --v-slate-700: #334155;
73
- --v-slate-800: #1e293b;
74
- --v-slate-900: #0f172a;
75
- --v-slate-950: #020617;
76
- --v-emerald-50: #ecfdf5;
77
- --v-emerald-100: #d1fae5;
78
- --v-emerald-200: #a7f3d0;
79
- --v-emerald-300: #6ee7b7;
80
- --v-emerald-400: #34d399;
81
- --v-emerald-500: #10b981;
82
- --v-emerald-600: #059669;
83
- --v-emerald-700: #047857;
84
- --v-emerald-800: #065f46;
85
- --v-emerald-900: #064e3b;
86
- --v-emerald-950: #022c22;
87
- --v-violet-50: #f5f3ff;
88
- --v-violet-100: #ede9fe;
89
- --v-violet-200: #ddd6fe;
90
- --v-violet-300: #c4b5fd;
91
- --v-violet-400: #a78bfa;
92
- --v-violet-500: #8b5cf6;
93
- --v-violet-600: #7c3aed;
94
- --v-violet-700: #6d28d9;
95
- --v-violet-800: #5b21b6;
96
- --v-violet-900: #4c1d95;
97
- --v-violet-950: #2e1065;
98
- --v-indigo-50: #eef2ff;
99
- --v-indigo-100: #e0e7ff;
100
- --v-indigo-200: #c7d2fe;
101
- --v-indigo-300: #a5b4fc;
102
- --v-indigo-400: #818cf8;
103
- --v-indigo-500: #6366f1;
104
- --v-indigo-600: #4f46e5;
105
- --v-indigo-700: #4338ca;
106
- --v-indigo-800: #3730a3;
107
- --v-indigo-900: #312e81;
108
- --v-indigo-950: #1e1b4b;
109
- --v-rose-50: #fff1f2;
110
- --v-rose-100: #ffe4e6;
111
- --v-rose-200: #fecdd3;
112
- --v-rose-300: #fda4af;
113
- --v-rose-400: #fb7185;
114
- --v-rose-500: #f43f5e;
115
- --v-rose-600: #e11d48;
116
- --v-rose-700: #be123c;
117
- --v-rose-800: #9f1239;
118
- --v-rose-900: #881337;
119
- --v-rose-950: #4c0519;
120
- --v-amber-50: #fffbeb;
121
- --v-amber-100: #fef3c7;
122
- --v-amber-200: #fde68a;
123
- --v-amber-300: #fcd34d;
124
- --v-amber-400: #fbbf24;
125
- --v-amber-500: #f59e0b;
126
- --v-amber-600: #d97706;
127
- --v-amber-700: #b45309;
128
- --v-amber-800: #92400e;
129
- --v-amber-900: #78350f;
130
- --v-amber-950: #451a03;
131
-
132
- /* ── Spacing (4pt grid) ─────────────────────────────────────── */
133
- --v-spacing-xxs: 2px;
134
- --v-spacing-xs: 4px;
135
- --v-spacing-sm: 8px;
136
- --v-spacing-md: 12px;
137
- --v-spacing-lg: 16px;
138
- --v-spacing-xl: 24px;
139
- --v-spacing-xxl: 32px;
140
- --v-spacing-xxxl: 48px;
141
-
142
- /* ── Radius ─────────────────────────────────────────────────── */
143
- --v-radius-xs: 2px;
144
- --v-radius-sm: 4px;
145
- --v-radius-md: 8px;
146
- --v-radius-lg: 12px;
147
- --v-radius-xl: 16px;
148
- --v-radius-pill: 999px;
149
-
150
- /* ── Shadows ────────────────────────────────────────────────── */
151
- --v-shadow-sm: 0 2px 4px rgba(0, 0, 0, 0.08);
152
- --v-shadow-md: 0 4px 8px rgba(0, 0, 0, 0.12);
153
- --v-shadow-lg: 0 8px 16px rgba(0, 0, 0, 0.16);
154
-
155
- /* ── Animation ──────────────────────────────────────────────── */
156
- --v-duration-fast: 0.15s;
157
- --v-duration-standard: 0.25s;
158
- --v-duration-slow: 0.4s;
159
-
160
- /* ── Typography ─────────────────────────────────────────────── */
161
- --v-font-family:
162
- -apple-system, BlinkMacSystemFont, "SF Pro Text", "Helvetica Neue",
163
- sans-serif;
164
- --v-font-mono:
165
- "SF Mono", SFMono-Regular, ui-monospace, Menlo, Monaco, monospace;
166
- --v-font-size-xs: 10px;
167
- --v-font-size-sm: 11px;
168
- --v-font-size-base: 14px;
169
- --v-font-size-lg: 17px;
170
- --v-font-size-xl: 22px;
171
- --v-font-size-2xl: 26px;
172
- --v-line-height: 1.5;
173
- }
174
-
175
- /* ── Dark Mode (matches SwiftUI VColor semantic values) ───────── */
176
-
177
- @media (prefers-color-scheme: dark) {
178
- :root {
179
- --v-primary-disabled: #3a3a37;
180
- --v-primary-base: #657d5b;
181
- --v-primary-hover: #516748;
182
- --v-primary-active: #7a8b6f;
183
- --v-surface-base: #2a2a28;
184
- --v-surface-overlay: #20201e;
185
- --v-surface-active: #3a3a37;
186
- --v-surface-lift: #000000;
187
- --v-border-disabled: #3a3a37;
188
- --v-border-base: #4a4a46;
189
- --v-border-hover: #6b6b65;
190
- --v-border-active: #7a8b6f;
191
- --v-content-emphasized: #f5f3eb;
192
- --v-content-default: #e8e6da;
193
- --v-content-secondary: #bdb9a9;
194
- --v-content-tertiary: #a1a096;
195
- --v-content-disabled: #6b6b65;
196
- --v-content-background: #3a3a37;
197
- --v-content-inset: #000000;
198
- --v-system-positive-strong: #516748;
199
- --v-system-positive-weak: #1a2316;
200
- --v-system-negative-strong: #da491a;
201
- --v-system-negative-hover: #ab3f1c;
202
- --v-system-negative-weak: #4e281d;
203
- --v-system-mid-strong: #f1b21e;
204
- --v-system-mid-weak: #4b3d1e;
205
- --v-aux-white: #ffffff;
206
-
207
- --v-shadow-sm: 0 2px 4px rgba(0, 0, 0, 0.3);
208
- --v-shadow-md: 0 4px 8px rgba(0, 0, 0, 0.4);
209
- --v-shadow-lg: 0 8px 16px rgba(0, 0, 0, 0.5);
210
- }
211
- }
212
-
213
- /* ─── Layer 2: Element Defaults ──────────────────────────────── */
214
-
215
- body {
216
- margin: 0;
217
- font-family: var(--v-font-family);
218
- font-size: var(--v-font-size-base);
219
- line-height: var(--v-line-height);
220
- color: var(--v-content-default);
221
- background: var(--v-surface-overlay);
222
- padding: var(--v-spacing-xl);
223
- min-height: 100vh;
224
- display: flex;
225
- flex-direction: column;
226
- align-items: center;
227
- justify-content: center;
228
- -webkit-font-smoothing: antialiased;
229
- }
230
- body > *:not(#vellum-bottom-fade):not(#v-toast-container) {
231
- width: 100%;
232
- }
233
-
234
- @media (prefers-color-scheme: dark) {
235
- body {
236
- background:
237
- radial-gradient(
238
- ellipse at 50% 0%,
239
- var(--v-surface-base) 0%,
240
- transparent 50%
241
- ),
242
- var(--v-surface-overlay);
243
- }
244
- }
245
-
246
- h1,
247
- h2,
248
- h3,
249
- h4,
250
- h5,
251
- h6 {
252
- line-height: 1.2;
253
- margin: 0 0 var(--v-spacing-md) 0;
254
- color: var(--v-content-default);
255
- }
256
-
257
- h1 {
258
- font-size: var(--v-font-size-2xl);
259
- font-weight: 700;
260
- }
261
- h2 {
262
- font-size: var(--v-font-size-xl);
263
- font-weight: 600;
264
- }
265
- h3 {
266
- font-size: var(--v-font-size-lg);
267
- font-weight: 600;
268
- }
269
- h4 {
270
- font-size: var(--v-font-size-base);
271
- font-weight: 600;
272
- }
273
- h5 {
274
- font-size: var(--v-font-size-sm);
275
- font-weight: 600;
276
- text-transform: uppercase;
277
- letter-spacing: 0.05em;
278
- }
279
- h6 {
280
- font-size: var(--v-font-size-xs);
281
- font-weight: 600;
282
- text-transform: uppercase;
283
- letter-spacing: 0.05em;
284
- }
285
-
286
- p {
287
- margin: 0 0 var(--v-spacing-md) 0;
288
- }
289
-
290
- a {
291
- color: var(--v-primary-base);
292
- text-decoration: none;
293
- }
294
- a:hover {
295
- text-decoration: underline;
296
- }
297
-
298
- button {
299
- font-family: var(--v-font-family);
300
- font-size: var(--v-font-size-base);
301
- border: none;
302
- background: none;
303
- cursor: pointer;
304
- color: inherit;
305
- }
306
-
307
- input,
308
- textarea,
309
- select {
310
- font-family: var(--v-font-family);
311
- font-size: var(--v-font-size-base);
312
- padding: var(--v-spacing-sm) var(--v-spacing-md);
313
- background: var(--v-surface-overlay);
314
- color: var(--v-content-default);
315
- border: 1px solid var(--v-border-base);
316
- border-radius: var(--v-radius-md);
317
- outline: none;
318
- transition: border-color var(--v-duration-fast) ease-out;
319
- }
320
- select {
321
- -webkit-appearance: none;
322
- appearance: none;
323
- background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%2386868B' d='M6 8.5L1.5 4h9z'/%3E%3C/svg%3E");
324
- background-repeat: no-repeat;
325
- background-position: right var(--v-spacing-md) center;
326
- padding-right: calc(var(--v-spacing-md) + 20px);
327
- }
328
- input:focus,
329
- textarea:focus,
330
- select:focus {
331
- border-color: var(--v-primary-base);
332
- }
333
-
334
- textarea {
335
- resize: vertical;
336
- }
337
-
338
- code {
339
- font-family: var(--v-font-mono);
340
- font-size: 0.9em;
341
- background: var(--v-surface-base);
342
- padding: var(--v-spacing-xxs) var(--v-spacing-xs);
343
- border-radius: var(--v-radius-sm);
344
- }
345
-
346
- pre {
347
- font-family: var(--v-font-mono);
348
- font-size: var(--v-font-size-sm);
349
- background: var(--v-surface-base);
350
- padding: var(--v-spacing-lg);
351
- border-radius: var(--v-radius-md);
352
- overflow-x: auto;
353
- margin: 0 0 var(--v-spacing-md) 0;
354
- }
355
- pre code {
356
- background: none;
357
- padding: 0;
358
- }
359
-
360
- hr {
361
- border: none;
362
- border-top: 1px solid var(--v-border-base);
363
- margin: var(--v-spacing-xl) 0;
364
- }
365
-
366
- ul,
367
- ol {
368
- padding-left: var(--v-spacing-xl);
369
- margin: 0 0 var(--v-spacing-md) 0;
370
- }
371
-
372
- table {
373
- width: 100%;
374
- border-collapse: collapse;
375
- margin: 0 0 var(--v-spacing-md) 0;
376
- }
377
- th,
378
- td {
379
- text-align: left;
380
- padding: var(--v-spacing-sm) var(--v-spacing-md);
381
- border-bottom: 1px solid var(--v-border-base);
382
- }
383
- th {
384
- font-weight: 600;
385
- color: var(--v-content-secondary);
386
- font-size: var(--v-font-size-sm);
387
- }
388
-
389
- /* ─── Layer 3: Component Classes ─────────────────────────────── */
390
-
391
- /* Button variants */
392
- .v-button {
393
- font-family: var(--v-font-family);
394
- font-size: var(--v-font-size-base);
395
- font-weight: 500;
396
- padding: var(--v-spacing-sm) var(--v-spacing-lg);
397
- background: var(--v-primary-base);
398
- color: var(--v-aux-white);
399
- border: none;
400
- border-radius: var(--v-radius-md);
401
- cursor: pointer;
402
- transition:
403
- filter var(--v-duration-fast) ease-out,
404
- transform var(--v-duration-fast) ease-out;
405
- }
406
- .v-button:hover {
407
- filter: brightness(1.1);
408
- }
409
- .v-button:active {
410
- transform: scale(0.97);
411
- }
412
- .v-button:disabled {
413
- opacity: 0.4;
414
- cursor: not-allowed;
415
- filter: none;
416
- transform: none;
417
- }
418
- .v-button.secondary {
419
- background: var(--v-surface-base);
420
- color: var(--v-content-default);
421
- border: 1px solid var(--v-border-base);
422
- }
423
- .v-button.secondary:hover {
424
- filter: brightness(0.95);
425
- }
426
- .v-button.danger {
427
- background: var(--v-system-negative-strong);
428
- }
429
- .v-button.ghost {
430
- background: transparent;
431
- color: var(--v-primary-base);
432
- }
433
- .v-button.ghost:hover {
434
- background: var(--v-surface-base);
435
- filter: none;
436
- }
437
-
438
- /* Focus-visible for keyboard accessibility */
439
- .v-button:focus-visible {
440
- outline: 2px solid var(--v-primary-base);
441
- outline-offset: 2px;
442
- }
443
- input:focus-visible,
444
- textarea:focus-visible,
445
- select:focus-visible {
446
- border-color: var(--v-primary-base);
447
- outline: 2px solid var(--v-primary-base);
448
- outline-offset: -1px;
449
- }
450
-
451
- /* Card */
452
- .v-card {
453
- background: var(--v-surface-base);
454
- border: 1px solid var(--v-border-base);
455
- border-radius: var(--v-radius-lg);
456
- padding: var(--v-spacing-lg);
457
- box-shadow: var(--v-shadow-sm);
458
- }
459
-
460
- /* Badge */
461
- .v-badge {
462
- display: inline-flex;
463
- align-items: center;
464
- font-size: var(--v-font-size-xs);
465
- font-weight: 600;
466
- padding: var(--v-spacing-xxs) var(--v-spacing-sm);
467
- border-radius: var(--v-radius-pill);
468
- background: var(--v-surface-base);
469
- color: var(--v-content-secondary);
470
- }
471
- .v-badge.success {
472
- background: color-mix(
473
- in srgb,
474
- var(--v-system-positive-strong) 15%,
475
- transparent
476
- );
477
- color: var(--v-system-positive-strong);
478
- }
479
- .v-badge.danger {
480
- background: color-mix(
481
- in srgb,
482
- var(--v-system-negative-strong) 15%,
483
- transparent
484
- );
485
- color: var(--v-system-negative-strong);
486
- }
487
- .v-badge.warning {
488
- background: color-mix(in srgb, var(--v-system-mid-strong) 15%, transparent);
489
- color: var(--v-system-mid-strong);
490
- }
491
-
492
- /* List */
493
- .v-list {
494
- list-style: none;
495
- margin: 0;
496
- padding: 0;
497
- }
498
- .v-list-item {
499
- padding: var(--v-spacing-md) var(--v-spacing-lg);
500
- border-radius: var(--v-radius-md);
501
- transition: background var(--v-duration-fast) ease-out;
502
- }
503
- .v-list-item:hover {
504
- background: var(--v-surface-base);
505
- }
506
- .v-list-item:focus-visible {
507
- outline: 2px solid var(--v-primary-base);
508
- outline-offset: -2px;
509
- }
510
-
511
- /* Toggle switch */
512
- .v-toggle {
513
- position: relative;
514
- display: inline-block;
515
- width: 40px;
516
- height: 22px;
517
- }
518
- .v-toggle input {
519
- position: absolute;
520
- top: 0;
521
- left: 0;
522
- width: 100%;
523
- height: 100%;
524
- opacity: 0;
525
- margin: 0;
526
- cursor: pointer;
527
- }
528
- .v-toggle-track {
529
- position: absolute;
530
- inset: 0;
531
- background: var(--v-border-base);
532
- border-radius: var(--v-radius-pill);
533
- cursor: pointer;
534
- transition: background var(--v-duration-fast) ease-out;
535
- }
536
- .v-toggle-track::after {
537
- content: "";
538
- position: absolute;
539
- top: 2px;
540
- left: 2px;
541
- width: 18px;
542
- height: 18px;
543
- background: white;
544
- border-radius: 50%;
545
- transition: transform var(--v-duration-fast) ease-out;
546
- }
547
- .v-toggle input:checked + .v-toggle-track {
548
- background: var(--v-primary-base);
549
- }
550
- .v-toggle input:checked + .v-toggle-track::after {
551
- transform: translateX(18px);
552
- }
553
- .v-toggle input:focus-visible + .v-toggle-track {
554
- outline: 2px solid var(--v-primary-base);
555
- outline-offset: 2px;
556
- }
557
-
558
- /* Input row (input + button combo) */
559
- .v-input-row {
560
- display: flex;
561
- gap: var(--v-spacing-sm);
562
- }
563
- .v-input-row input,
564
- .v-input-row .v-input {
565
- flex: 1;
566
- }
567
-
568
- /* ─── Layer 4: Utility Classes ───────────────────────────────── */
569
-
570
- /* Flexbox */
571
- .v-flex {
572
- display: flex;
573
- }
574
- .v-flex-col {
575
- display: flex;
576
- flex-direction: column;
577
- }
578
- .v-flex-wrap {
579
- flex-wrap: wrap;
580
- }
581
- .v-items-center {
582
- align-items: center;
583
- }
584
- .v-justify-between {
585
- justify-content: space-between;
586
- }
587
- .v-justify-center {
588
- justify-content: center;
589
- }
590
-
591
- /* Gap */
592
- .v-gap-xs {
593
- gap: var(--v-spacing-xs);
594
- }
595
- .v-gap-sm {
596
- gap: var(--v-spacing-sm);
597
- }
598
- .v-gap-md {
599
- gap: var(--v-spacing-md);
600
- }
601
- .v-gap-lg {
602
- gap: var(--v-spacing-lg);
603
- }
604
- .v-gap-xl {
605
- gap: var(--v-spacing-xl);
606
- }
607
-
608
- /* Text */
609
- .v-text-secondary {
610
- color: var(--v-content-secondary);
611
- }
612
- .v-text-muted {
613
- color: var(--v-content-tertiary);
614
- }
615
- .v-text-accent {
616
- color: var(--v-primary-base);
617
- }
618
- .v-text-xs {
619
- font-size: var(--v-font-size-xs);
620
- }
621
- .v-text-sm {
622
- font-size: var(--v-font-size-sm);
623
- }
624
- .v-text-lg {
625
- font-size: var(--v-font-size-lg);
626
- }
627
- .v-font-mono {
628
- font-family: var(--v-font-mono);
629
- }
630
-
631
- /* Layout */
632
- .v-truncate {
633
- overflow: hidden;
634
- text-overflow: ellipsis;
635
- white-space: nowrap;
636
- }
637
- .v-w-full {
638
- width: 100%;
639
- }
640
-
641
- /* Accessibility */
642
- .v-sr-only {
643
- position: absolute;
644
- width: 1px;
645
- height: 1px;
646
- padding: 0;
647
- margin: -1px;
648
- overflow: hidden;
649
- clip: rect(0, 0, 0, 0);
650
- white-space: nowrap;
651
- border-width: 0;
652
- }
653
-
654
- /* ─── Layer 5: Widget Components ────────────────────────────── */
655
-
656
- /* ── Tier 1: Layout & Data Primitives ───────────────────────── */
657
-
658
- /* Metric Card — single big number with label and trend arrow */
659
- .v-metric-card {
660
- background: var(--v-surface-base);
661
- border: 1px solid var(--v-border-base);
662
- border-radius: var(--v-radius-lg);
663
- padding: var(--v-spacing-lg);
664
- display: flex;
665
- flex-direction: column;
666
- gap: var(--v-spacing-xs);
667
- }
668
- .v-metric-card .v-metric-value {
669
- font-size: var(--v-font-size-2xl);
670
- font-weight: 700;
671
- line-height: 1.1;
672
- color: var(--v-content-default);
673
- }
674
- .v-metric-card .v-metric-label {
675
- font-size: var(--v-font-size-sm);
676
- color: var(--v-content-secondary);
677
- font-weight: 500;
678
- text-transform: uppercase;
679
- letter-spacing: 0.04em;
680
- }
681
- .v-metric-card .v-metric-trend {
682
- font-size: var(--v-font-size-sm);
683
- font-weight: 600;
684
- display: inline-flex;
685
- align-items: center;
686
- gap: var(--v-spacing-xxs);
687
- }
688
- .v-metric-card .v-metric-trend.up {
689
- color: var(--v-system-positive-strong);
690
- }
691
- .v-metric-card .v-metric-trend.down {
692
- color: var(--v-system-negative-strong);
693
- }
694
- .v-metric-card .v-metric-trend.neutral {
695
- color: var(--v-content-tertiary);
696
- }
697
-
698
- /* Metric Grid — responsive grid of metric cards */
699
- .v-metric-grid {
700
- display: grid;
701
- grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
702
- gap: var(--v-spacing-lg);
703
- }
704
-
705
- /* Data Table — sortable, hoverable, sticky header */
706
- .v-data-table {
707
- width: 100%;
708
- border-collapse: separate;
709
- border-spacing: 0;
710
- background: var(--v-surface-base);
711
- border: 1px solid var(--v-border-base);
712
- border-radius: var(--v-radius-lg);
713
- overflow: hidden;
714
- }
715
- .v-data-table thead th {
716
- position: sticky;
717
- top: 0;
718
- background: var(--v-surface-overlay);
719
- font-size: var(--v-font-size-sm);
720
- font-weight: 600;
721
- color: var(--v-content-secondary);
722
- text-align: left;
723
- padding: var(--v-spacing-sm) var(--v-spacing-md);
724
- border-bottom: 1px solid var(--v-border-base);
725
- cursor: default;
726
- user-select: none;
727
- white-space: nowrap;
728
- }
729
- .v-data-table thead th[data-sortable] {
730
- cursor: pointer;
731
- }
732
- .v-data-table thead th[data-sortable]:hover {
733
- color: var(--v-content-default);
734
- }
735
- .v-data-table tbody td {
736
- padding: var(--v-spacing-sm) var(--v-spacing-md);
737
- border-bottom: 1px solid var(--v-border-base);
738
- font-size: var(--v-font-size-base);
739
- color: var(--v-content-default);
740
- }
741
- .v-data-table tbody tr:last-child td {
742
- border-bottom: none;
743
- }
744
- .v-data-table tbody tr:hover {
745
- background: color-mix(in srgb, var(--v-primary-base) 5%, transparent);
746
- }
747
- .v-data-table tbody tr.selected {
748
- background: color-mix(in srgb, var(--v-primary-base) 10%, transparent);
749
- }
750
- .v-data-table input[type="checkbox"] {
751
- accent-color: var(--v-primary-base);
752
- }
753
-
754
- /* Timeline — vertical timeline with entries */
755
- .v-timeline {
756
- display: flex;
757
- flex-direction: column;
758
- position: relative;
759
- padding-left: var(--v-spacing-xl);
760
- }
761
- .v-timeline::before {
762
- content: "";
763
- position: absolute;
764
- left: 7px;
765
- top: var(--v-spacing-xs);
766
- bottom: var(--v-spacing-xs);
767
- width: 2px;
768
- background: var(--v-border-base);
769
- }
770
- .v-timeline-entry {
771
- position: relative;
772
- padding-bottom: var(--v-spacing-lg);
773
- }
774
- .v-timeline-entry::before {
775
- content: "";
776
- position: absolute;
777
- left: calc(-1 * var(--v-spacing-xl) + 3px);
778
- top: 6px;
779
- width: 10px;
780
- height: 10px;
781
- border-radius: 50%;
782
- background: var(--v-border-base);
783
- border: 2px solid var(--v-surface-overlay);
784
- }
785
- .v-timeline-entry.active::before {
786
- background: var(--v-primary-base);
787
- }
788
- .v-timeline-entry.success::before {
789
- background: var(--v-system-positive-strong);
790
- }
791
- .v-timeline-entry.error::before {
792
- background: var(--v-system-negative-strong);
793
- }
794
- .v-timeline-entry .v-timeline-time {
795
- font-size: var(--v-font-size-xs);
796
- color: var(--v-content-tertiary);
797
- margin-bottom: var(--v-spacing-xxs);
798
- }
799
- .v-timeline-entry .v-timeline-title {
800
- font-size: var(--v-font-size-base);
801
- font-weight: 600;
802
- color: var(--v-content-default);
803
- }
804
- .v-timeline-entry .v-timeline-desc {
805
- font-size: var(--v-font-size-sm);
806
- color: var(--v-content-secondary);
807
- margin-top: var(--v-spacing-xxs);
808
- }
809
-
810
- /* Action List — rows with per-item action buttons */
811
- .v-action-list {
812
- list-style: none;
813
- margin: 0;
814
- padding: 0;
815
- display: flex;
816
- flex-direction: column;
817
- }
818
- .v-action-list-item {
819
- display: flex;
820
- align-items: center;
821
- gap: var(--v-spacing-md);
822
- padding: var(--v-spacing-md) var(--v-spacing-lg);
823
- border-bottom: 1px solid var(--v-border-base);
824
- transition: background var(--v-duration-fast) ease-out;
825
- }
826
- .v-action-list-item:last-child {
827
- border-bottom: none;
828
- }
829
- .v-action-list-item:hover {
830
- background: var(--v-surface-base);
831
- }
832
- .v-action-list-item .v-action-content {
833
- flex: 1;
834
- min-width: 0;
835
- }
836
- .v-action-list-item .v-action-title {
837
- font-weight: 500;
838
- color: var(--v-content-default);
839
- }
840
- .v-action-list-item .v-action-subtitle {
841
- font-size: var(--v-font-size-sm);
842
- color: var(--v-content-secondary);
843
- margin-top: var(--v-spacing-xxs);
844
- }
845
- .v-action-list-item .v-action-buttons {
846
- display: flex;
847
- gap: var(--v-spacing-xs);
848
- flex-shrink: 0;
849
- }
850
-
851
- /* Tabs — tab bar + tab panels */
852
- .v-tabs {
853
- display: flex;
854
- flex-direction: column;
855
- }
856
- .v-tab-bar {
857
- display: flex;
858
- gap: 0;
859
- border-bottom: 1px solid var(--v-border-base);
860
- }
861
- .v-tab {
862
- padding: var(--v-spacing-sm) var(--v-spacing-lg);
863
- font-size: var(--v-font-size-base);
864
- font-weight: 500;
865
- color: var(--v-content-secondary);
866
- background: transparent;
867
- border: none;
868
- border-bottom: 2px solid transparent;
869
- cursor: pointer;
870
- transition:
871
- color var(--v-duration-fast) ease-out,
872
- border-color var(--v-duration-fast) ease-out;
873
- }
874
- .v-tab:hover {
875
- color: var(--v-content-default);
876
- }
877
- .v-tab[aria-selected="true"],
878
- .v-tab.active {
879
- color: var(--v-primary-base);
880
- border-bottom-color: var(--v-primary-base);
881
- }
882
- .v-tab:focus-visible {
883
- outline: 2px solid var(--v-primary-base);
884
- outline-offset: -2px;
885
- }
886
- .v-tab-panel {
887
- padding: var(--v-spacing-lg) 0;
888
- }
889
- .v-tab-panel[hidden] {
890
- display: none;
891
- }
892
-
893
- /* Accordion — collapsible sections */
894
- .v-accordion {
895
- display: flex;
896
- flex-direction: column;
897
- border: 1px solid var(--v-border-base);
898
- border-radius: var(--v-radius-lg);
899
- overflow: hidden;
900
- }
901
- .v-accordion-item {
902
- border-bottom: 1px solid var(--v-border-base);
903
- }
904
- .v-accordion-item:last-child {
905
- border-bottom: none;
906
- }
907
- .v-accordion-header {
908
- display: flex;
909
- align-items: center;
910
- justify-content: space-between;
911
- width: 100%;
912
- padding: var(--v-spacing-md) var(--v-spacing-lg);
913
- background: var(--v-surface-base);
914
- border: none;
915
- cursor: pointer;
916
- font-size: var(--v-font-size-base);
917
- font-weight: 500;
918
- color: var(--v-content-default);
919
- text-align: left;
920
- transition: background var(--v-duration-fast) ease-out;
921
- }
922
- .v-accordion-header:hover {
923
- background: color-mix(
924
- in srgb,
925
- var(--v-surface-base) 80%,
926
- var(--v-surface-overlay)
927
- );
928
- }
929
- .v-accordion-header::after {
930
- content: "\203A";
931
- font-size: var(--v-font-size-lg);
932
- color: var(--v-content-tertiary);
933
- transform: rotate(90deg);
934
- transition: transform var(--v-duration-standard) ease-in-out;
935
- }
936
- .v-accordion-item[open] .v-accordion-header::after,
937
- .v-accordion-header[aria-expanded="true"]::after {
938
- transform: rotate(270deg);
939
- }
940
- .v-accordion-body {
941
- padding: var(--v-spacing-lg);
942
- background: var(--v-surface-overlay);
943
- }
944
- .v-accordion-header:focus-visible {
945
- outline: 2px solid var(--v-primary-base);
946
- outline-offset: -2px;
947
- }
948
-
949
- /* Search Bar — input with icon and clear button */
950
- .v-search-bar {
951
- position: relative;
952
- display: flex;
953
- align-items: center;
954
- }
955
- .v-search-bar input {
956
- width: 100%;
957
- padding-left: var(--v-spacing-xxl);
958
- padding-right: var(--v-spacing-xxl);
959
- background: var(--v-surface-base);
960
- border: 1px solid var(--v-border-base);
961
- border-radius: var(--v-radius-pill);
962
- }
963
- .v-search-bar input:focus {
964
- border-color: var(--v-primary-base);
965
- }
966
- .v-search-bar::before {
967
- content: "\1F50D";
968
- position: absolute;
969
- left: var(--v-spacing-md);
970
- font-size: var(--v-font-size-sm);
971
- color: var(--v-content-tertiary);
972
- pointer-events: none;
973
- }
974
- .v-search-bar .v-search-clear {
975
- position: absolute;
976
- right: var(--v-spacing-sm);
977
- background: none;
978
- border: none;
979
- color: var(--v-content-tertiary);
980
- cursor: pointer;
981
- font-size: var(--v-font-size-sm);
982
- padding: var(--v-spacing-xs);
983
- border-radius: 50%;
984
- }
985
- .v-search-bar .v-search-clear:hover {
986
- color: var(--v-content-default);
987
- background: var(--v-border-base);
988
- }
989
-
990
- /* Card Grid — responsive grid of cards */
991
- .v-card-grid {
992
- display: grid;
993
- grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
994
- gap: var(--v-spacing-lg);
995
- }
996
-
997
- /* Progress Bar — horizontal fill bar with label */
998
- .v-progress-bar {
999
- display: flex;
1000
- flex-direction: column;
1001
- gap: var(--v-spacing-xs);
1002
- }
1003
- .v-progress-bar .v-progress-header {
1004
- display: flex;
1005
- justify-content: space-between;
1006
- font-size: var(--v-font-size-sm);
1007
- color: var(--v-content-secondary);
1008
- }
1009
- .v-progress-bar .v-progress-track {
1010
- height: 8px;
1011
- background: var(--v-border-base);
1012
- border-radius: var(--v-radius-pill);
1013
- overflow: hidden;
1014
- }
1015
- .v-progress-bar .v-progress-fill {
1016
- height: 100%;
1017
- background: var(--v-primary-base);
1018
- border-radius: var(--v-radius-pill);
1019
- transition: width var(--v-duration-standard) ease-in-out;
1020
- }
1021
- .v-progress-bar .v-progress-fill.success {
1022
- background: var(--v-system-positive-strong);
1023
- }
1024
- .v-progress-bar .v-progress-fill.warning {
1025
- background: var(--v-system-mid-strong);
1026
- }
1027
- .v-progress-bar .v-progress-fill.danger {
1028
- background: var(--v-system-negative-strong);
1029
- }
1030
-
1031
- /* Status Badge — colored pill with dot indicator */
1032
- .v-status-badge {
1033
- display: inline-flex;
1034
- align-items: center;
1035
- gap: var(--v-spacing-xs);
1036
- font-size: var(--v-font-size-xs);
1037
- font-weight: 600;
1038
- padding: var(--v-spacing-xxs) var(--v-spacing-sm);
1039
- border-radius: var(--v-radius-pill);
1040
- background: var(--v-surface-base);
1041
- color: var(--v-content-secondary);
1042
- }
1043
- .v-status-badge::before {
1044
- content: "";
1045
- width: 6px;
1046
- height: 6px;
1047
- border-radius: 50%;
1048
- background: currentColor;
1049
- flex-shrink: 0;
1050
- }
1051
- .v-status-badge.success {
1052
- background: color-mix(
1053
- in srgb,
1054
- var(--v-system-positive-strong) 15%,
1055
- transparent
1056
- );
1057
- color: var(--v-system-positive-strong);
1058
- }
1059
- .v-status-badge.warning {
1060
- background: color-mix(in srgb, var(--v-system-mid-strong) 15%, transparent);
1061
- color: var(--v-system-mid-strong);
1062
- }
1063
- .v-status-badge.error {
1064
- background: color-mix(
1065
- in srgb,
1066
- var(--v-system-negative-strong) 15%,
1067
- transparent
1068
- );
1069
- color: var(--v-system-negative-strong);
1070
- }
1071
- .v-status-badge.info {
1072
- background: color-mix(in srgb, var(--v-primary-base) 15%, transparent);
1073
- color: var(--v-primary-base);
1074
- }
1075
-
1076
- /* Stat Row — horizontal strip of label-value pairs */
1077
- .v-stat-row {
1078
- display: flex;
1079
- flex-wrap: wrap;
1080
- gap: var(--v-spacing-lg);
1081
- padding: var(--v-spacing-md) 0;
1082
- }
1083
- .v-stat-row .v-stat {
1084
- display: flex;
1085
- flex-direction: column;
1086
- gap: var(--v-spacing-xxs);
1087
- }
1088
- .v-stat-row .v-stat:not(:last-child) {
1089
- padding-right: var(--v-spacing-lg);
1090
- border-right: 1px solid var(--v-border-base);
1091
- }
1092
- .v-stat-row .v-stat-label {
1093
- font-size: var(--v-font-size-xs);
1094
- color: var(--v-content-tertiary);
1095
- text-transform: uppercase;
1096
- letter-spacing: 0.04em;
1097
- font-weight: 500;
1098
- }
1099
- .v-stat-row .v-stat-value {
1100
- font-size: var(--v-font-size-lg);
1101
- font-weight: 700;
1102
- color: var(--v-content-default);
1103
- }
1104
-
1105
- /* Toast — dismissible notification banner */
1106
- .v-toast {
1107
- display: flex;
1108
- align-items: center;
1109
- gap: var(--v-spacing-md);
1110
- padding: var(--v-spacing-md) var(--v-spacing-lg);
1111
- border-radius: var(--v-radius-md);
1112
- font-size: var(--v-font-size-sm);
1113
- font-weight: 500;
1114
- background: var(--v-surface-base);
1115
- border: 1px solid var(--v-border-base);
1116
- box-shadow: var(--v-shadow-md);
1117
- }
1118
- .v-toast.success {
1119
- background: color-mix(
1120
- in srgb,
1121
- var(--v-system-positive-strong) 10%,
1122
- var(--v-surface-base)
1123
- );
1124
- border-color: color-mix(
1125
- in srgb,
1126
- var(--v-system-positive-strong) 30%,
1127
- var(--v-border-base)
1128
- );
1129
- color: var(--v-system-positive-strong);
1130
- }
1131
- .v-toast.error {
1132
- background: color-mix(
1133
- in srgb,
1134
- var(--v-system-negative-strong) 10%,
1135
- var(--v-surface-base)
1136
- );
1137
- border-color: color-mix(
1138
- in srgb,
1139
- var(--v-system-negative-strong) 30%,
1140
- var(--v-border-base)
1141
- );
1142
- color: var(--v-system-negative-strong);
1143
- }
1144
- .v-toast.warning {
1145
- background: color-mix(
1146
- in srgb,
1147
- var(--v-system-mid-strong) 10%,
1148
- var(--v-surface-base)
1149
- );
1150
- border-color: color-mix(
1151
- in srgb,
1152
- var(--v-system-mid-strong) 30%,
1153
- var(--v-border-base)
1154
- );
1155
- color: var(--v-system-mid-strong);
1156
- }
1157
- .v-toast.info {
1158
- background: color-mix(
1159
- in srgb,
1160
- var(--v-primary-base) 10%,
1161
- var(--v-surface-base)
1162
- );
1163
- border-color: color-mix(
1164
- in srgb,
1165
- var(--v-primary-base) 30%,
1166
- var(--v-border-base)
1167
- );
1168
- color: var(--v-primary-base);
1169
- }
1170
- .v-toast .v-toast-dismiss {
1171
- margin-left: auto;
1172
- background: none;
1173
- border: none;
1174
- color: inherit;
1175
- opacity: 0.6;
1176
- cursor: pointer;
1177
- font-size: var(--v-font-size-lg);
1178
- padding: 0 var(--v-spacing-xs);
1179
- }
1180
- .v-toast .v-toast-dismiss:hover {
1181
- opacity: 1;
1182
- }
1183
-
1184
- /* Empty State — enhanced version with icon + CTA */
1185
- .v-empty-state {
1186
- text-align: center;
1187
- color: var(--v-content-tertiary);
1188
- padding: var(--v-spacing-xxxl) var(--v-spacing-xl);
1189
- display: flex;
1190
- flex-direction: column;
1191
- align-items: center;
1192
- gap: var(--v-spacing-md);
1193
- }
1194
- .v-empty-state .v-empty-icon {
1195
- font-size: 48px;
1196
- line-height: 1;
1197
- opacity: 0.5;
1198
- }
1199
- .v-empty-state .v-empty-title {
1200
- font-size: var(--v-font-size-lg);
1201
- font-weight: 600;
1202
- color: var(--v-content-secondary);
1203
- margin: 0;
1204
- }
1205
- .v-empty-state .v-empty-desc {
1206
- font-size: var(--v-font-size-base);
1207
- color: var(--v-content-tertiary);
1208
- max-width: 360px;
1209
- }
1210
-
1211
- /* Divider — horizontal rule with optional label */
1212
- .v-divider {
1213
- display: flex;
1214
- align-items: center;
1215
- gap: var(--v-spacing-md);
1216
- margin: var(--v-spacing-xl) 0;
1217
- color: var(--v-content-tertiary);
1218
- font-size: var(--v-font-size-xs);
1219
- font-weight: 500;
1220
- text-transform: uppercase;
1221
- letter-spacing: 0.04em;
1222
- }
1223
- .v-divider::before,
1224
- .v-divider::after {
1225
- content: "";
1226
- flex: 1;
1227
- height: 1px;
1228
- background: var(--v-border-base);
1229
- }
1230
- .v-divider:empty::after {
1231
- display: none;
1232
- }
1233
-
1234
- /* Avatar Row — circular avatar + name + subtitle */
1235
- .v-avatar-row {
1236
- display: flex;
1237
- align-items: center;
1238
- gap: var(--v-spacing-md);
1239
- }
1240
- .v-avatar-row .v-avatar {
1241
- width: 36px;
1242
- height: 36px;
1243
- border-radius: 50%;
1244
- background: var(--v-primary-base);
1245
- color: var(--v-content-inset);
1246
- display: flex;
1247
- align-items: center;
1248
- justify-content: center;
1249
- font-weight: 600;
1250
- font-size: var(--v-font-size-sm);
1251
- flex-shrink: 0;
1252
- overflow: hidden;
1253
- }
1254
- .v-avatar-row .v-avatar img {
1255
- width: 100%;
1256
- height: 100%;
1257
- object-fit: cover;
1258
- }
1259
- .v-avatar-row .v-avatar-info {
1260
- display: flex;
1261
- flex-direction: column;
1262
- min-width: 0;
1263
- }
1264
- .v-avatar-row .v-avatar-name {
1265
- font-weight: 500;
1266
- color: var(--v-content-default);
1267
- white-space: nowrap;
1268
- overflow: hidden;
1269
- text-overflow: ellipsis;
1270
- }
1271
- .v-avatar-row .v-avatar-subtitle {
1272
- font-size: var(--v-font-size-sm);
1273
- color: var(--v-content-secondary);
1274
- }
1275
-
1276
- /* Tag / Chip Group — wrapping row of badges */
1277
- .v-tag-group {
1278
- display: flex;
1279
- flex-wrap: wrap;
1280
- gap: var(--v-spacing-xs);
1281
- }
1282
-
1283
- /* ── Tier 2: Domain-Specific Widgets ────────────────────────── */
1284
-
1285
- /* Weather Card */
1286
- .v-weather-card {
1287
- background: var(--v-surface-base);
1288
- border: 1px solid var(--v-border-base);
1289
- border-radius: var(--v-radius-lg);
1290
- padding: var(--v-spacing-lg);
1291
- display: flex;
1292
- flex-direction: column;
1293
- gap: var(--v-spacing-md);
1294
- }
1295
- .v-weather-card .v-weather-main {
1296
- display: flex;
1297
- align-items: center;
1298
- gap: var(--v-spacing-lg);
1299
- }
1300
- .v-weather-card .v-weather-temp {
1301
- font-size: 48px;
1302
- font-weight: 700;
1303
- line-height: 1;
1304
- color: var(--v-content-default);
1305
- }
1306
- .v-weather-card .v-weather-condition {
1307
- font-size: var(--v-font-size-sm);
1308
- color: var(--v-content-secondary);
1309
- }
1310
- .v-weather-card .v-weather-icon {
1311
- font-size: 48px;
1312
- line-height: 1;
1313
- }
1314
- .v-weather-card .v-weather-details {
1315
- display: flex;
1316
- gap: var(--v-spacing-lg);
1317
- font-size: var(--v-font-size-sm);
1318
- color: var(--v-content-secondary);
1319
- }
1320
- .v-weather-card .v-weather-forecast {
1321
- display: grid;
1322
- grid-template-columns: repeat(auto-fit, minmax(60px, 1fr));
1323
- gap: var(--v-spacing-sm);
1324
- text-align: center;
1325
- }
1326
- .v-weather-card .v-weather-forecast-item {
1327
- display: flex;
1328
- flex-direction: column;
1329
- align-items: center;
1330
- gap: var(--v-spacing-xxs);
1331
- font-size: var(--v-font-size-xs);
1332
- color: var(--v-content-secondary);
1333
- padding: var(--v-spacing-sm);
1334
- border-radius: var(--v-radius-md);
1335
- background: color-mix(in srgb, var(--v-border-base) 30%, transparent);
1336
- }
1337
-
1338
- /* Stock Ticker */
1339
- .v-stock-ticker {
1340
- background: var(--v-surface-base);
1341
- border: 1px solid var(--v-border-base);
1342
- border-radius: var(--v-radius-lg);
1343
- padding: var(--v-spacing-lg);
1344
- display: flex;
1345
- flex-direction: column;
1346
- gap: var(--v-spacing-md);
1347
- }
1348
- .v-stock-ticker .v-stock-header {
1349
- display: flex;
1350
- align-items: baseline;
1351
- gap: var(--v-spacing-md);
1352
- }
1353
- .v-stock-ticker .v-stock-symbol {
1354
- font-size: var(--v-font-size-lg);
1355
- font-weight: 700;
1356
- color: var(--v-content-default);
1357
- }
1358
- .v-stock-ticker .v-stock-price {
1359
- font-size: var(--v-font-size-2xl);
1360
- font-weight: 700;
1361
- color: var(--v-content-default);
1362
- }
1363
- .v-stock-ticker .v-stock-change {
1364
- font-size: var(--v-font-size-sm);
1365
- font-weight: 600;
1366
- }
1367
- .v-stock-ticker .v-stock-change.up {
1368
- color: var(--v-system-positive-strong);
1369
- }
1370
- .v-stock-ticker .v-stock-change.down {
1371
- color: var(--v-system-negative-strong);
1372
- }
1373
- .v-stock-ticker .v-stock-chart {
1374
- width: 100%;
1375
- height: 120px;
1376
- border-radius: var(--v-radius-md);
1377
- overflow: hidden;
1378
- }
1379
- .v-stock-ticker .v-stock-meta {
1380
- display: flex;
1381
- gap: var(--v-spacing-lg);
1382
- font-size: var(--v-font-size-xs);
1383
- color: var(--v-content-tertiary);
1384
- }
1385
-
1386
- /* Flight Card */
1387
- .v-flight-card {
1388
- background: var(--v-surface-base);
1389
- border: 1px solid var(--v-border-base);
1390
- border-radius: var(--v-radius-lg);
1391
- padding: var(--v-spacing-lg);
1392
- display: flex;
1393
- flex-direction: column;
1394
- gap: var(--v-spacing-md);
1395
- }
1396
- .v-flight-card .v-flight-header {
1397
- display: flex;
1398
- align-items: center;
1399
- justify-content: space-between;
1400
- }
1401
- .v-flight-card .v-flight-airline {
1402
- font-weight: 600;
1403
- color: var(--v-content-default);
1404
- }
1405
- .v-flight-card .v-flight-price {
1406
- font-size: var(--v-font-size-lg);
1407
- font-weight: 700;
1408
- color: var(--v-primary-base);
1409
- }
1410
- .v-flight-card .v-flight-route {
1411
- display: flex;
1412
- align-items: center;
1413
- justify-content: space-between;
1414
- gap: var(--v-spacing-md);
1415
- }
1416
- .v-flight-card .v-flight-endpoint {
1417
- display: flex;
1418
- flex-direction: column;
1419
- gap: var(--v-spacing-xxs);
1420
- }
1421
- .v-flight-card .v-flight-time {
1422
- font-size: var(--v-font-size-xl);
1423
- font-weight: 700;
1424
- color: var(--v-content-default);
1425
- }
1426
- .v-flight-card .v-flight-code {
1427
- font-size: var(--v-font-size-sm);
1428
- color: var(--v-content-secondary);
1429
- font-weight: 500;
1430
- }
1431
- .v-flight-card .v-flight-duration {
1432
- display: flex;
1433
- flex-direction: column;
1434
- align-items: center;
1435
- gap: var(--v-spacing-xxs);
1436
- font-size: var(--v-font-size-xs);
1437
- color: var(--v-content-tertiary);
1438
- }
1439
- .v-flight-card .v-flight-line {
1440
- width: 80px;
1441
- height: 1px;
1442
- background: var(--v-border-base);
1443
- position: relative;
1444
- }
1445
- .v-flight-card .v-flight-line::after {
1446
- content: "\2708";
1447
- position: absolute;
1448
- right: -4px;
1449
- top: -8px;
1450
- font-size: var(--v-font-size-base);
1451
- color: var(--v-content-tertiary);
1452
- }
1453
- .v-flight-card .v-flight-meta {
1454
- display: flex;
1455
- gap: var(--v-spacing-lg);
1456
- font-size: var(--v-font-size-xs);
1457
- color: var(--v-content-tertiary);
1458
- }
1459
-
1460
- /* Billing Chart */
1461
- .v-billing-chart {
1462
- background: var(--v-surface-base);
1463
- border: 1px solid var(--v-border-base);
1464
- border-radius: var(--v-radius-lg);
1465
- padding: var(--v-spacing-lg);
1466
- display: flex;
1467
- flex-direction: column;
1468
- gap: var(--v-spacing-md);
1469
- }
1470
- .v-billing-chart .v-billing-header {
1471
- display: flex;
1472
- align-items: baseline;
1473
- justify-content: space-between;
1474
- }
1475
- .v-billing-chart .v-billing-total {
1476
- font-size: var(--v-font-size-2xl);
1477
- font-weight: 700;
1478
- color: var(--v-content-default);
1479
- }
1480
- .v-billing-chart .v-billing-period {
1481
- font-size: var(--v-font-size-sm);
1482
- color: var(--v-content-secondary);
1483
- }
1484
- .v-billing-chart .v-billing-canvas {
1485
- width: 100%;
1486
- height: 160px;
1487
- border-radius: var(--v-radius-md);
1488
- overflow: hidden;
1489
- }
1490
- .v-billing-chart .v-billing-legend {
1491
- display: flex;
1492
- flex-wrap: wrap;
1493
- gap: var(--v-spacing-md);
1494
- font-size: var(--v-font-size-xs);
1495
- color: var(--v-content-secondary);
1496
- }
1497
- .v-billing-chart .v-billing-legend-item {
1498
- display: flex;
1499
- align-items: center;
1500
- gap: var(--v-spacing-xs);
1501
- }
1502
- .v-billing-chart .v-billing-legend-dot {
1503
- width: 8px;
1504
- height: 8px;
1505
- border-radius: 50%;
1506
- }
1507
-
1508
- /* Boarding Pass */
1509
- .v-boarding-pass {
1510
- background: var(--v-surface-base);
1511
- border: 1px solid var(--v-border-base);
1512
- border-radius: var(--v-radius-lg);
1513
- padding: var(--v-spacing-lg);
1514
- display: flex;
1515
- flex-direction: column;
1516
- gap: var(--v-spacing-lg);
1517
- position: relative;
1518
- overflow: hidden;
1519
- }
1520
- .v-boarding-pass::before {
1521
- content: "";
1522
- position: absolute;
1523
- left: -8px;
1524
- top: 50%;
1525
- width: 16px;
1526
- height: 16px;
1527
- border-radius: 50%;
1528
- background: var(--v-surface-overlay);
1529
- }
1530
- .v-boarding-pass::after {
1531
- content: "";
1532
- position: absolute;
1533
- right: -8px;
1534
- top: 50%;
1535
- width: 16px;
1536
- height: 16px;
1537
- border-radius: 50%;
1538
- background: var(--v-surface-overlay);
1539
- }
1540
- .v-boarding-pass .v-bp-header {
1541
- display: flex;
1542
- justify-content: space-between;
1543
- align-items: center;
1544
- font-weight: 600;
1545
- color: var(--v-content-default);
1546
- }
1547
- .v-boarding-pass .v-bp-route {
1548
- display: flex;
1549
- justify-content: space-between;
1550
- align-items: center;
1551
- }
1552
- .v-boarding-pass .v-bp-city {
1553
- font-size: var(--v-font-size-2xl);
1554
- font-weight: 700;
1555
- color: var(--v-content-default);
1556
- }
1557
- .v-boarding-pass .v-bp-details {
1558
- display: grid;
1559
- grid-template-columns: repeat(auto-fit, minmax(80px, 1fr));
1560
- gap: var(--v-spacing-md);
1561
- padding-top: var(--v-spacing-md);
1562
- border-top: 1px dashed var(--v-border-base);
1563
- }
1564
- .v-boarding-pass .v-bp-field {
1565
- display: flex;
1566
- flex-direction: column;
1567
- gap: var(--v-spacing-xxs);
1568
- }
1569
- .v-boarding-pass .v-bp-field-label {
1570
- font-size: var(--v-font-size-xs);
1571
- color: var(--v-content-tertiary);
1572
- text-transform: uppercase;
1573
- letter-spacing: 0.05em;
1574
- }
1575
- .v-boarding-pass .v-bp-field-value {
1576
- font-size: var(--v-font-size-lg);
1577
- font-weight: 700;
1578
- color: var(--v-content-default);
1579
- }
1580
-
1581
- /* Itinerary */
1582
- .v-itinerary {
1583
- display: flex;
1584
- flex-direction: column;
1585
- gap: var(--v-spacing-lg);
1586
- }
1587
- .v-itinerary .v-itinerary-day {
1588
- display: flex;
1589
- flex-direction: column;
1590
- gap: var(--v-spacing-sm);
1591
- }
1592
- .v-itinerary .v-itinerary-date {
1593
- font-size: var(--v-font-size-sm);
1594
- font-weight: 600;
1595
- color: var(--v-primary-base);
1596
- text-transform: uppercase;
1597
- letter-spacing: 0.04em;
1598
- }
1599
- .v-itinerary .v-itinerary-item {
1600
- background: var(--v-surface-base);
1601
- border: 1px solid var(--v-border-base);
1602
- border-radius: var(--v-radius-md);
1603
- padding: var(--v-spacing-md) var(--v-spacing-lg);
1604
- display: flex;
1605
- align-items: center;
1606
- gap: var(--v-spacing-md);
1607
- }
1608
- .v-itinerary .v-itinerary-time {
1609
- font-size: var(--v-font-size-sm);
1610
- color: var(--v-content-tertiary);
1611
- font-weight: 500;
1612
- white-space: nowrap;
1613
- }
1614
- .v-itinerary .v-itinerary-content {
1615
- flex: 1;
1616
- }
1617
- .v-itinerary .v-itinerary-title {
1618
- font-weight: 500;
1619
- color: var(--v-content-default);
1620
- }
1621
- .v-itinerary .v-itinerary-location {
1622
- font-size: var(--v-font-size-sm);
1623
- color: var(--v-content-secondary);
1624
- }
1625
-
1626
- /* Receipt */
1627
- .v-receipt {
1628
- background: var(--v-surface-base);
1629
- border: 1px solid var(--v-border-base);
1630
- border-radius: var(--v-radius-lg);
1631
- padding: var(--v-spacing-xl);
1632
- display: flex;
1633
- flex-direction: column;
1634
- gap: var(--v-spacing-md);
1635
- max-width: 400px;
1636
- font-family: var(--v-font-mono);
1637
- }
1638
- .v-receipt .v-receipt-header {
1639
- text-align: center;
1640
- padding-bottom: var(--v-spacing-md);
1641
- border-bottom: 1px dashed var(--v-border-base);
1642
- }
1643
- .v-receipt .v-receipt-store {
1644
- font-size: var(--v-font-size-lg);
1645
- font-weight: 700;
1646
- color: var(--v-content-default);
1647
- font-family: var(--v-font-family);
1648
- }
1649
- .v-receipt .v-receipt-items {
1650
- display: flex;
1651
- flex-direction: column;
1652
- gap: var(--v-spacing-xs);
1653
- }
1654
- .v-receipt .v-receipt-line {
1655
- display: flex;
1656
- justify-content: space-between;
1657
- font-size: var(--v-font-size-sm);
1658
- color: var(--v-content-default);
1659
- }
1660
- .v-receipt .v-receipt-divider {
1661
- border: none;
1662
- border-top: 1px dashed var(--v-border-base);
1663
- margin: var(--v-spacing-sm) 0;
1664
- }
1665
- .v-receipt .v-receipt-total {
1666
- display: flex;
1667
- justify-content: space-between;
1668
- font-weight: 700;
1669
- font-size: var(--v-font-size-base);
1670
- color: var(--v-content-default);
1671
- padding-top: var(--v-spacing-sm);
1672
- border-top: 2px solid var(--v-border-base);
1673
- }
1674
-
1675
- /* Invoice */
1676
- .v-invoice {
1677
- background: var(--v-surface-base);
1678
- border: 1px solid var(--v-border-base);
1679
- border-radius: var(--v-radius-lg);
1680
- padding: var(--v-spacing-xl);
1681
- display: flex;
1682
- flex-direction: column;
1683
- gap: var(--v-spacing-lg);
1684
- }
1685
- .v-invoice .v-invoice-header {
1686
- display: flex;
1687
- justify-content: space-between;
1688
- align-items: flex-start;
1689
- }
1690
- .v-invoice .v-invoice-title {
1691
- font-size: var(--v-font-size-xl);
1692
- font-weight: 700;
1693
- color: var(--v-content-default);
1694
- }
1695
- .v-invoice .v-invoice-number {
1696
- font-size: var(--v-font-size-sm);
1697
- color: var(--v-content-secondary);
1698
- font-family: var(--v-font-mono);
1699
- }
1700
- .v-invoice .v-invoice-parties {
1701
- display: grid;
1702
- grid-template-columns: 1fr 1fr;
1703
- gap: var(--v-spacing-xl);
1704
- }
1705
- .v-invoice .v-invoice-party-label {
1706
- font-size: var(--v-font-size-xs);
1707
- color: var(--v-content-tertiary);
1708
- text-transform: uppercase;
1709
- letter-spacing: 0.04em;
1710
- margin-bottom: var(--v-spacing-xs);
1711
- }
1712
- .v-invoice .v-invoice-party-name {
1713
- font-weight: 600;
1714
- color: var(--v-content-default);
1715
- }
1716
- .v-invoice .v-invoice-party-detail {
1717
- font-size: var(--v-font-size-sm);
1718
- color: var(--v-content-secondary);
1719
- }
1720
- .v-invoice .v-invoice-table {
1721
- width: 100%;
1722
- border-collapse: collapse;
1723
- }
1724
- .v-invoice .v-invoice-table th {
1725
- text-align: left;
1726
- font-size: var(--v-font-size-xs);
1727
- color: var(--v-content-tertiary);
1728
- text-transform: uppercase;
1729
- letter-spacing: 0.04em;
1730
- padding: var(--v-spacing-sm) var(--v-spacing-md);
1731
- border-bottom: 2px solid var(--v-border-base);
1732
- }
1733
- .v-invoice .v-invoice-table td {
1734
- padding: var(--v-spacing-sm) var(--v-spacing-md);
1735
- border-bottom: 1px solid var(--v-border-base);
1736
- font-size: var(--v-font-size-sm);
1737
- color: var(--v-content-default);
1738
- }
1739
- .v-invoice .v-invoice-table td:last-child,
1740
- .v-invoice .v-invoice-table th:last-child {
1741
- text-align: right;
1742
- }
1743
- .v-invoice .v-invoice-totals {
1744
- display: flex;
1745
- flex-direction: column;
1746
- align-items: flex-end;
1747
- gap: var(--v-spacing-xs);
1748
- }
1749
- .v-invoice .v-invoice-totals .v-invoice-line {
1750
- display: flex;
1751
- gap: var(--v-spacing-xxl);
1752
- font-size: var(--v-font-size-sm);
1753
- color: var(--v-content-secondary);
1754
- }
1755
- .v-invoice .v-invoice-totals .v-invoice-line.total {
1756
- font-weight: 700;
1757
- font-size: var(--v-font-size-lg);
1758
- color: var(--v-content-default);
1759
- padding-top: var(--v-spacing-sm);
1760
- border-top: 2px solid var(--v-border-base);
1761
- }
1762
- .v-invoice .v-invoice-footer {
1763
- font-size: var(--v-font-size-xs);
1764
- color: var(--v-content-tertiary);
1765
- padding-top: var(--v-spacing-md);
1766
- border-top: 1px solid var(--v-border-base);
1767
- }
1768
-
1769
- /* ── Tier 3: Content & Landing Page Components ─────────────── */
1770
-
1771
- /* Page — centered content container for landing pages */
1772
- .v-page {
1773
- margin: 0 auto;
1774
- display: flex;
1775
- flex-direction: column;
1776
- gap: var(--v-spacing-xxl);
1777
- width: 100%;
1778
- }
1779
-
1780
- /* Hero — top-of-page banner with gradient background */
1781
- .v-hero {
1782
- position: relative;
1783
- background: linear-gradient(
1784
- 135deg,
1785
- var(--v-system-positive-weak) 0%,
1786
- var(--v-border-active) 100%
1787
- );
1788
- border-radius: var(--v-radius-xl);
1789
- padding: var(--v-spacing-xxxl) var(--v-spacing-xl);
1790
- text-align: center;
1791
- overflow: hidden;
1792
- display: flex;
1793
- flex-direction: column;
1794
- align-items: center;
1795
- gap: var(--v-spacing-md);
1796
- }
1797
- .v-hero::before {
1798
- content: "";
1799
- position: absolute;
1800
- top: -40%;
1801
- left: 50%;
1802
- transform: translateX(-50%);
1803
- width: 120%;
1804
- height: 80%;
1805
- background: radial-gradient(
1806
- ellipse,
1807
- color-mix(in srgb, var(--v-primary-base) 30%, transparent) 0%,
1808
- transparent 70%
1809
- );
1810
- pointer-events: none;
1811
- }
1812
- .v-hero-badge {
1813
- display: inline-block;
1814
- padding: var(--v-spacing-xs) var(--v-spacing-lg);
1815
- background: rgba(255, 255, 255, 0.1);
1816
- backdrop-filter: blur(8px);
1817
- -webkit-backdrop-filter: blur(8px);
1818
- border: 1px solid rgba(255, 255, 255, 0.15);
1819
- border-radius: var(--v-radius-pill);
1820
- font-size: var(--v-font-size-xs);
1821
- font-weight: 600;
1822
- text-transform: uppercase;
1823
- letter-spacing: 0.06em;
1824
- color: var(--v-content-disabled);
1825
- position: relative;
1826
- }
1827
- .v-hero h1 {
1828
- font-size: 2.5rem;
1829
- font-weight: 800;
1830
- background: linear-gradient(
1831
- 180deg,
1832
- #fff 30%,
1833
- var(--v-content-background) 100%
1834
- );
1835
- -webkit-background-clip: text;
1836
- -webkit-text-fill-color: transparent;
1837
- background-clip: text;
1838
- margin: 0;
1839
- position: relative;
1840
- line-height: 1.15;
1841
- }
1842
- .v-hero-subtitle {
1843
- font-size: var(--v-font-size-base);
1844
- color: var(--v-content-tertiary);
1845
- max-width: 500px;
1846
- margin: 0 auto;
1847
- line-height: 1.5;
1848
- position: relative;
1849
- }
1850
-
1851
- /* Section Header — labeled section intro */
1852
- .v-section-header {
1853
- display: flex;
1854
- flex-direction: column;
1855
- gap: var(--v-spacing-xs);
1856
- margin-bottom: var(--v-spacing-lg);
1857
- }
1858
- .v-section-label {
1859
- font-size: var(--v-font-size-xs);
1860
- font-weight: 600;
1861
- text-transform: uppercase;
1862
- letter-spacing: 0.06em;
1863
- color: var(--v-primary-base);
1864
- }
1865
- .v-section-header h2 {
1866
- margin: 0;
1867
- }
1868
- .v-section-desc {
1869
- font-size: var(--v-font-size-base);
1870
- color: var(--v-content-secondary);
1871
- margin: 0;
1872
- }
1873
-
1874
- /* Pullquote — dramatic blockquote with glassmorphism */
1875
- .v-pullquote {
1876
- position: relative;
1877
- background: var(--v-surface-base);
1878
- border: 1px solid var(--v-border-base);
1879
- border-radius: var(--v-radius-lg);
1880
- padding: var(--v-spacing-xl);
1881
- display: flex;
1882
- flex-direction: column;
1883
- gap: var(--v-spacing-md);
1884
- }
1885
- .v-pullquote::before {
1886
- content: "";
1887
- position: absolute;
1888
- left: 0;
1889
- top: var(--v-spacing-lg);
1890
- bottom: var(--v-spacing-lg);
1891
- width: 3px;
1892
- background: linear-gradient(
1893
- 180deg,
1894
- var(--v-primary-hover) 0%,
1895
- var(--v-primary-active) 100%
1896
- );
1897
- border-radius: var(--v-radius-pill);
1898
- }
1899
- .v-pullquote-text {
1900
- font-size: var(--v-font-size-lg);
1901
- font-style: italic;
1902
- color: var(--v-content-default);
1903
- line-height: 1.5;
1904
- margin: 0;
1905
- padding-left: var(--v-spacing-lg);
1906
- }
1907
- .v-pullquote-points {
1908
- list-style: none;
1909
- padding: 0;
1910
- margin: 0;
1911
- display: flex;
1912
- flex-direction: column;
1913
- gap: var(--v-spacing-sm);
1914
- padding-left: var(--v-spacing-lg);
1915
- }
1916
- .v-pullquote-points li {
1917
- position: relative;
1918
- padding-left: var(--v-spacing-lg);
1919
- font-size: var(--v-font-size-base);
1920
- color: var(--v-content-secondary);
1921
- }
1922
- .v-pullquote-points li::before {
1923
- content: "";
1924
- position: absolute;
1925
- left: 0;
1926
- top: 0.55em;
1927
- width: 6px;
1928
- height: 6px;
1929
- border-radius: 50%;
1930
- background: var(--v-primary-base);
1931
- }
1932
-
1933
- /* Comparison — before/after or contrasting ideas */
1934
- .v-comparison {
1935
- display: grid;
1936
- grid-template-columns: 1fr auto 1fr;
1937
- gap: var(--v-spacing-md);
1938
- align-items: center;
1939
- }
1940
- .v-comparison-card {
1941
- background: var(--v-surface-base);
1942
- border: 1px solid var(--v-border-base);
1943
- border-radius: var(--v-radius-lg);
1944
- padding: var(--v-spacing-lg);
1945
- display: flex;
1946
- flex-direction: column;
1947
- gap: var(--v-spacing-sm);
1948
- }
1949
- .v-comparison-card.before {
1950
- background: color-mix(
1951
- in srgb,
1952
- var(--v-surface-base) 60%,
1953
- var(--v-surface-overlay)
1954
- );
1955
- }
1956
- .v-comparison-card.before .v-comparison-label {
1957
- color: var(--v-content-tertiary);
1958
- }
1959
- .v-comparison-card.after {
1960
- background: color-mix(
1961
- in srgb,
1962
- var(--v-primary-base) 8%,
1963
- var(--v-surface-base)
1964
- );
1965
- border-color: color-mix(
1966
- in srgb,
1967
- var(--v-primary-base) 25%,
1968
- var(--v-border-base)
1969
- );
1970
- }
1971
- .v-comparison-card.after .v-comparison-label {
1972
- color: var(--v-primary-base);
1973
- }
1974
- .v-comparison-label {
1975
- font-size: var(--v-font-size-xs);
1976
- font-weight: 600;
1977
- text-transform: uppercase;
1978
- letter-spacing: 0.06em;
1979
- }
1980
- .v-comparison-arrow {
1981
- font-size: var(--v-font-size-xl);
1982
- color: var(--v-content-tertiary);
1983
- text-align: center;
1984
- }
1985
-
1986
- /* Feature Grid — auto-fit grid of feature cards */
1987
- .v-feature-grid {
1988
- display: grid;
1989
- grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
1990
- gap: var(--v-spacing-lg);
1991
- }
1992
- .v-feature-card {
1993
- background: var(--v-surface-base);
1994
- border: 1px solid var(--v-border-base);
1995
- border-radius: var(--v-radius-lg);
1996
- padding: var(--v-spacing-lg);
1997
- display: flex;
1998
- flex-direction: column;
1999
- gap: var(--v-spacing-sm);
2000
- transition:
2001
- transform var(--v-duration-fast) ease-out,
2002
- box-shadow var(--v-duration-fast) ease-out;
2003
- }
2004
- .v-feature-card:hover {
2005
- transform: translateY(-2px);
2006
- box-shadow: var(--v-shadow-md);
2007
- }
2008
- .v-feature-card .v-feature-icon {
2009
- font-size: 24px;
2010
- line-height: 1;
2011
- }
2012
- .v-feature-card .v-feature-title {
2013
- font-size: var(--v-font-size-base);
2014
- font-weight: 600;
2015
- color: var(--v-content-default);
2016
- }
2017
- .v-feature-card .v-feature-desc {
2018
- font-size: var(--v-font-size-sm);
2019
- color: var(--v-content-secondary);
2020
- line-height: 1.4;
2021
- }
2022
-
2023
- /* Gradient Text — forest gradient text fill */
2024
- .v-gradient-text {
2025
- background: linear-gradient(
2026
- 135deg,
2027
- var(--v-primary-active) 0%,
2028
- var(--v-system-positive-weak) 100%
2029
- );
2030
- -webkit-background-clip: text;
2031
- -webkit-text-fill-color: transparent;
2032
- background-clip: text;
2033
- }
2034
-
2035
- /* Staggered Fade-In Animation */
2036
- @keyframes v-fade-in {
2037
- from {
2038
- opacity: 0;
2039
- transform: translateY(12px);
2040
- }
2041
- to {
2042
- opacity: 1;
2043
- transform: translateY(0);
2044
- }
2045
- }
2046
- .v-animate-in {
2047
- animation: v-fade-in var(--v-duration-slow) ease-out both;
2048
- }
2049
- .v-animate-in:nth-child(1) {
2050
- animation-delay: 0s;
2051
- }
2052
- .v-animate-in:nth-child(2) {
2053
- animation-delay: 0.1s;
2054
- }
2055
- .v-animate-in:nth-child(3) {
2056
- animation-delay: 0.2s;
2057
- }
2058
- .v-animate-in:nth-child(4) {
2059
- animation-delay: 0.3s;
2060
- }
2061
- .v-animate-in:nth-child(5) {
2062
- animation-delay: 0.4s;
2063
- }
2064
- .v-animate-in:nth-child(6) {
2065
- animation-delay: 0.5s;
2066
- }
2067
-
2068
- /* ── Pill Toggles — time range / filter toggle group ────────── */
2069
- .v-pill-toggles {
2070
- display: inline-flex;
2071
- gap: var(--v-spacing-xxs);
2072
- background: var(--v-surface-base);
2073
- border: 1px solid var(--v-border-base);
2074
- border-radius: var(--v-radius-md);
2075
- padding: var(--v-spacing-xxs);
2076
- }
2077
- .v-pill-toggle {
2078
- padding: var(--v-spacing-xs) var(--v-spacing-md);
2079
- border-radius: var(--v-radius-md);
2080
- border: none;
2081
- background: none;
2082
- font-size: var(--v-font-size-sm);
2083
- font-weight: 500;
2084
- color: var(--v-content-secondary);
2085
- cursor: pointer;
2086
- transition: all var(--v-duration-fast) ease-out;
2087
- }
2088
- .v-pill-toggle:hover {
2089
- color: var(--v-content-default);
2090
- }
2091
- .v-pill-toggle.active {
2092
- background: var(--v-primary-base);
2093
- color: var(--v-aux-white);
2094
- font-weight: 600;
2095
- box-shadow: var(--v-shadow-sm);
2096
- }
2097
-
2098
- /* ── Chip Group — suggestion / filter chip row ─────────────── */
2099
- .v-chip-group {
2100
- display: flex;
2101
- flex-wrap: wrap;
2102
- gap: var(--v-spacing-xs);
2103
- }
2104
- .v-chip {
2105
- padding: var(--v-spacing-xs) var(--v-spacing-md);
2106
- border-radius: var(--v-radius-md);
2107
- border: 1px solid var(--v-border-base);
2108
- background: var(--v-surface-base);
2109
- font-size: var(--v-font-size-sm);
2110
- color: var(--v-content-secondary);
2111
- cursor: pointer;
2112
- transition: all var(--v-duration-fast) ease-out;
2113
- }
2114
- .v-chip:hover {
2115
- border-color: var(--v-primary-base);
2116
- color: var(--v-content-default);
2117
- }
2118
- .v-chip.active {
2119
- background: color-mix(in srgb, var(--v-primary-base) 12%, transparent);
2120
- border-color: var(--v-primary-base);
2121
- color: var(--v-primary-base);
2122
- font-weight: 600;
2123
- }
2124
-
2125
- /* ── Metric Icon — emoji icon for metric cards ─────────────── */
2126
- .v-metric-card .v-metric-icon {
2127
- font-size: 28px;
2128
- line-height: 1;
2129
- }
2130
-
2131
- /* ── Action Bar — sticky bulk-action bar for multi-select UIs ── */
2132
- .v-action-bar {
2133
- position: sticky;
2134
- top: 0;
2135
- z-index: 100;
2136
- display: none;
2137
- align-items: center;
2138
- gap: var(--v-spacing-md);
2139
- padding: var(--v-spacing-sm) var(--v-spacing-lg);
2140
- background: var(--v-surface-base);
2141
- border-bottom: 1px solid var(--v-border-base);
2142
- backdrop-filter: blur(12px);
2143
- -webkit-backdrop-filter: blur(12px);
2144
- }
2145
- .v-action-bar.visible {
2146
- display: flex;
2147
- }
2148
- .v-action-bar-count {
2149
- font-size: var(--v-font-size-sm);
2150
- font-weight: 600;
2151
- color: var(--v-primary-base);
2152
- white-space: nowrap;
2153
- }
2154
- .v-action-bar-buttons {
2155
- display: flex;
2156
- gap: var(--v-spacing-sm);
2157
- margin-left: auto;
2158
- }
2159
-
2160
- /* ── Action Progress — inline progress bar during bulk ops ───── */
2161
- .v-action-progress {
2162
- width: 100%;
2163
- height: 4px;
2164
- border-radius: var(--v-radius-pill);
2165
- background: var(--v-border-base);
2166
- overflow: hidden;
2167
- }
2168
- .v-action-progress::after {
2169
- content: "";
2170
- display: block;
2171
- height: 100%;
2172
- width: var(--progress, 0%);
2173
- background: var(--v-primary-base);
2174
- border-radius: var(--v-radius-pill);
2175
- transition: width 0.3s ease-out;
2176
- }
2177
-
2178
- /* ── Group Header — collapsible section with checkbox + chevron ─ */
2179
- .v-group-header {
2180
- display: flex;
2181
- align-items: center;
2182
- gap: var(--v-spacing-sm);
2183
- padding: var(--v-spacing-sm) var(--v-spacing-md);
2184
- background: color-mix(in srgb, var(--v-surface-base) 60%, transparent);
2185
- border-radius: var(--v-radius-md);
2186
- cursor: pointer;
2187
- user-select: none;
2188
- -webkit-user-select: none;
2189
- transition: background var(--v-duration-fast) ease-out;
2190
- }
2191
- .v-group-header:hover {
2192
- background: var(--v-surface-base);
2193
- }
2194
- .v-group-header .v-group-title {
2195
- flex: 1;
2196
- font-weight: 600;
2197
- font-size: var(--v-font-size-base);
2198
- color: var(--v-content-default);
2199
- }
2200
- .v-group-header .v-group-count {
2201
- font-size: var(--v-font-size-sm);
2202
- color: var(--v-content-tertiary);
2203
- }
2204
- .v-group-header .v-group-chevron {
2205
- font-size: 12px;
2206
- color: var(--v-content-tertiary);
2207
- transition: transform var(--v-duration-fast) ease-out;
2208
- }
2209
- .v-group-header[aria-expanded="true"] .v-group-chevron {
2210
- transform: rotate(90deg);
2211
- }
2212
-
2213
- /* ── Group Body — indented container for group items ─────────── */
2214
- .v-group-body {
2215
- padding-left: var(--v-spacing-xl);
2216
- overflow: hidden;
2217
- }
2218
-
2219
- /* ── Row Removing — fade-out + slide animation for processed items */
2220
- .v-row-removing {
2221
- opacity: 0;
2222
- transform: translateX(20px);
2223
- max-height: 0;
2224
- padding-top: 0 !important;
2225
- padding-bottom: 0 !important;
2226
- margin-top: 0 !important;
2227
- margin-bottom: 0 !important;
2228
- overflow: hidden;
2229
- transition:
2230
- opacity 0.25s ease-out,
2231
- transform 0.25s ease-out,
2232
- max-height 0.3s 0.1s ease-out,
2233
- padding 0.3s 0.1s ease-out,
2234
- margin 0.3s 0.1s ease-out;
2235
- }
2236
- } /* end @layer vellum-design-system */