@vellumai/assistant 0.9.0 → 0.10.0-staging.2

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 (572) hide show
  1. package/ARCHITECTURE.md +18 -34
  2. package/bun.lock +7 -8
  3. package/docs/activation-funnel-telemetry.md +28 -22
  4. package/docs/architecture/security.md +29 -28
  5. package/docs/stt-provider-onboarding.md +3 -5
  6. package/docs/workflows-testing.md +13 -44
  7. package/docs/workflows.md +3 -5
  8. package/node_modules/@vellumai/ces-client/src/__tests__/ces-client.test.ts +47 -0
  9. package/node_modules/@vellumai/ces-client/src/rpc-client.ts +28 -5
  10. package/node_modules/@vellumai/environments/src/seeds.ts +2 -5
  11. package/node_modules/@vellumai/gateway-client/src/admission-policy-contract.ts +97 -0
  12. package/node_modules/@vellumai/gateway-client/src/inbound-contract.ts +10 -0
  13. package/node_modules/@vellumai/gateway-client/src/index.ts +32 -6
  14. package/node_modules/@vellumai/gateway-client/src/outbound-contract.ts +119 -0
  15. package/node_modules/@vellumai/gateway-client/src/types.ts +15 -84
  16. package/openapi.yaml +976 -63
  17. package/package.json +2 -1
  18. package/scripts/sync-llm-catalog.ts +6 -15
  19. package/scripts/sync-web-search-catalog.ts +3 -11
  20. package/src/__tests__/access-request-card-view.test.ts +98 -0
  21. package/src/__tests__/access-request-seed-content-blocks.test.ts +2 -4
  22. package/src/__tests__/actor-trust-resolver-address-fallback.test.ts +72 -32
  23. package/src/__tests__/agent-loop-compaction-strip.test.ts +241 -0
  24. package/src/__tests__/agent-loop-mutable-latest-user-message.test.ts +16 -13
  25. package/src/__tests__/agent-loop-output-hooks.test.ts +69 -0
  26. package/src/__tests__/agent-loop-override-profile.test.ts +25 -0
  27. package/src/__tests__/always-loaded-tools-guard.test.ts +2 -3
  28. package/src/__tests__/app-compiler.test.ts +15 -1
  29. package/src/__tests__/app-dir-path-guard.test.ts +0 -1
  30. package/src/__tests__/assistant-feature-flag-guard.test.ts +1 -4
  31. package/src/__tests__/assistant-feature-flag-guardrails.test.ts +0 -2
  32. package/src/__tests__/auth-fallback-events-store.test.ts +6 -14
  33. package/src/__tests__/avatar-identity-sync.test.ts +2 -27
  34. package/src/__tests__/btw-routes.test.ts +6 -8
  35. package/src/__tests__/call-pointer-messages.test.ts +28 -0
  36. package/src/__tests__/cancel-clears-processing.test.ts +89 -0
  37. package/src/__tests__/channel-approval-routes.test.ts +0 -4
  38. package/src/__tests__/channel-inbound-disk-pressure.test.ts +5 -15
  39. package/src/__tests__/checker.test.ts +0 -3
  40. package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +3 -4
  41. package/src/__tests__/compactor-image-manifest-trust.test.ts +21 -1
  42. package/src/__tests__/compactor-summary-call-truncation.test.ts +223 -0
  43. package/src/__tests__/config-loader-backfill.test.ts +268 -27
  44. package/src/__tests__/config-schema.test.ts +35 -0
  45. package/src/__tests__/config-watcher.test.ts +0 -18
  46. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +2 -2
  47. package/src/__tests__/contact-store-user-file.test.ts +0 -6
  48. package/src/__tests__/contacts-tools.test.ts +29 -0
  49. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +22 -0
  50. package/src/__tests__/conversation-agent-loop-overflow.test.ts +1 -0
  51. package/src/__tests__/conversation-agent-loop.test.ts +58 -0
  52. package/src/__tests__/conversation-attention-telegram.test.ts +0 -1
  53. package/src/__tests__/conversation-lifecycle.test.ts +7 -9
  54. package/src/__tests__/conversation-load-history-repair.test.ts +101 -0
  55. package/src/__tests__/conversation-routes-guardian-reply.test.ts +15 -12
  56. package/src/__tests__/conversation-surfaces-activation-emit.test.ts +6 -3
  57. package/src/__tests__/conversation-title-service.test.ts +62 -0
  58. package/src/__tests__/credential-broker.test.ts +449 -1
  59. package/src/__tests__/credential-execution-shell-lockdown.test.ts +18 -11
  60. package/src/__tests__/credential-execution-tools.test.ts +0 -1
  61. package/src/__tests__/credential-prompt-route.test.ts +4 -4
  62. package/src/__tests__/credential-routes.test.ts +360 -0
  63. package/src/__tests__/credential-security-invariants.test.ts +4 -13
  64. package/src/__tests__/disk-pressure-policy.test.ts +12 -0
  65. package/src/__tests__/disk-usage.test.ts +65 -0
  66. package/src/__tests__/dynamic-page-surface.test.ts +152 -1
  67. package/src/__tests__/fixtures/credential-security-fixtures.ts +2 -33
  68. package/src/__tests__/gateway-flag-listener.test.ts +110 -1
  69. package/src/__tests__/gateway-only-guard.test.ts +3 -7
  70. package/src/__tests__/guardian-binding-drift-heal.test.ts +1 -1
  71. package/src/__tests__/guardian-card-withdrawal.test.ts +403 -0
  72. package/src/__tests__/guardian-decision-primitive-canonical.test.ts +5 -3
  73. package/src/__tests__/guardian-grant-minting.test.ts +3 -35
  74. package/src/__tests__/guardian-routing-invariants.test.ts +64 -26
  75. package/src/__tests__/guardian-routing-state.test.ts +0 -1
  76. package/src/__tests__/headless-browser-mode.test.ts +10 -0
  77. package/src/__tests__/headless-browser-navigate.test.ts +8 -3
  78. package/src/__tests__/helpers/create-guardian-binding.ts +0 -1
  79. package/src/__tests__/host-browser-proxy.test.ts +87 -0
  80. package/src/__tests__/identity-routes.test.ts +0 -189
  81. package/src/__tests__/inbound-invite-redemption.test.ts +4 -4
  82. package/src/__tests__/injector-v3-suppression.test.ts +27 -20
  83. package/src/__tests__/internal-telemetry-routes.test.ts +6 -14
  84. package/src/__tests__/invite-redemption-service.test.ts +4 -7
  85. package/src/__tests__/llm-callsite-catalog.test.ts +5 -6
  86. package/src/__tests__/llm-catalog-parity.test.ts +30 -23
  87. package/src/__tests__/llm-resolver.test.ts +70 -24
  88. package/src/__tests__/llm-schema.test.ts +1 -0
  89. package/src/__tests__/managed-profile-guard.test.ts +163 -4
  90. package/src/__tests__/mcp-health-check.test.ts +6 -7
  91. package/src/__tests__/media-stream-server-integration.test.ts +317 -13
  92. package/src/__tests__/oauth-provider-seed-logos.test.ts +4 -6
  93. package/src/__tests__/onboarding-persona-write.test.ts +1 -1
  94. package/src/__tests__/path-policy.test.ts +34 -0
  95. package/src/__tests__/persona-resolver.test.ts +49 -14
  96. package/src/__tests__/plugin-api-model-profiles.test.ts +178 -0
  97. package/src/__tests__/plugin-api-provider.test.ts +24 -0
  98. package/src/__tests__/plugin-tool-contribution.test.ts +6 -3
  99. package/src/__tests__/post-compaction-reinjection-idempotency.test.ts +214 -0
  100. package/src/__tests__/provider-send-message-override-profile.test.ts +76 -0
  101. package/src/__tests__/reaction-persistence.test.ts +150 -29
  102. package/src/__tests__/registry.test.ts +2 -7
  103. package/src/__tests__/relay-server.test.ts +285 -0
  104. package/src/__tests__/runtime-attachment-metadata.test.ts +0 -1
  105. package/src/__tests__/schedule-routes-workflow-validation.test.ts +1 -10
  106. package/src/__tests__/schedule-routes.test.ts +0 -30
  107. package/src/__tests__/schedule-tools.test.ts +2 -18
  108. package/src/__tests__/scheduler-reuse-conversation.test.ts +8 -5
  109. package/src/__tests__/skill-execute-input.test.ts +51 -1
  110. package/src/__tests__/skill-runtime-path.test.ts +2 -3
  111. package/src/__tests__/skills.test.ts +51 -0
  112. package/src/__tests__/slack-notification-approval-card.test.ts +176 -0
  113. package/src/__tests__/slack-reaction-canonical-approval.test.ts +285 -0
  114. package/src/__tests__/subagent-tools.test.ts +266 -0
  115. package/src/__tests__/surface-completion-nudge-hook.test.ts +367 -0
  116. package/src/__tests__/task-progress-nudge-hook.test.ts +1 -1
  117. package/src/__tests__/title-generate-hook.test.ts +100 -3
  118. package/src/__tests__/token-estimator-accuracy.benchmark.test.ts +1 -29
  119. package/src/__tests__/token-manager.test.ts +519 -0
  120. package/src/__tests__/tool-approval-seed-content-blocks.test.ts +1 -1
  121. package/src/__tests__/tool-audit-listener.test.ts +7 -7
  122. package/src/__tests__/tool-executor-lifecycle-events.test.ts +6 -3
  123. package/src/__tests__/tool-executor.test.ts +0 -79
  124. package/src/__tests__/trusted-contact-approval-notifier.test.ts +4 -2
  125. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +220 -3
  126. package/src/__tests__/trusted-contact-multichannel.test.ts +3 -3
  127. package/src/__tests__/trusted-contact-verification.test.ts +8 -10
  128. package/src/__tests__/twilio-routes.test.ts +81 -1
  129. package/src/__tests__/voice-invite-redemption.test.ts +2 -3
  130. package/src/__tests__/weak-open-model.test.ts +30 -0
  131. package/src/__tests__/web-search-catalog-parity.test.ts +6 -25
  132. package/src/__tests__/workspace-greetings.test.ts +152 -0
  133. package/src/__tests__/workspace-migration-105-enable-memory-v3-live-for-new-workspaces.test.ts +149 -0
  134. package/src/__tests__/workspace-migration-108-drop-balanced-economy-profile.test.ts +285 -0
  135. package/src/__tests__/workspace-migration-add-send-diagnostics.test.ts +1 -1
  136. package/src/__tests__/workspace-migration-drop-collect-usage-data.test.ts +118 -0
  137. package/src/__tests__/workspace-migration-drop-send-diagnostics.test.ts +118 -0
  138. package/src/a2a/__tests__/e2e-a2a-channel.test.ts +0 -4
  139. package/src/agent/loop.ts +49 -29
  140. package/src/api/README.md +6 -6
  141. package/src/api/events/tool-result.ts +6 -0
  142. package/src/api/events/workflow-completed.ts +53 -0
  143. package/src/api/events/workflow-leaf-finished.ts +38 -0
  144. package/src/api/events/workflow-leaf-started.ts +35 -0
  145. package/src/api/events/workflow-progress.ts +32 -0
  146. package/src/api/events/workflow-started.ts +31 -0
  147. package/src/api/index.ts +40 -0
  148. package/src/api/responses/conversation-message.ts +28 -4
  149. package/src/api/responses/home.ts +26 -4
  150. package/src/api/responses/workflow-journal.ts +53 -0
  151. package/src/approvals/guardian-card-withdrawal.ts +145 -0
  152. package/src/approvals/guardian-decision-primitive.ts +26 -3
  153. package/src/approvals/guardian-request-resolvers.ts +183 -80
  154. package/src/calls/__tests__/channel-admission-reader.test.ts +132 -0
  155. package/src/calls/__tests__/relay-setup-router.test.ts +350 -0
  156. package/src/calls/call-pointer-messages.ts +10 -4
  157. package/src/calls/channel-admission-reader.ts +104 -0
  158. package/src/calls/guardian-dispatch.ts +17 -45
  159. package/src/calls/media-stream-server.ts +84 -2
  160. package/src/calls/relay-access-wait.ts +1 -1
  161. package/src/calls/relay-server.ts +66 -0
  162. package/src/calls/relay-setup-router.ts +82 -1
  163. package/src/calls/twilio-routes.ts +17 -8
  164. package/src/calls/voice-session-bridge.ts +2 -2
  165. package/src/cli/commands/clients.ts +3 -0
  166. package/src/cli/commands/{__tests__ → memory/__tests__}/memory-v2-compare-render.test.ts +1 -1
  167. package/src/cli/commands/{__tests__ → memory/__tests__}/memory-v2.test.ts +8 -7
  168. package/src/cli/commands/{__tests__ → memory/__tests__}/memory-v3.test.ts +5 -4
  169. package/src/cli/commands/memory/index.ts +30 -0
  170. package/src/cli/commands/{memory-v2-compare-render.ts → memory/memory-v2-compare-render.ts} +1 -1
  171. package/src/cli/commands/{memory-v2.ts → memory/memory-v2.ts} +6 -15
  172. package/src/cli/commands/{memory-v3.ts → memory/memory-v3.ts} +97 -11
  173. package/src/cli/commands/oauth/status.test.ts +36 -0
  174. package/src/cli/commands/oauth/status.ts +23 -3
  175. package/src/cli/commands/plugins.ts +197 -4
  176. package/src/cli/lib/__tests__/diff-plugin.test.ts +443 -0
  177. package/src/cli/lib/__tests__/inspect-plugin.test.ts +54 -0
  178. package/src/cli/lib/__tests__/merge-plugin-tree.test.ts +443 -0
  179. package/src/cli/lib/__tests__/plugin-surfaces.test.ts +111 -0
  180. package/src/cli/lib/__tests__/upgrade-plugin.test.ts +295 -2
  181. package/src/cli/lib/diff-plugin.ts +346 -0
  182. package/src/cli/lib/inspect-plugin.ts +12 -1
  183. package/src/cli/lib/install-from-github.ts +105 -17
  184. package/src/cli/lib/merge-plugin-tree.ts +328 -0
  185. package/src/cli/lib/plugin-fingerprint.ts +14 -0
  186. package/src/cli/lib/plugin-surfaces.ts +104 -0
  187. package/src/cli/lib/upgrade-plugin.ts +298 -10
  188. package/src/cli/program.ts +2 -6
  189. package/src/config/__tests__/sync-gated-profiles.test.ts +368 -0
  190. package/src/config/assistant-feature-flags.ts +22 -7
  191. package/src/config/bundled-skills/contacts/tools/contact-search.ts +0 -1
  192. package/src/config/bundled-skills/messaging/SKILL.md +6 -4
  193. package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +9 -8
  194. package/src/config/bundled-skills/subagent/SKILL.md +4 -0
  195. package/src/config/bundled-skills/subagent/TOOLS.json +4 -0
  196. package/src/config/bundled-skills/workflows/SKILL.md +14 -8
  197. package/src/config/bundled-tool-registry.ts +2 -7
  198. package/src/config/call-site-defaults.ts +15 -2
  199. package/src/config/feature-flag-registry.json +46 -31
  200. package/src/config/inference-profile-validation.ts +26 -0
  201. package/src/config/llm-resolver.ts +3 -0
  202. package/src/config/loader.ts +4 -0
  203. package/src/config/memory-v3-gate.ts +11 -0
  204. package/src/config/profile-order.ts +28 -0
  205. package/src/config/schema.ts +8 -6
  206. package/src/config/schemas/__tests__/memory-v3.test.ts +1 -0
  207. package/src/config/schemas/call-site-catalog.ts +7 -0
  208. package/src/config/schemas/channels.ts +11 -0
  209. package/src/config/schemas/elevenlabs.ts +0 -1
  210. package/src/config/schemas/llm.ts +31 -0
  211. package/src/config/schemas/memory-lifecycle.ts +3 -7
  212. package/src/config/schemas/memory-v3.ts +6 -0
  213. package/src/config/schemas/platform.ts +0 -8
  214. package/src/config/schemas/services.ts +18 -0
  215. package/src/config/seed-inference-profiles.ts +109 -44
  216. package/src/config/skills.ts +21 -0
  217. package/src/config/sync-gated-profiles.ts +220 -0
  218. package/src/contacts/contact-store.ts +89 -106
  219. package/src/contacts/contacts-write.ts +5 -22
  220. package/src/contacts/types.ts +0 -1
  221. package/src/context/compactor.ts +88 -54
  222. package/src/context/strip-injections.ts +58 -10
  223. package/src/context/token-estimator.ts +1 -1
  224. package/src/credential-execution/process-manager.ts +55 -14
  225. package/src/credential-execution/prompted-credential.ts +2 -3
  226. package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +3 -2
  227. package/src/daemon/config-watcher.ts +0 -4
  228. package/src/daemon/conversation-agent-loop-handlers.ts +2 -0
  229. package/src/daemon/conversation-agent-loop.ts +114 -22
  230. package/src/daemon/conversation-history.ts +1 -1
  231. package/src/daemon/conversation-lifecycle.ts +3 -5
  232. package/src/daemon/conversation-process.ts +13 -5
  233. package/src/daemon/conversation-runtime-assembly.ts +13 -15
  234. package/src/daemon/conversation-slash.ts +2 -23
  235. package/src/daemon/conversation-surfaces.ts +26 -0
  236. package/src/daemon/conversation-tool-setup.ts +27 -14
  237. package/src/daemon/conversation.ts +66 -14
  238. package/src/daemon/disk-pressure-policy.ts +5 -3
  239. package/src/daemon/handlers/__tests__/config-a2a-complete.test.ts +0 -1
  240. package/src/daemon/handlers/__tests__/config-a2a-redeem.test.ts +0 -1
  241. package/src/daemon/handlers/config-a2a.ts +0 -2
  242. package/src/daemon/handlers/config-channels.ts +15 -16
  243. package/src/daemon/handlers/config-slack-channel.ts +22 -3
  244. package/src/daemon/handlers/conversations.ts +107 -0
  245. package/src/daemon/host-browser-proxy.ts +41 -0
  246. package/src/daemon/lifecycle.ts +55 -27
  247. package/src/daemon/message-provenance.ts +2 -0
  248. package/src/daemon/message-types/contacts.ts +0 -1
  249. package/src/daemon/message-types/conversations.ts +3 -3
  250. package/src/daemon/message-types/sync.ts +0 -1
  251. package/src/daemon/message-types/web-activity.ts +7 -1
  252. package/src/daemon/message-types/workflows.ts +83 -1
  253. package/src/daemon/orphan-reaper.test.ts +0 -19
  254. package/src/daemon/orphan-reaper.ts +2 -24
  255. package/src/daemon/server.ts +0 -10
  256. package/src/daemon/tool-setup-types.ts +4 -0
  257. package/src/daemon/trust-context.ts +1 -1
  258. package/src/events/tool-audit-listener.ts +2 -2
  259. package/src/home/feed-source-enrichment.test.ts +151 -0
  260. package/src/home/feed-source-enrichment.ts +176 -0
  261. package/src/home/relationship-state.ts +2 -4
  262. package/src/instrument.ts +18 -6
  263. package/src/ipc/__tests__/binary-result-ipc.test.ts +81 -0
  264. package/src/ipc/__tests__/clients-list-ipc.test.ts +20 -0
  265. package/src/ipc/assistant-server.ts +37 -4
  266. package/src/ipc/gateway-flag-listener.ts +18 -2
  267. package/src/memory/__tests__/auto-analysis-enqueue.test.ts +5 -16
  268. package/src/memory/__tests__/jobs-store-enqueue-gate.test.ts +7 -11
  269. package/src/memory/__tests__/memory-retrospective-enqueue.test.ts +37 -7
  270. package/src/memory/__tests__/memory-retrospective-job.test.ts +229 -401
  271. package/src/memory/__tests__/onboarding-events-store.test.ts +7 -7
  272. package/src/memory/auth-fallback-events-store.ts +2 -2
  273. package/src/memory/auto-analysis-enqueue.ts +3 -5
  274. package/src/memory/bookmark-crud.ts +1 -2
  275. package/src/memory/canonical-guardian-store.ts +39 -1
  276. package/src/memory/conversation-crud.ts +9 -4
  277. package/src/memory/conversation-key-store.ts +17 -2
  278. package/src/memory/conversation-title-service.ts +64 -7
  279. package/src/memory/db-init.ts +17 -17
  280. package/src/memory/embedding-backend.ts +38 -1
  281. package/src/memory/embedding-billing-breaker.ts +96 -0
  282. package/src/memory/jobs-store.ts +25 -13
  283. package/src/memory/jobs-worker.ts +54 -1
  284. package/src/memory/lifecycle-events-store.ts +2 -2
  285. package/src/memory/memory-retrospective-constants.ts +4 -4
  286. package/src/memory/memory-retrospective-enqueue.ts +31 -6
  287. package/src/memory/memory-retrospective-job.ts +28 -227
  288. package/src/memory/migrations/129-contact-channels-access-fields.ts +18 -9
  289. package/src/memory/migrations/131-drop-legacy-member-guardian-tables.ts +14 -2
  290. package/src/memory/migrations/289-contact-channels-unique-ext-user.ts +10 -0
  291. package/src/memory/migrations/291-contact-channels-renormalize-addresses.ts +72 -0
  292. package/src/memory/migrations/292-schedule-default-no-reuse-conversation.test.ts +67 -0
  293. package/src/memory/migrations/292-schedule-default-no-reuse-conversation.ts +25 -0
  294. package/src/memory/migrations/293-workflow-journal-leaf-tokens.ts +32 -0
  295. package/src/memory/migrations/294-drop-external-user-id.ts +31 -0
  296. package/src/memory/migrations/295-drop-approval-prompt-ts-tracker.ts +20 -0
  297. package/src/memory/migrations/296-rewrite-balanced-economy-profile-pins.test.ts +110 -0
  298. package/src/memory/migrations/296-rewrite-balanced-economy-profile-pins.ts +68 -0
  299. package/src/memory/migrations/__tests__/131-drop-legacy-member-guardian-tables.test.ts +154 -0
  300. package/src/memory/migrations/__tests__/289-contact-channels-unique-ext-user.test.ts +31 -0
  301. package/src/memory/migrations/__tests__/291-contact-channels-renormalize-addresses.test.ts +341 -0
  302. package/src/memory/migrations/__tests__/run-migrations.test.ts +52 -0
  303. package/src/memory/migrations/index.ts +6 -0
  304. package/src/memory/migrations/run-migrations.ts +41 -0
  305. package/src/memory/migrations/validate-migration-state.ts +1 -1
  306. package/src/memory/onboarding-events-store.ts +3 -3
  307. package/src/memory/schema/contacts.ts +0 -5
  308. package/src/memory/skill-loaded-events-store.test.ts +7 -15
  309. package/src/memory/skill-loaded-events-store.ts +2 -2
  310. package/src/memory/tool-executed-events-store.test.ts +7 -7
  311. package/src/memory/turn-trace-store.test.ts +736 -0
  312. package/src/memory/turn-trace-store.ts +364 -0
  313. package/src/memory/v2/__tests__/consolidation-job.test.ts +8 -0
  314. package/src/memory/v2/__tests__/skill-content.test.ts +30 -0
  315. package/src/memory/v2/consolidation-job.ts +2 -2
  316. package/src/memory/v2/skill-content.ts +25 -7
  317. package/src/memory/v2/skill-store.ts +7 -1
  318. package/src/memory/v3-eval/__tests__/eval-packets.test.ts +248 -0
  319. package/src/memory/v3-eval/eval-packets.ts +546 -0
  320. package/src/messaging/providers/slack/adapter.ts +1 -1
  321. package/src/messaging/providers/slack/api.ts +31 -0
  322. package/src/messaging/providers/slack/send.test.ts +114 -2
  323. package/src/messaging/providers/slack/send.ts +30 -7
  324. package/src/messaging/providers/slack/withdraw.test.ts +200 -0
  325. package/src/messaging/providers/slack/withdraw.ts +161 -0
  326. package/src/notifications/AGENTS.md +2 -0
  327. package/src/notifications/access-request-copy.ts +72 -59
  328. package/src/notifications/adapters/shared.ts +29 -0
  329. package/src/notifications/adapters/slack.ts +58 -103
  330. package/src/notifications/adapters/telegram.ts +2 -20
  331. package/src/notifications/approval-card-data.ts +333 -0
  332. package/src/notifications/broadcaster.ts +16 -3
  333. package/src/notifications/canonical-delivery-recorder.ts +139 -0
  334. package/src/notifications/copy-composer.ts +3 -3
  335. package/src/notifications/decision-engine.ts +4 -2
  336. package/src/notifications/destination-resolver.ts +4 -6
  337. package/src/notifications/guardian-question-mode.ts +10 -0
  338. package/src/notifications/home-feed-side-effect.ts +7 -16
  339. package/src/notifications/notification-utils.ts +19 -20
  340. package/src/notifications/signal.ts +79 -43
  341. package/src/notifications/types.ts +98 -121
  342. package/src/oauth/AGENTS.md +5 -24
  343. package/src/permissions/checker.test.ts +51 -0
  344. package/src/permissions/checker.ts +185 -26
  345. package/src/permissions/ipc-risk-types.ts +24 -0
  346. package/src/permissions/question-prompter.test.ts +27 -0
  347. package/src/permissions/question-prompter.ts +4 -0
  348. package/src/platform/client.test.ts +119 -0
  349. package/src/platform/client.ts +66 -0
  350. package/src/platform/consent-cache.test.ts +267 -0
  351. package/src/platform/consent-cache.ts +174 -0
  352. package/src/plugin-api/constants.ts +1 -1
  353. package/src/plugin-api/index.ts +33 -1
  354. package/src/plugin-api/model-profiles.ts +33 -0
  355. package/src/plugin-api/types.ts +50 -2
  356. package/src/plugins/defaults/advisor/__tests__/advisor-gate.test.ts +56 -0
  357. package/src/plugins/defaults/advisor/__tests__/advisor-state-store.test.ts +43 -0
  358. package/src/plugins/defaults/advisor/__tests__/agent-loop-integration.test.ts +137 -0
  359. package/src/plugins/defaults/advisor/__tests__/consult.test.ts +153 -0
  360. package/src/plugins/defaults/advisor/__tests__/hooks.test.ts +138 -0
  361. package/src/plugins/defaults/advisor/__tests__/transcript.test.ts +147 -0
  362. package/src/plugins/defaults/advisor/advisor-gate.ts +29 -0
  363. package/src/plugins/defaults/advisor/advisor-state-store.ts +94 -0
  364. package/src/plugins/defaults/advisor/config.ts +21 -0
  365. package/src/plugins/defaults/advisor/consult.ts +93 -0
  366. package/src/plugins/defaults/advisor/hooks/post-model-call.ts +34 -0
  367. package/src/plugins/defaults/advisor/hooks/pre-model-call.ts +30 -0
  368. package/src/plugins/defaults/advisor/hooks/user-prompt-submit.ts +19 -0
  369. package/src/plugins/defaults/advisor/package.json +14 -0
  370. package/src/plugins/defaults/advisor/steering.ts +67 -0
  371. package/src/plugins/defaults/advisor/tools/advisor.ts +65 -0
  372. package/src/plugins/defaults/advisor/transcript.ts +76 -0
  373. package/src/plugins/defaults/index.ts +60 -0
  374. package/src/plugins/defaults/memory-retrieval/hooks/post-compact.ts +22 -9
  375. package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit.ts +2 -2
  376. package/src/plugins/defaults/memory-retrieval/tail-reinjection-strip.ts +64 -0
  377. package/src/plugins/defaults/memory-retrieval/unified-turn-context.ts +29 -21
  378. package/src/plugins/defaults/memory-v3-shadow/__tests__/carry-integration.test.ts +1 -0
  379. package/src/plugins/defaults/memory-v3-shadow/__tests__/injection.test.ts +1 -0
  380. package/src/plugins/defaults/memory-v3-shadow/__tests__/maintain-job.test.ts +129 -9
  381. package/src/plugins/defaults/memory-v3-shadow/__tests__/orchestrate.test.ts +31 -4
  382. package/src/plugins/defaults/memory-v3-shadow/__tests__/selection-log-store.test.ts +77 -2
  383. package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-plugin.test.ts +1 -0
  384. package/src/plugins/defaults/memory-v3-shadow/injector.ts +7 -10
  385. package/src/plugins/defaults/memory-v3-shadow/maintain-job.ts +144 -11
  386. package/src/plugins/defaults/memory-v3-shadow/orchestrate.ts +32 -20
  387. package/src/plugins/defaults/memory-v3-shadow/selection-log-store.ts +56 -3
  388. package/src/plugins/defaults/memory-v3-shadow/shadow-plugin.ts +23 -2
  389. package/src/plugins/defaults/surface-completion-nudge/hooks/post-model-call.ts +276 -0
  390. package/src/plugins/defaults/surface-completion-nudge/hooks/stop.ts +22 -0
  391. package/src/plugins/defaults/surface-completion-nudge/nudge-state-store.ts +46 -0
  392. package/src/plugins/defaults/surface-completion-nudge/package.json +14 -0
  393. package/src/plugins/defaults/task-progress-nudge/hooks/post-tool-use.ts +3 -13
  394. package/src/plugins/defaults/title-generate/hooks/stop.ts +56 -21
  395. package/src/prompts/persona-resolver.ts +14 -4
  396. package/src/prompts/templates/system-sections.ts +7 -2
  397. package/src/providers/__tests__/provider-env-vars.test.ts +6 -0
  398. package/src/providers/__tests__/provider-secret-catalog.test.ts +1 -0
  399. package/src/providers/__tests__/retry-callsite.test.ts +176 -0
  400. package/src/providers/atlascloud/client.ts +85 -0
  401. package/src/providers/fetch-provider-catalog.ts +85 -0
  402. package/src/providers/inference/adapter-factory.ts +3 -0
  403. package/src/providers/model-catalog.ts +58 -0
  404. package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +33 -0
  405. package/src/providers/openai/chat-completions-provider.ts +7 -0
  406. package/src/providers/openai/responses-provider.ts +10 -0
  407. package/src/providers/provider-send-message.ts +11 -3
  408. package/src/providers/retry.ts +53 -12
  409. package/src/providers/search-provider-catalog.ts +10 -0
  410. package/src/providers/weak-open-model.ts +22 -0
  411. package/src/runtime/AGENTS.md +0 -1
  412. package/src/runtime/__tests__/agent-wake.test.ts +181 -0
  413. package/src/runtime/__tests__/client-health.test.ts +44 -0
  414. package/src/runtime/access-request-helper.ts +21 -53
  415. package/src/runtime/actor-trust-resolver.ts +59 -63
  416. package/src/runtime/agent-wake.ts +52 -0
  417. package/src/runtime/assistant-event-hub.ts +18 -4
  418. package/src/runtime/auth/__tests__/route-policy.test.ts +12 -0
  419. package/src/runtime/auth/require-bound-guardian.ts +1 -4
  420. package/src/runtime/btw-sidechain.ts +3 -6
  421. package/src/runtime/capabilities.test.ts +120 -0
  422. package/src/runtime/capabilities.ts +197 -0
  423. package/src/runtime/channel-approval-types.ts +22 -45
  424. package/src/runtime/channel-invite-transports/telegram.ts +4 -4
  425. package/src/runtime/channel-retry-sweep.ts +1 -0
  426. package/src/runtime/channel-verification-service.ts +3 -3
  427. package/src/runtime/client-health.ts +26 -0
  428. package/src/runtime/confirmation-request-guardian-bridge.ts +38 -29
  429. package/src/runtime/effective-capabilities.test.ts +128 -0
  430. package/src/runtime/effective-capabilities.ts +84 -0
  431. package/src/runtime/guardian-reply-router.ts +106 -21
  432. package/src/runtime/invite-redemption-service.ts +9 -25
  433. package/src/runtime/migrations/__tests__/vbundle-builder-fd-leak.test.ts +123 -0
  434. package/src/runtime/migrations/vbundle-builder.ts +49 -20
  435. package/src/runtime/pending-interactions.ts +15 -0
  436. package/src/runtime/routes/__tests__/client-routes.test.ts +13 -0
  437. package/src/runtime/routes/__tests__/conversation-management-routes.test.ts +67 -0
  438. package/src/runtime/routes/__tests__/plugins-routes.test.ts +240 -1
  439. package/src/runtime/routes/app-routes.ts +1 -1
  440. package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +2 -2
  441. package/src/runtime/routes/assets/vellum-design-system.css +1959 -0
  442. package/src/runtime/routes/browser-tabs-routes.ts +9 -0
  443. package/src/runtime/routes/btw-routes.ts +1 -27
  444. package/src/runtime/routes/canonical-guardian-expiry-sweep.ts +17 -8
  445. package/src/runtime/routes/client-routes.ts +10 -0
  446. package/src/runtime/routes/contact-routes.ts +31 -8
  447. package/src/runtime/routes/conversation-compaction-routes.ts +1 -1
  448. package/src/runtime/routes/conversation-management-routes.ts +80 -1
  449. package/src/runtime/routes/conversation-query-routes.ts +68 -22
  450. package/src/runtime/routes/conversation-routes.ts +39 -14
  451. package/src/runtime/routes/credential-routes.ts +40 -16
  452. package/src/runtime/routes/empty-state-greeting-cache.ts +1 -2
  453. package/src/runtime/routes/events-routes.ts +1 -3
  454. package/src/runtime/routes/guardian-approval-interception.ts +14 -73
  455. package/src/runtime/routes/guardian-approval-prompt.ts +22 -4
  456. package/src/runtime/routes/home-feed-routes.ts +8 -3
  457. package/src/runtime/routes/identity-routes.ts +1 -296
  458. package/src/runtime/routes/inbound-message-handler.ts +214 -228
  459. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +89 -7
  460. package/src/runtime/routes/inbound-stages/admission-policy.test.ts +154 -0
  461. package/src/runtime/routes/inbound-stages/admission-policy.ts +140 -0
  462. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +3 -3
  463. package/src/runtime/routes/inbound-stages/background-dispatch.ts +11 -6
  464. package/src/runtime/routes/inbound-stages/escalation-intercept.ts +1 -2
  465. package/src/runtime/routes/inbound-stages/guardian-activation-intercept.ts +1 -2
  466. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.test.ts +7 -7
  467. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +47 -28
  468. package/src/runtime/routes/inbound-stages/reaction-intercept.ts +358 -0
  469. package/src/runtime/routes/index.ts +2 -0
  470. package/src/runtime/routes/integrations/slack/__tests__/channel.test.ts +8 -0
  471. package/src/runtime/routes/integrations/slack/channel.ts +36 -0
  472. package/src/runtime/routes/internal-telemetry-routes.ts +1 -1
  473. package/src/runtime/routes/mcp-auth-routes.ts +233 -41
  474. package/src/runtime/routes/memory-eval-routes.ts +87 -0
  475. package/src/runtime/routes/notification-routes.ts +122 -133
  476. package/src/runtime/routes/platform-routes.ts +2 -2
  477. package/src/runtime/routes/plugins-routes.ts +202 -3
  478. package/src/runtime/routes/schedule-routes.ts +0 -22
  479. package/src/runtime/routes/secret-routes.ts +10 -0
  480. package/src/runtime/routes/surface-action-routes.ts +2 -1
  481. package/src/runtime/routes/tool-call-question-enrichment.test.ts +146 -0
  482. package/src/runtime/routes/tool-call-question-enrichment.ts +66 -0
  483. package/src/runtime/routes/workflow-routes.test.ts +229 -44
  484. package/src/runtime/routes/workflow-routes.ts +131 -29
  485. package/src/runtime/routes/workspace-greetings.ts +55 -0
  486. package/src/runtime/sync/resource-sync-events.ts +1 -11
  487. package/src/runtime/tool-grant-request-helper.ts +18 -16
  488. package/src/runtime/trust-context-resolver.ts +8 -5
  489. package/src/schedule/inference-profile.ts +2 -14
  490. package/src/schedule/schedule-store.ts +1 -1
  491. package/src/schedule/scheduler-types.ts +5 -1
  492. package/src/security/__tests__/provider-key-env-fallback.test.ts +6 -0
  493. package/src/security/secret-patterns.ts +3 -0
  494. package/src/subagent/manager.ts +17 -4
  495. package/src/subagent/types.ts +6 -0
  496. package/src/telemetry/trace-collection-policy.test.ts +28 -0
  497. package/src/telemetry/trace-collection-policy.ts +30 -0
  498. package/src/telemetry/types.ts +89 -0
  499. package/src/telemetry/usage-telemetry-reporter.test.ts +586 -36
  500. package/src/telemetry/usage-telemetry-reporter.ts +148 -41
  501. package/src/tools/AGENTS.md +3 -3
  502. package/src/tools/browser/__tests__/browser-execution-acquire.test.ts +31 -0
  503. package/src/tools/browser/browser-execution.ts +30 -19
  504. package/src/tools/document/document-tool.ts +2 -3
  505. package/src/tools/executor.ts +5 -3
  506. package/src/tools/host-terminal/host-shell.ts +5 -4
  507. package/src/tools/memory/register.ts +2 -2
  508. package/src/tools/network/__tests__/web-fetch-firecrawl.test.ts +360 -0
  509. package/src/tools/network/__tests__/web-search.test.ts +143 -0
  510. package/src/tools/network/web-fetch.ts +372 -1
  511. package/src/tools/network/web-search-error.ts +1 -1
  512. package/src/tools/network/web-search.ts +213 -10
  513. package/src/tools/permission-checker.ts +4 -3
  514. package/src/tools/registry.ts +20 -0
  515. package/src/tools/schedule/create.ts +7 -12
  516. package/src/tools/schedule/update.ts +4 -11
  517. package/src/tools/shared/filesystem/path-policy.ts +39 -13
  518. package/src/tools/side-effects.ts +2 -17
  519. package/src/tools/skills/execute.ts +33 -0
  520. package/src/tools/subagent/spawn.ts +61 -12
  521. package/src/tools/terminal/shell.ts +10 -4
  522. package/src/tools/tool-approval-handler.ts +18 -13
  523. package/src/tools/tool-manifest.ts +0 -2
  524. package/src/tools/types.ts +9 -0
  525. package/src/tools/ui-surface/definitions.ts +64 -3
  526. package/src/tools/verification-control-plane-policy.ts +3 -1
  527. package/src/tools/workflows/run-workflow.test.ts +8 -18
  528. package/src/tools/workflows/run-workflow.ts +1 -0
  529. package/src/util/disk-usage.ts +78 -23
  530. package/src/util/platform.ts +10 -3
  531. package/src/watcher/telemetry.ts +2 -2
  532. package/src/workflows/capabilities.ts +2 -3
  533. package/src/workflows/engine.test.ts +175 -1
  534. package/src/workflows/engine.ts +82 -0
  535. package/src/workflows/journal-store.test.ts +70 -0
  536. package/src/workflows/journal-store.ts +18 -3
  537. package/src/workflows/run-manager.test.ts +171 -28
  538. package/src/workflows/run-manager.ts +66 -24
  539. package/src/workspace/migrations/105-enable-memory-v3-live-for-new-workspaces.ts +63 -0
  540. package/src/workspace/migrations/106-drop-collect-usage-data.ts +47 -0
  541. package/src/workspace/migrations/107-drop-send-diagnostics.ts +47 -0
  542. package/src/workspace/migrations/108-drop-balanced-economy-profile.ts +129 -0
  543. package/src/workspace/migrations/registry.ts +8 -0
  544. package/src/__tests__/app-control-no-global-cgevent.test.ts +0 -98
  545. package/src/__tests__/credential-security-e2e.test.ts +0 -362
  546. package/src/__tests__/credential-vault-unit.test.ts +0 -1528
  547. package/src/__tests__/credential-vault.test.ts +0 -1706
  548. package/src/__tests__/identity-intro-cache.test.ts +0 -315
  549. package/src/__tests__/secret-onetime-send.test.ts +0 -182
  550. package/src/cli/commands/__tests__/task.test.ts +0 -914
  551. package/src/cli/commands/task.ts +0 -771
  552. package/src/config/bundled-skills/personal-page/SKILL.md +0 -57
  553. package/src/config/bundled-skills/personal-page/TOOLS.json +0 -27
  554. package/src/config/bundled-skills/personal-page/tools/app-refresh.ts +0 -17
  555. package/src/config/preloaded-apps/personal-page/src/components/About.tsx +0 -22
  556. package/src/config/preloaded-apps/personal-page/src/components/App.tsx +0 -16
  557. package/src/config/preloaded-apps/personal-page/src/components/Features.tsx +0 -77
  558. package/src/config/preloaded-apps/personal-page/src/components/Hero.tsx +0 -57
  559. package/src/config/preloaded-apps/personal-page/src/components/Pending.tsx +0 -28
  560. package/src/config/preloaded-apps/personal-page/src/components/animations.tsx +0 -234
  561. package/src/config/preloaded-apps/personal-page/src/components/icons.tsx +0 -48
  562. package/src/config/preloaded-apps/personal-page/src/components/media.ts +0 -16
  563. package/src/config/preloaded-apps/personal-page/src/index.html +0 -20
  564. package/src/config/preloaded-apps/personal-page/src/main.tsx +0 -7
  565. package/src/config/preloaded-apps/personal-page/src/profile-data.ts +0 -82
  566. package/src/config/preloaded-apps/personal-page/src/styles.css +0 -759
  567. package/src/memory/__tests__/preloaded-apps.test.ts +0 -85
  568. package/src/memory/preloaded-apps.ts +0 -116
  569. package/src/notifications/tool-approval-copy.ts +0 -142
  570. package/src/runtime/routes/approval-prompt-ts-tracker.ts +0 -78
  571. package/src/runtime/routes/identity-intro-cache.ts +0 -172
  572. package/src/tools/credentials/vault.ts +0 -712
@@ -0,0 +1,1959 @@
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
+
12
+ /* ─── Reset ──────────────────────────────────────────────────── */
13
+
14
+ *,
15
+ *::before,
16
+ *::after {
17
+ box-sizing: border-box;
18
+ }
19
+
20
+ /* ─── Layer 1: Tokens ────────────────────────────────────────── */
21
+
22
+ :root {
23
+ /* ── Semantic Colors (Light Mode — default) ─────────────────── */
24
+ --v-primary-disabled: #D4D1C1;
25
+ --v-primary-base: #516748;
26
+ --v-primary-hover: #657D5B;
27
+ --v-primary-active: #7A8B6F;
28
+ --v-surface-base: #E8E6DA;
29
+ --v-surface-overlay: #F5F3EB;
30
+ --v-surface-active: #D4D1C1;
31
+ --v-surface-lift: #FFFFFF;
32
+ --v-border-disabled: #D4D1C1;
33
+ --v-border-base: #BDB9A9;
34
+ --v-border-hover: #A1A096;
35
+ --v-border-active: #7A8B6F;
36
+ --v-content-emphasized: #20201E;
37
+ --v-content-default: #2A2A28;
38
+ --v-content-secondary: #4A4A46;
39
+ --v-content-tertiary: #A1A096;
40
+ --v-content-disabled: #BDB9A9;
41
+ --v-content-background: #D4D1C1;
42
+ --v-content-inset: #FFFFFF;
43
+ --v-system-positive-strong: #516748;
44
+ --v-system-positive-weak: #D4DFD0;
45
+ --v-system-negative-strong: #DA491A;
46
+ --v-system-negative-hover: #E86B40;
47
+ --v-system-negative-weak: #F7DAC9;
48
+ --v-system-mid-strong: #F1B21E;
49
+ --v-system-mid-weak: #FCF3DD;
50
+ --v-aux-white: #FFFFFF;
51
+
52
+ /* ── Shorthand Aliases (referenced by app-builder SKILL.md) ── */
53
+ --v-bg: var(--v-surface-overlay);
54
+ --v-surface: var(--v-surface-base);
55
+ --v-surface-border: var(--v-border-base);
56
+ --v-text: var(--v-content-default);
57
+ --v-text-secondary: var(--v-content-secondary);
58
+ --v-text-muted: var(--v-content-tertiary);
59
+ --v-accent: var(--v-primary-base);
60
+ --v-accent-hover: var(--v-primary-hover);
61
+ --v-success: var(--v-system-positive-strong);
62
+ --v-danger: var(--v-system-negative-strong);
63
+ --v-warning: var(--v-system-mid-strong);
64
+
65
+ /* ── Palette Scales (Tailwind-style, referenced by SKILL.md) ─ */
66
+ --v-slate-50: #F8FAFC; --v-slate-100: #F1F5F9; --v-slate-200: #E2E8F0;
67
+ --v-slate-300: #CBD5E1; --v-slate-400: #94A3B8; --v-slate-500: #64748B;
68
+ --v-slate-600: #475569; --v-slate-700: #334155; --v-slate-800: #1E293B;
69
+ --v-slate-900: #0F172A; --v-slate-950: #020617;
70
+ --v-emerald-50: #ECFDF5; --v-emerald-100: #D1FAE5; --v-emerald-200: #A7F3D0;
71
+ --v-emerald-300: #6EE7B7; --v-emerald-400: #34D399; --v-emerald-500: #10B981;
72
+ --v-emerald-600: #059669; --v-emerald-700: #047857; --v-emerald-800: #065F46;
73
+ --v-emerald-900: #064E3B; --v-emerald-950: #022C22;
74
+ --v-violet-50: #F5F3FF; --v-violet-100: #EDE9FE; --v-violet-200: #DDD6FE;
75
+ --v-violet-300: #C4B5FD; --v-violet-400: #A78BFA; --v-violet-500: #8B5CF6;
76
+ --v-violet-600: #7C3AED; --v-violet-700: #6D28D9; --v-violet-800: #5B21B6;
77
+ --v-violet-900: #4C1D95; --v-violet-950: #2E1065;
78
+ --v-indigo-50: #EEF2FF; --v-indigo-100: #E0E7FF; --v-indigo-200: #C7D2FE;
79
+ --v-indigo-300: #A5B4FC; --v-indigo-400: #818CF8; --v-indigo-500: #6366F1;
80
+ --v-indigo-600: #4F46E5; --v-indigo-700: #4338CA; --v-indigo-800: #3730A3;
81
+ --v-indigo-900: #312E81; --v-indigo-950: #1E1B4B;
82
+ --v-rose-50: #FFF1F2; --v-rose-100: #FFE4E6; --v-rose-200: #FECDD3;
83
+ --v-rose-300: #FDA4AF; --v-rose-400: #FB7185; --v-rose-500: #F43F5E;
84
+ --v-rose-600: #E11D48; --v-rose-700: #BE123C; --v-rose-800: #9F1239;
85
+ --v-rose-900: #881337; --v-rose-950: #4C0519;
86
+ --v-amber-50: #FFFBEB; --v-amber-100: #FEF3C7; --v-amber-200: #FDE68A;
87
+ --v-amber-300: #FCD34D; --v-amber-400: #FBBF24; --v-amber-500: #F59E0B;
88
+ --v-amber-600: #D97706; --v-amber-700: #B45309; --v-amber-800: #92400E;
89
+ --v-amber-900: #78350F; --v-amber-950: #451A03;
90
+
91
+ /* ── Spacing (4pt grid) ─────────────────────────────────────── */
92
+ --v-spacing-xxs: 2px;
93
+ --v-spacing-xs: 4px;
94
+ --v-spacing-sm: 8px;
95
+ --v-spacing-md: 12px;
96
+ --v-spacing-lg: 16px;
97
+ --v-spacing-xl: 24px;
98
+ --v-spacing-xxl: 32px;
99
+ --v-spacing-xxxl: 48px;
100
+
101
+ /* ── Radius ─────────────────────────────────────────────────── */
102
+ --v-radius-xs: 2px;
103
+ --v-radius-sm: 4px;
104
+ --v-radius-md: 8px;
105
+ --v-radius-lg: 12px;
106
+ --v-radius-xl: 16px;
107
+ --v-radius-pill: 999px;
108
+
109
+ /* ── Shadows ────────────────────────────────────────────────── */
110
+ --v-shadow-sm: 0 2px 4px rgba(0, 0, 0, 0.08);
111
+ --v-shadow-md: 0 4px 8px rgba(0, 0, 0, 0.12);
112
+ --v-shadow-lg: 0 8px 16px rgba(0, 0, 0, 0.16);
113
+
114
+ /* ── Animation ──────────────────────────────────────────────── */
115
+ --v-duration-fast: 0.15s;
116
+ --v-duration-standard: 0.25s;
117
+ --v-duration-slow: 0.4s;
118
+
119
+ /* ── Typography ─────────────────────────────────────────────── */
120
+ --v-font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text",
121
+ "Helvetica Neue", sans-serif;
122
+ --v-font-mono: "SF Mono", SFMono-Regular, ui-monospace, Menlo,
123
+ Monaco, monospace;
124
+ --v-font-size-xs: 10px;
125
+ --v-font-size-sm: 11px;
126
+ --v-font-size-base: 14px;
127
+ --v-font-size-lg: 17px;
128
+ --v-font-size-xl: 22px;
129
+ --v-font-size-2xl: 26px;
130
+ --v-line-height: 1.5;
131
+ }
132
+
133
+ /* ── Dark Mode (matches SwiftUI VColor semantic values) ───────── */
134
+
135
+ @media (prefers-color-scheme: dark) {
136
+ :root {
137
+ --v-primary-disabled: #3A3A37;
138
+ --v-primary-base: #657D5B;
139
+ --v-primary-hover: #516748;
140
+ --v-primary-active: #7A8B6F;
141
+ --v-surface-base: #2A2A28;
142
+ --v-surface-overlay: #20201E;
143
+ --v-surface-active: #3A3A37;
144
+ --v-surface-lift: #000000;
145
+ --v-border-disabled: #3A3A37;
146
+ --v-border-base: #4A4A46;
147
+ --v-border-hover: #6B6B65;
148
+ --v-border-active: #7A8B6F;
149
+ --v-content-emphasized: #F5F3EB;
150
+ --v-content-default: #E8E6DA;
151
+ --v-content-secondary: #BDB9A9;
152
+ --v-content-tertiary: #A1A096;
153
+ --v-content-disabled: #6B6B65;
154
+ --v-content-background: #3A3A37;
155
+ --v-content-inset: #000000;
156
+ --v-system-positive-strong: #516748;
157
+ --v-system-positive-weak: #1A2316;
158
+ --v-system-negative-strong: #DA491A;
159
+ --v-system-negative-hover: #AB3F1C;
160
+ --v-system-negative-weak: #4E281D;
161
+ --v-system-mid-strong: #F1B21E;
162
+ --v-system-mid-weak: #4B3D1E;
163
+ --v-aux-white: #FFFFFF;
164
+
165
+ --v-shadow-sm: 0 2px 4px rgba(0, 0, 0, 0.3);
166
+ --v-shadow-md: 0 4px 8px rgba(0, 0, 0, 0.4);
167
+ --v-shadow-lg: 0 8px 16px rgba(0, 0, 0, 0.5);
168
+ }
169
+ }
170
+
171
+ /* ─── Layer 2: Element Defaults ──────────────────────────────── */
172
+
173
+ body {
174
+ margin: 0;
175
+ font-family: var(--v-font-family);
176
+ font-size: var(--v-font-size-base);
177
+ line-height: var(--v-line-height);
178
+ color: var(--v-content-default);
179
+ background: var(--v-surface-overlay);
180
+ padding: var(--v-spacing-xl);
181
+ min-height: 100vh;
182
+ display: flex;
183
+ flex-direction: column;
184
+ align-items: center;
185
+ justify-content: center;
186
+ -webkit-font-smoothing: antialiased;
187
+ }
188
+ body > *:not(#vellum-bottom-fade):not(#v-toast-container) {
189
+ width: 100%;
190
+ }
191
+
192
+ @media (prefers-color-scheme: dark) {
193
+ body {
194
+ background:
195
+ radial-gradient(ellipse at 50% 0%, var(--v-surface-base) 0%, transparent 50%),
196
+ var(--v-surface-overlay);
197
+ }
198
+ }
199
+
200
+ h1, h2, h3, h4, h5, h6 {
201
+ line-height: 1.2;
202
+ margin: 0 0 var(--v-spacing-md) 0;
203
+ color: var(--v-content-default);
204
+ }
205
+
206
+ h1 { font-size: var(--v-font-size-2xl); font-weight: 700; }
207
+ h2 { font-size: var(--v-font-size-xl); font-weight: 600; }
208
+ h3 { font-size: var(--v-font-size-lg); font-weight: 600; }
209
+ h4 { font-size: var(--v-font-size-base); font-weight: 600; }
210
+ h5 { font-size: var(--v-font-size-sm); font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em; }
211
+ h6 { font-size: var(--v-font-size-xs); font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em; }
212
+
213
+ p { margin: 0 0 var(--v-spacing-md) 0; }
214
+
215
+ a {
216
+ color: var(--v-primary-base);
217
+ text-decoration: none;
218
+ }
219
+ a:hover { text-decoration: underline; }
220
+
221
+ button {
222
+ font-family: var(--v-font-family);
223
+ font-size: var(--v-font-size-base);
224
+ border: none;
225
+ background: none;
226
+ cursor: pointer;
227
+ color: inherit;
228
+ }
229
+
230
+ input, textarea, select {
231
+ font-family: var(--v-font-family);
232
+ font-size: var(--v-font-size-base);
233
+ padding: var(--v-spacing-sm) var(--v-spacing-md);
234
+ background: var(--v-surface-overlay);
235
+ color: var(--v-content-default);
236
+ border: 1px solid var(--v-border-base);
237
+ border-radius: var(--v-radius-md);
238
+ outline: none;
239
+ transition: border-color var(--v-duration-fast) ease-out;
240
+ }
241
+ select {
242
+ -webkit-appearance: none;
243
+ appearance: none;
244
+ 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");
245
+ background-repeat: no-repeat;
246
+ background-position: right var(--v-spacing-md) center;
247
+ padding-right: calc(var(--v-spacing-md) + 20px);
248
+ }
249
+ input:focus, textarea:focus, select:focus {
250
+ border-color: var(--v-primary-base);
251
+ }
252
+
253
+ textarea { resize: vertical; }
254
+
255
+ code {
256
+ font-family: var(--v-font-mono);
257
+ font-size: 0.9em;
258
+ background: var(--v-surface-base);
259
+ padding: var(--v-spacing-xxs) var(--v-spacing-xs);
260
+ border-radius: var(--v-radius-sm);
261
+ }
262
+
263
+ pre {
264
+ font-family: var(--v-font-mono);
265
+ font-size: var(--v-font-size-sm);
266
+ background: var(--v-surface-base);
267
+ padding: var(--v-spacing-lg);
268
+ border-radius: var(--v-radius-md);
269
+ overflow-x: auto;
270
+ margin: 0 0 var(--v-spacing-md) 0;
271
+ }
272
+ pre code {
273
+ background: none;
274
+ padding: 0;
275
+ }
276
+
277
+ hr {
278
+ border: none;
279
+ border-top: 1px solid var(--v-border-base);
280
+ margin: var(--v-spacing-xl) 0;
281
+ }
282
+
283
+ ul, ol { padding-left: var(--v-spacing-xl); margin: 0 0 var(--v-spacing-md) 0; }
284
+
285
+ table {
286
+ width: 100%;
287
+ border-collapse: collapse;
288
+ margin: 0 0 var(--v-spacing-md) 0;
289
+ }
290
+ th, td {
291
+ text-align: left;
292
+ padding: var(--v-spacing-sm) var(--v-spacing-md);
293
+ border-bottom: 1px solid var(--v-border-base);
294
+ }
295
+ th { font-weight: 600; color: var(--v-content-secondary); font-size: var(--v-font-size-sm); }
296
+
297
+ /* ─── Layer 3: Component Classes ─────────────────────────────── */
298
+
299
+ /* Button variants */
300
+ .v-button {
301
+ font-family: var(--v-font-family);
302
+ font-size: var(--v-font-size-base);
303
+ font-weight: 500;
304
+ padding: var(--v-spacing-sm) var(--v-spacing-lg);
305
+ background: var(--v-primary-base);
306
+ color: var(--v-aux-white);
307
+ border: none;
308
+ border-radius: var(--v-radius-md);
309
+ cursor: pointer;
310
+ transition: filter var(--v-duration-fast) ease-out,
311
+ transform var(--v-duration-fast) ease-out;
312
+ }
313
+ .v-button:hover { filter: brightness(1.1); }
314
+ .v-button:active { transform: scale(0.97); }
315
+ .v-button:disabled { opacity: 0.4; cursor: not-allowed; filter: none; transform: none; }
316
+ .v-button.secondary {
317
+ background: var(--v-surface-base);
318
+ color: var(--v-content-default);
319
+ border: 1px solid var(--v-border-base);
320
+ }
321
+ .v-button.secondary:hover { filter: brightness(0.95); }
322
+ .v-button.danger {
323
+ background: var(--v-system-negative-strong);
324
+ }
325
+ .v-button.ghost {
326
+ background: transparent;
327
+ color: var(--v-primary-base);
328
+ }
329
+ .v-button.ghost:hover { background: var(--v-surface-base); filter: none; }
330
+
331
+ /* Focus-visible for keyboard accessibility */
332
+ .v-button:focus-visible {
333
+ outline: 2px solid var(--v-primary-base);
334
+ outline-offset: 2px;
335
+ }
336
+ input:focus-visible, textarea:focus-visible, select:focus-visible {
337
+ border-color: var(--v-primary-base);
338
+ outline: 2px solid var(--v-primary-base);
339
+ outline-offset: -1px;
340
+ }
341
+
342
+ /* Card */
343
+ .v-card {
344
+ background: var(--v-surface-base);
345
+ border: 1px solid var(--v-border-base);
346
+ border-radius: var(--v-radius-lg);
347
+ padding: var(--v-spacing-lg);
348
+ box-shadow: var(--v-shadow-sm);
349
+ }
350
+
351
+ /* Badge */
352
+ .v-badge {
353
+ display: inline-flex;
354
+ align-items: center;
355
+ font-size: var(--v-font-size-xs);
356
+ font-weight: 600;
357
+ padding: var(--v-spacing-xxs) var(--v-spacing-sm);
358
+ border-radius: var(--v-radius-pill);
359
+ background: var(--v-surface-base);
360
+ color: var(--v-content-secondary);
361
+ }
362
+ .v-badge.success { background: color-mix(in srgb, var(--v-system-positive-strong) 15%, transparent); color: var(--v-system-positive-strong); }
363
+ .v-badge.danger { background: color-mix(in srgb, var(--v-system-negative-strong) 15%, transparent); color: var(--v-system-negative-strong); }
364
+ .v-badge.warning { background: color-mix(in srgb, var(--v-system-mid-strong) 15%, transparent); color: var(--v-system-mid-strong); }
365
+
366
+ /* List */
367
+ .v-list {
368
+ list-style: none;
369
+ margin: 0;
370
+ padding: 0;
371
+ }
372
+ .v-list-item {
373
+ padding: var(--v-spacing-md) var(--v-spacing-lg);
374
+ border-radius: var(--v-radius-md);
375
+ transition: background var(--v-duration-fast) ease-out;
376
+ }
377
+ .v-list-item:hover { background: var(--v-surface-base); }
378
+ .v-list-item:focus-visible {
379
+ outline: 2px solid var(--v-primary-base);
380
+ outline-offset: -2px;
381
+ }
382
+
383
+ /* Toggle switch */
384
+ .v-toggle {
385
+ position: relative;
386
+ display: inline-block;
387
+ width: 40px;
388
+ height: 22px;
389
+ }
390
+ .v-toggle input {
391
+ position: absolute;
392
+ top: 0; left: 0;
393
+ width: 100%; height: 100%;
394
+ opacity: 0;
395
+ margin: 0;
396
+ cursor: pointer;
397
+ }
398
+ .v-toggle-track {
399
+ position: absolute;
400
+ inset: 0;
401
+ background: var(--v-border-base);
402
+ border-radius: var(--v-radius-pill);
403
+ cursor: pointer;
404
+ transition: background var(--v-duration-fast) ease-out;
405
+ }
406
+ .v-toggle-track::after {
407
+ content: "";
408
+ position: absolute;
409
+ top: 2px; left: 2px;
410
+ width: 18px; height: 18px;
411
+ background: white;
412
+ border-radius: 50%;
413
+ transition: transform var(--v-duration-fast) ease-out;
414
+ }
415
+ .v-toggle input:checked + .v-toggle-track {
416
+ background: var(--v-primary-base);
417
+ }
418
+ .v-toggle input:checked + .v-toggle-track::after {
419
+ transform: translateX(18px);
420
+ }
421
+ .v-toggle input:focus-visible + .v-toggle-track {
422
+ outline: 2px solid var(--v-primary-base);
423
+ outline-offset: 2px;
424
+ }
425
+
426
+ /* Input row (input + button combo) */
427
+ .v-input-row {
428
+ display: flex;
429
+ gap: var(--v-spacing-sm);
430
+ }
431
+ .v-input-row input,
432
+ .v-input-row .v-input {
433
+ flex: 1;
434
+ }
435
+
436
+ /* ─── Layer 4: Utility Classes ───────────────────────────────── */
437
+
438
+ /* Flexbox */
439
+ .v-flex { display: flex; }
440
+ .v-flex-col { display: flex; flex-direction: column; }
441
+ .v-flex-wrap { flex-wrap: wrap; }
442
+ .v-items-center { align-items: center; }
443
+ .v-justify-between { justify-content: space-between; }
444
+ .v-justify-center { justify-content: center; }
445
+
446
+ /* Gap */
447
+ .v-gap-xs { gap: var(--v-spacing-xs); }
448
+ .v-gap-sm { gap: var(--v-spacing-sm); }
449
+ .v-gap-md { gap: var(--v-spacing-md); }
450
+ .v-gap-lg { gap: var(--v-spacing-lg); }
451
+ .v-gap-xl { gap: var(--v-spacing-xl); }
452
+
453
+ /* Text */
454
+ .v-text-secondary { color: var(--v-content-secondary); }
455
+ .v-text-muted { color: var(--v-content-tertiary); }
456
+ .v-text-accent { color: var(--v-primary-base); }
457
+ .v-text-xs { font-size: var(--v-font-size-xs); }
458
+ .v-text-sm { font-size: var(--v-font-size-sm); }
459
+ .v-text-lg { font-size: var(--v-font-size-lg); }
460
+ .v-font-mono { font-family: var(--v-font-mono); }
461
+
462
+ /* Layout */
463
+ .v-truncate {
464
+ overflow: hidden;
465
+ text-overflow: ellipsis;
466
+ white-space: nowrap;
467
+ }
468
+ .v-w-full { width: 100%; }
469
+
470
+ /* Accessibility */
471
+ .v-sr-only {
472
+ position: absolute;
473
+ width: 1px;
474
+ height: 1px;
475
+ padding: 0;
476
+ margin: -1px;
477
+ overflow: hidden;
478
+ clip: rect(0, 0, 0, 0);
479
+ white-space: nowrap;
480
+ border-width: 0;
481
+ }
482
+
483
+ /* ─── Layer 5: Widget Components ────────────────────────────── */
484
+
485
+ /* ── Tier 1: Layout & Data Primitives ───────────────────────── */
486
+
487
+ /* Metric Card — single big number with label and trend arrow */
488
+ .v-metric-card {
489
+ background: var(--v-surface-base);
490
+ border: 1px solid var(--v-border-base);
491
+ border-radius: var(--v-radius-lg);
492
+ padding: var(--v-spacing-lg);
493
+ display: flex;
494
+ flex-direction: column;
495
+ gap: var(--v-spacing-xs);
496
+ }
497
+ .v-metric-card .v-metric-value {
498
+ font-size: var(--v-font-size-2xl);
499
+ font-weight: 700;
500
+ line-height: 1.1;
501
+ color: var(--v-content-default);
502
+ }
503
+ .v-metric-card .v-metric-label {
504
+ font-size: var(--v-font-size-sm);
505
+ color: var(--v-content-secondary);
506
+ font-weight: 500;
507
+ text-transform: uppercase;
508
+ letter-spacing: 0.04em;
509
+ }
510
+ .v-metric-card .v-metric-trend {
511
+ font-size: var(--v-font-size-sm);
512
+ font-weight: 600;
513
+ display: inline-flex;
514
+ align-items: center;
515
+ gap: var(--v-spacing-xxs);
516
+ }
517
+ .v-metric-card .v-metric-trend.up { color: var(--v-system-positive-strong); }
518
+ .v-metric-card .v-metric-trend.down { color: var(--v-system-negative-strong); }
519
+ .v-metric-card .v-metric-trend.neutral { color: var(--v-content-tertiary); }
520
+
521
+ /* Metric Grid — responsive grid of metric cards */
522
+ .v-metric-grid {
523
+ display: grid;
524
+ grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
525
+ gap: var(--v-spacing-lg);
526
+ }
527
+
528
+ /* Data Table — sortable, hoverable, sticky header */
529
+ .v-data-table {
530
+ width: 100%;
531
+ border-collapse: separate;
532
+ border-spacing: 0;
533
+ background: var(--v-surface-base);
534
+ border: 1px solid var(--v-border-base);
535
+ border-radius: var(--v-radius-lg);
536
+ overflow: hidden;
537
+ }
538
+ .v-data-table thead th {
539
+ position: sticky;
540
+ top: 0;
541
+ background: var(--v-surface-overlay);
542
+ font-size: var(--v-font-size-sm);
543
+ font-weight: 600;
544
+ color: var(--v-content-secondary);
545
+ text-align: left;
546
+ padding: var(--v-spacing-sm) var(--v-spacing-md);
547
+ border-bottom: 1px solid var(--v-border-base);
548
+ cursor: default;
549
+ user-select: none;
550
+ white-space: nowrap;
551
+ }
552
+ .v-data-table thead th[data-sortable] {
553
+ cursor: pointer;
554
+ }
555
+ .v-data-table thead th[data-sortable]:hover {
556
+ color: var(--v-content-default);
557
+ }
558
+ .v-data-table tbody td {
559
+ padding: var(--v-spacing-sm) var(--v-spacing-md);
560
+ border-bottom: 1px solid var(--v-border-base);
561
+ font-size: var(--v-font-size-base);
562
+ color: var(--v-content-default);
563
+ }
564
+ .v-data-table tbody tr:last-child td {
565
+ border-bottom: none;
566
+ }
567
+ .v-data-table tbody tr:hover {
568
+ background: color-mix(in srgb, var(--v-primary-base) 5%, transparent);
569
+ }
570
+ .v-data-table tbody tr.selected {
571
+ background: color-mix(in srgb, var(--v-primary-base) 10%, transparent);
572
+ }
573
+ .v-data-table input[type="checkbox"] {
574
+ accent-color: var(--v-primary-base);
575
+ }
576
+
577
+ /* Timeline — vertical timeline with entries */
578
+ .v-timeline {
579
+ display: flex;
580
+ flex-direction: column;
581
+ position: relative;
582
+ padding-left: var(--v-spacing-xl);
583
+ }
584
+ .v-timeline::before {
585
+ content: "";
586
+ position: absolute;
587
+ left: 7px;
588
+ top: var(--v-spacing-xs);
589
+ bottom: var(--v-spacing-xs);
590
+ width: 2px;
591
+ background: var(--v-border-base);
592
+ }
593
+ .v-timeline-entry {
594
+ position: relative;
595
+ padding-bottom: var(--v-spacing-lg);
596
+ }
597
+ .v-timeline-entry::before {
598
+ content: "";
599
+ position: absolute;
600
+ left: calc(-1 * var(--v-spacing-xl) + 3px);
601
+ top: 6px;
602
+ width: 10px;
603
+ height: 10px;
604
+ border-radius: 50%;
605
+ background: var(--v-border-base);
606
+ border: 2px solid var(--v-surface-overlay);
607
+ }
608
+ .v-timeline-entry.active::before {
609
+ background: var(--v-primary-base);
610
+ }
611
+ .v-timeline-entry.success::before {
612
+ background: var(--v-system-positive-strong);
613
+ }
614
+ .v-timeline-entry.error::before {
615
+ background: var(--v-system-negative-strong);
616
+ }
617
+ .v-timeline-entry .v-timeline-time {
618
+ font-size: var(--v-font-size-xs);
619
+ color: var(--v-content-tertiary);
620
+ margin-bottom: var(--v-spacing-xxs);
621
+ }
622
+ .v-timeline-entry .v-timeline-title {
623
+ font-size: var(--v-font-size-base);
624
+ font-weight: 600;
625
+ color: var(--v-content-default);
626
+ }
627
+ .v-timeline-entry .v-timeline-desc {
628
+ font-size: var(--v-font-size-sm);
629
+ color: var(--v-content-secondary);
630
+ margin-top: var(--v-spacing-xxs);
631
+ }
632
+
633
+ /* Action List — rows with per-item action buttons */
634
+ .v-action-list {
635
+ list-style: none;
636
+ margin: 0;
637
+ padding: 0;
638
+ display: flex;
639
+ flex-direction: column;
640
+ }
641
+ .v-action-list-item {
642
+ display: flex;
643
+ align-items: center;
644
+ gap: var(--v-spacing-md);
645
+ padding: var(--v-spacing-md) var(--v-spacing-lg);
646
+ border-bottom: 1px solid var(--v-border-base);
647
+ transition: background var(--v-duration-fast) ease-out;
648
+ }
649
+ .v-action-list-item:last-child {
650
+ border-bottom: none;
651
+ }
652
+ .v-action-list-item:hover {
653
+ background: var(--v-surface-base);
654
+ }
655
+ .v-action-list-item .v-action-content {
656
+ flex: 1;
657
+ min-width: 0;
658
+ }
659
+ .v-action-list-item .v-action-title {
660
+ font-weight: 500;
661
+ color: var(--v-content-default);
662
+ }
663
+ .v-action-list-item .v-action-subtitle {
664
+ font-size: var(--v-font-size-sm);
665
+ color: var(--v-content-secondary);
666
+ margin-top: var(--v-spacing-xxs);
667
+ }
668
+ .v-action-list-item .v-action-buttons {
669
+ display: flex;
670
+ gap: var(--v-spacing-xs);
671
+ flex-shrink: 0;
672
+ }
673
+
674
+ /* Tabs — tab bar + tab panels */
675
+ .v-tabs {
676
+ display: flex;
677
+ flex-direction: column;
678
+ }
679
+ .v-tab-bar {
680
+ display: flex;
681
+ gap: 0;
682
+ border-bottom: 1px solid var(--v-border-base);
683
+ }
684
+ .v-tab {
685
+ padding: var(--v-spacing-sm) var(--v-spacing-lg);
686
+ font-size: var(--v-font-size-base);
687
+ font-weight: 500;
688
+ color: var(--v-content-secondary);
689
+ background: transparent;
690
+ border: none;
691
+ border-bottom: 2px solid transparent;
692
+ cursor: pointer;
693
+ transition: color var(--v-duration-fast) ease-out,
694
+ border-color var(--v-duration-fast) ease-out;
695
+ }
696
+ .v-tab:hover {
697
+ color: var(--v-content-default);
698
+ }
699
+ .v-tab[aria-selected="true"],
700
+ .v-tab.active {
701
+ color: var(--v-primary-base);
702
+ border-bottom-color: var(--v-primary-base);
703
+ }
704
+ .v-tab:focus-visible {
705
+ outline: 2px solid var(--v-primary-base);
706
+ outline-offset: -2px;
707
+ }
708
+ .v-tab-panel {
709
+ padding: var(--v-spacing-lg) 0;
710
+ }
711
+ .v-tab-panel[hidden] {
712
+ display: none;
713
+ }
714
+
715
+ /* Accordion — collapsible sections */
716
+ .v-accordion {
717
+ display: flex;
718
+ flex-direction: column;
719
+ border: 1px solid var(--v-border-base);
720
+ border-radius: var(--v-radius-lg);
721
+ overflow: hidden;
722
+ }
723
+ .v-accordion-item {
724
+ border-bottom: 1px solid var(--v-border-base);
725
+ }
726
+ .v-accordion-item:last-child {
727
+ border-bottom: none;
728
+ }
729
+ .v-accordion-header {
730
+ display: flex;
731
+ align-items: center;
732
+ justify-content: space-between;
733
+ width: 100%;
734
+ padding: var(--v-spacing-md) var(--v-spacing-lg);
735
+ background: var(--v-surface-base);
736
+ border: none;
737
+ cursor: pointer;
738
+ font-size: var(--v-font-size-base);
739
+ font-weight: 500;
740
+ color: var(--v-content-default);
741
+ text-align: left;
742
+ transition: background var(--v-duration-fast) ease-out;
743
+ }
744
+ .v-accordion-header:hover {
745
+ background: color-mix(in srgb, var(--v-surface-base) 80%, var(--v-surface-overlay));
746
+ }
747
+ .v-accordion-header::after {
748
+ content: "\203A";
749
+ font-size: var(--v-font-size-lg);
750
+ color: var(--v-content-tertiary);
751
+ transform: rotate(90deg);
752
+ transition: transform var(--v-duration-standard) ease-in-out;
753
+ }
754
+ .v-accordion-item[open] .v-accordion-header::after,
755
+ .v-accordion-header[aria-expanded="true"]::after {
756
+ transform: rotate(270deg);
757
+ }
758
+ .v-accordion-body {
759
+ padding: var(--v-spacing-lg);
760
+ background: var(--v-surface-overlay);
761
+ }
762
+ .v-accordion-header:focus-visible {
763
+ outline: 2px solid var(--v-primary-base);
764
+ outline-offset: -2px;
765
+ }
766
+
767
+ /* Search Bar — input with icon and clear button */
768
+ .v-search-bar {
769
+ position: relative;
770
+ display: flex;
771
+ align-items: center;
772
+ }
773
+ .v-search-bar input {
774
+ width: 100%;
775
+ padding-left: var(--v-spacing-xxl);
776
+ padding-right: var(--v-spacing-xxl);
777
+ background: var(--v-surface-base);
778
+ border: 1px solid var(--v-border-base);
779
+ border-radius: var(--v-radius-pill);
780
+ }
781
+ .v-search-bar input:focus {
782
+ border-color: var(--v-primary-base);
783
+ }
784
+ .v-search-bar::before {
785
+ content: "\1F50D";
786
+ position: absolute;
787
+ left: var(--v-spacing-md);
788
+ font-size: var(--v-font-size-sm);
789
+ color: var(--v-content-tertiary);
790
+ pointer-events: none;
791
+ }
792
+ .v-search-bar .v-search-clear {
793
+ position: absolute;
794
+ right: var(--v-spacing-sm);
795
+ background: none;
796
+ border: none;
797
+ color: var(--v-content-tertiary);
798
+ cursor: pointer;
799
+ font-size: var(--v-font-size-sm);
800
+ padding: var(--v-spacing-xs);
801
+ border-radius: 50%;
802
+ }
803
+ .v-search-bar .v-search-clear:hover {
804
+ color: var(--v-content-default);
805
+ background: var(--v-border-base);
806
+ }
807
+
808
+ /* Card Grid — responsive grid of cards */
809
+ .v-card-grid {
810
+ display: grid;
811
+ grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
812
+ gap: var(--v-spacing-lg);
813
+ }
814
+
815
+ /* Progress Bar — horizontal fill bar with label */
816
+ .v-progress-bar {
817
+ display: flex;
818
+ flex-direction: column;
819
+ gap: var(--v-spacing-xs);
820
+ }
821
+ .v-progress-bar .v-progress-header {
822
+ display: flex;
823
+ justify-content: space-between;
824
+ font-size: var(--v-font-size-sm);
825
+ color: var(--v-content-secondary);
826
+ }
827
+ .v-progress-bar .v-progress-track {
828
+ height: 8px;
829
+ background: var(--v-border-base);
830
+ border-radius: var(--v-radius-pill);
831
+ overflow: hidden;
832
+ }
833
+ .v-progress-bar .v-progress-fill {
834
+ height: 100%;
835
+ background: var(--v-primary-base);
836
+ border-radius: var(--v-radius-pill);
837
+ transition: width var(--v-duration-standard) ease-in-out;
838
+ }
839
+ .v-progress-bar .v-progress-fill.success { background: var(--v-system-positive-strong); }
840
+ .v-progress-bar .v-progress-fill.warning { background: var(--v-system-mid-strong); }
841
+ .v-progress-bar .v-progress-fill.danger { background: var(--v-system-negative-strong); }
842
+
843
+ /* Status Badge — colored pill with dot indicator */
844
+ .v-status-badge {
845
+ display: inline-flex;
846
+ align-items: center;
847
+ gap: var(--v-spacing-xs);
848
+ font-size: var(--v-font-size-xs);
849
+ font-weight: 600;
850
+ padding: var(--v-spacing-xxs) var(--v-spacing-sm);
851
+ border-radius: var(--v-radius-pill);
852
+ background: var(--v-surface-base);
853
+ color: var(--v-content-secondary);
854
+ }
855
+ .v-status-badge::before {
856
+ content: "";
857
+ width: 6px;
858
+ height: 6px;
859
+ border-radius: 50%;
860
+ background: currentColor;
861
+ flex-shrink: 0;
862
+ }
863
+ .v-status-badge.success {
864
+ background: color-mix(in srgb, var(--v-system-positive-strong) 15%, transparent);
865
+ color: var(--v-system-positive-strong);
866
+ }
867
+ .v-status-badge.warning {
868
+ background: color-mix(in srgb, var(--v-system-mid-strong) 15%, transparent);
869
+ color: var(--v-system-mid-strong);
870
+ }
871
+ .v-status-badge.error {
872
+ background: color-mix(in srgb, var(--v-system-negative-strong) 15%, transparent);
873
+ color: var(--v-system-negative-strong);
874
+ }
875
+ .v-status-badge.info {
876
+ background: color-mix(in srgb, var(--v-primary-base) 15%, transparent);
877
+ color: var(--v-primary-base);
878
+ }
879
+
880
+ /* Stat Row — horizontal strip of label-value pairs */
881
+ .v-stat-row {
882
+ display: flex;
883
+ flex-wrap: wrap;
884
+ gap: var(--v-spacing-lg);
885
+ padding: var(--v-spacing-md) 0;
886
+ }
887
+ .v-stat-row .v-stat {
888
+ display: flex;
889
+ flex-direction: column;
890
+ gap: var(--v-spacing-xxs);
891
+ }
892
+ .v-stat-row .v-stat:not(:last-child) {
893
+ padding-right: var(--v-spacing-lg);
894
+ border-right: 1px solid var(--v-border-base);
895
+ }
896
+ .v-stat-row .v-stat-label {
897
+ font-size: var(--v-font-size-xs);
898
+ color: var(--v-content-tertiary);
899
+ text-transform: uppercase;
900
+ letter-spacing: 0.04em;
901
+ font-weight: 500;
902
+ }
903
+ .v-stat-row .v-stat-value {
904
+ font-size: var(--v-font-size-lg);
905
+ font-weight: 700;
906
+ color: var(--v-content-default);
907
+ }
908
+
909
+ /* Toast — dismissible notification banner */
910
+ .v-toast {
911
+ display: flex;
912
+ align-items: center;
913
+ gap: var(--v-spacing-md);
914
+ padding: var(--v-spacing-md) var(--v-spacing-lg);
915
+ border-radius: var(--v-radius-md);
916
+ font-size: var(--v-font-size-sm);
917
+ font-weight: 500;
918
+ background: var(--v-surface-base);
919
+ border: 1px solid var(--v-border-base);
920
+ box-shadow: var(--v-shadow-md);
921
+ }
922
+ .v-toast.success {
923
+ background: color-mix(in srgb, var(--v-system-positive-strong) 10%, var(--v-surface-base));
924
+ border-color: color-mix(in srgb, var(--v-system-positive-strong) 30%, var(--v-border-base));
925
+ color: var(--v-system-positive-strong);
926
+ }
927
+ .v-toast.error {
928
+ background: color-mix(in srgb, var(--v-system-negative-strong) 10%, var(--v-surface-base));
929
+ border-color: color-mix(in srgb, var(--v-system-negative-strong) 30%, var(--v-border-base));
930
+ color: var(--v-system-negative-strong);
931
+ }
932
+ .v-toast.warning {
933
+ background: color-mix(in srgb, var(--v-system-mid-strong) 10%, var(--v-surface-base));
934
+ border-color: color-mix(in srgb, var(--v-system-mid-strong) 30%, var(--v-border-base));
935
+ color: var(--v-system-mid-strong);
936
+ }
937
+ .v-toast.info {
938
+ background: color-mix(in srgb, var(--v-primary-base) 10%, var(--v-surface-base));
939
+ border-color: color-mix(in srgb, var(--v-primary-base) 30%, var(--v-border-base));
940
+ color: var(--v-primary-base);
941
+ }
942
+ .v-toast .v-toast-dismiss {
943
+ margin-left: auto;
944
+ background: none;
945
+ border: none;
946
+ color: inherit;
947
+ opacity: 0.6;
948
+ cursor: pointer;
949
+ font-size: var(--v-font-size-lg);
950
+ padding: 0 var(--v-spacing-xs);
951
+ }
952
+ .v-toast .v-toast-dismiss:hover {
953
+ opacity: 1;
954
+ }
955
+
956
+ /* Empty State — enhanced version with icon + CTA */
957
+ .v-empty-state {
958
+ text-align: center;
959
+ color: var(--v-content-tertiary);
960
+ padding: var(--v-spacing-xxxl) var(--v-spacing-xl);
961
+ display: flex;
962
+ flex-direction: column;
963
+ align-items: center;
964
+ gap: var(--v-spacing-md);
965
+ }
966
+ .v-empty-state .v-empty-icon {
967
+ font-size: 48px;
968
+ line-height: 1;
969
+ opacity: 0.5;
970
+ }
971
+ .v-empty-state .v-empty-title {
972
+ font-size: var(--v-font-size-lg);
973
+ font-weight: 600;
974
+ color: var(--v-content-secondary);
975
+ margin: 0;
976
+ }
977
+ .v-empty-state .v-empty-desc {
978
+ font-size: var(--v-font-size-base);
979
+ color: var(--v-content-tertiary);
980
+ max-width: 360px;
981
+ }
982
+
983
+ /* Divider — horizontal rule with optional label */
984
+ .v-divider {
985
+ display: flex;
986
+ align-items: center;
987
+ gap: var(--v-spacing-md);
988
+ margin: var(--v-spacing-xl) 0;
989
+ color: var(--v-content-tertiary);
990
+ font-size: var(--v-font-size-xs);
991
+ font-weight: 500;
992
+ text-transform: uppercase;
993
+ letter-spacing: 0.04em;
994
+ }
995
+ .v-divider::before,
996
+ .v-divider::after {
997
+ content: "";
998
+ flex: 1;
999
+ height: 1px;
1000
+ background: var(--v-border-base);
1001
+ }
1002
+ .v-divider:empty::after {
1003
+ display: none;
1004
+ }
1005
+
1006
+ /* Avatar Row — circular avatar + name + subtitle */
1007
+ .v-avatar-row {
1008
+ display: flex;
1009
+ align-items: center;
1010
+ gap: var(--v-spacing-md);
1011
+ }
1012
+ .v-avatar-row .v-avatar {
1013
+ width: 36px;
1014
+ height: 36px;
1015
+ border-radius: 50%;
1016
+ background: var(--v-primary-base);
1017
+ color: var(--v-content-inset);
1018
+ display: flex;
1019
+ align-items: center;
1020
+ justify-content: center;
1021
+ font-weight: 600;
1022
+ font-size: var(--v-font-size-sm);
1023
+ flex-shrink: 0;
1024
+ overflow: hidden;
1025
+ }
1026
+ .v-avatar-row .v-avatar img {
1027
+ width: 100%;
1028
+ height: 100%;
1029
+ object-fit: cover;
1030
+ }
1031
+ .v-avatar-row .v-avatar-info {
1032
+ display: flex;
1033
+ flex-direction: column;
1034
+ min-width: 0;
1035
+ }
1036
+ .v-avatar-row .v-avatar-name {
1037
+ font-weight: 500;
1038
+ color: var(--v-content-default);
1039
+ white-space: nowrap;
1040
+ overflow: hidden;
1041
+ text-overflow: ellipsis;
1042
+ }
1043
+ .v-avatar-row .v-avatar-subtitle {
1044
+ font-size: var(--v-font-size-sm);
1045
+ color: var(--v-content-secondary);
1046
+ }
1047
+
1048
+ /* Tag / Chip Group — wrapping row of badges */
1049
+ .v-tag-group {
1050
+ display: flex;
1051
+ flex-wrap: wrap;
1052
+ gap: var(--v-spacing-xs);
1053
+ }
1054
+
1055
+ /* ── Tier 2: Domain-Specific Widgets ────────────────────────── */
1056
+
1057
+ /* Weather Card */
1058
+ .v-weather-card {
1059
+ background: var(--v-surface-base);
1060
+ border: 1px solid var(--v-border-base);
1061
+ border-radius: var(--v-radius-lg);
1062
+ padding: var(--v-spacing-lg);
1063
+ display: flex;
1064
+ flex-direction: column;
1065
+ gap: var(--v-spacing-md);
1066
+ }
1067
+ .v-weather-card .v-weather-main {
1068
+ display: flex;
1069
+ align-items: center;
1070
+ gap: var(--v-spacing-lg);
1071
+ }
1072
+ .v-weather-card .v-weather-temp {
1073
+ font-size: 48px;
1074
+ font-weight: 700;
1075
+ line-height: 1;
1076
+ color: var(--v-content-default);
1077
+ }
1078
+ .v-weather-card .v-weather-condition {
1079
+ font-size: var(--v-font-size-sm);
1080
+ color: var(--v-content-secondary);
1081
+ }
1082
+ .v-weather-card .v-weather-icon {
1083
+ font-size: 48px;
1084
+ line-height: 1;
1085
+ }
1086
+ .v-weather-card .v-weather-details {
1087
+ display: flex;
1088
+ gap: var(--v-spacing-lg);
1089
+ font-size: var(--v-font-size-sm);
1090
+ color: var(--v-content-secondary);
1091
+ }
1092
+ .v-weather-card .v-weather-forecast {
1093
+ display: grid;
1094
+ grid-template-columns: repeat(auto-fit, minmax(60px, 1fr));
1095
+ gap: var(--v-spacing-sm);
1096
+ text-align: center;
1097
+ }
1098
+ .v-weather-card .v-weather-forecast-item {
1099
+ display: flex;
1100
+ flex-direction: column;
1101
+ align-items: center;
1102
+ gap: var(--v-spacing-xxs);
1103
+ font-size: var(--v-font-size-xs);
1104
+ color: var(--v-content-secondary);
1105
+ padding: var(--v-spacing-sm);
1106
+ border-radius: var(--v-radius-md);
1107
+ background: color-mix(in srgb, var(--v-border-base) 30%, transparent);
1108
+ }
1109
+
1110
+ /* Stock Ticker */
1111
+ .v-stock-ticker {
1112
+ background: var(--v-surface-base);
1113
+ border: 1px solid var(--v-border-base);
1114
+ border-radius: var(--v-radius-lg);
1115
+ padding: var(--v-spacing-lg);
1116
+ display: flex;
1117
+ flex-direction: column;
1118
+ gap: var(--v-spacing-md);
1119
+ }
1120
+ .v-stock-ticker .v-stock-header {
1121
+ display: flex;
1122
+ align-items: baseline;
1123
+ gap: var(--v-spacing-md);
1124
+ }
1125
+ .v-stock-ticker .v-stock-symbol {
1126
+ font-size: var(--v-font-size-lg);
1127
+ font-weight: 700;
1128
+ color: var(--v-content-default);
1129
+ }
1130
+ .v-stock-ticker .v-stock-price {
1131
+ font-size: var(--v-font-size-2xl);
1132
+ font-weight: 700;
1133
+ color: var(--v-content-default);
1134
+ }
1135
+ .v-stock-ticker .v-stock-change {
1136
+ font-size: var(--v-font-size-sm);
1137
+ font-weight: 600;
1138
+ }
1139
+ .v-stock-ticker .v-stock-change.up { color: var(--v-system-positive-strong); }
1140
+ .v-stock-ticker .v-stock-change.down { color: var(--v-system-negative-strong); }
1141
+ .v-stock-ticker .v-stock-chart {
1142
+ width: 100%;
1143
+ height: 120px;
1144
+ border-radius: var(--v-radius-md);
1145
+ overflow: hidden;
1146
+ }
1147
+ .v-stock-ticker .v-stock-meta {
1148
+ display: flex;
1149
+ gap: var(--v-spacing-lg);
1150
+ font-size: var(--v-font-size-xs);
1151
+ color: var(--v-content-tertiary);
1152
+ }
1153
+
1154
+ /* Flight Card */
1155
+ .v-flight-card {
1156
+ background: var(--v-surface-base);
1157
+ border: 1px solid var(--v-border-base);
1158
+ border-radius: var(--v-radius-lg);
1159
+ padding: var(--v-spacing-lg);
1160
+ display: flex;
1161
+ flex-direction: column;
1162
+ gap: var(--v-spacing-md);
1163
+ }
1164
+ .v-flight-card .v-flight-header {
1165
+ display: flex;
1166
+ align-items: center;
1167
+ justify-content: space-between;
1168
+ }
1169
+ .v-flight-card .v-flight-airline {
1170
+ font-weight: 600;
1171
+ color: var(--v-content-default);
1172
+ }
1173
+ .v-flight-card .v-flight-price {
1174
+ font-size: var(--v-font-size-lg);
1175
+ font-weight: 700;
1176
+ color: var(--v-primary-base);
1177
+ }
1178
+ .v-flight-card .v-flight-route {
1179
+ display: flex;
1180
+ align-items: center;
1181
+ justify-content: space-between;
1182
+ gap: var(--v-spacing-md);
1183
+ }
1184
+ .v-flight-card .v-flight-endpoint {
1185
+ display: flex;
1186
+ flex-direction: column;
1187
+ gap: var(--v-spacing-xxs);
1188
+ }
1189
+ .v-flight-card .v-flight-time {
1190
+ font-size: var(--v-font-size-xl);
1191
+ font-weight: 700;
1192
+ color: var(--v-content-default);
1193
+ }
1194
+ .v-flight-card .v-flight-code {
1195
+ font-size: var(--v-font-size-sm);
1196
+ color: var(--v-content-secondary);
1197
+ font-weight: 500;
1198
+ }
1199
+ .v-flight-card .v-flight-duration {
1200
+ display: flex;
1201
+ flex-direction: column;
1202
+ align-items: center;
1203
+ gap: var(--v-spacing-xxs);
1204
+ font-size: var(--v-font-size-xs);
1205
+ color: var(--v-content-tertiary);
1206
+ }
1207
+ .v-flight-card .v-flight-line {
1208
+ width: 80px;
1209
+ height: 1px;
1210
+ background: var(--v-border-base);
1211
+ position: relative;
1212
+ }
1213
+ .v-flight-card .v-flight-line::after {
1214
+ content: "\2708";
1215
+ position: absolute;
1216
+ right: -4px;
1217
+ top: -8px;
1218
+ font-size: var(--v-font-size-base);
1219
+ color: var(--v-content-tertiary);
1220
+ }
1221
+ .v-flight-card .v-flight-meta {
1222
+ display: flex;
1223
+ gap: var(--v-spacing-lg);
1224
+ font-size: var(--v-font-size-xs);
1225
+ color: var(--v-content-tertiary);
1226
+ }
1227
+
1228
+ /* Billing Chart */
1229
+ .v-billing-chart {
1230
+ background: var(--v-surface-base);
1231
+ border: 1px solid var(--v-border-base);
1232
+ border-radius: var(--v-radius-lg);
1233
+ padding: var(--v-spacing-lg);
1234
+ display: flex;
1235
+ flex-direction: column;
1236
+ gap: var(--v-spacing-md);
1237
+ }
1238
+ .v-billing-chart .v-billing-header {
1239
+ display: flex;
1240
+ align-items: baseline;
1241
+ justify-content: space-between;
1242
+ }
1243
+ .v-billing-chart .v-billing-total {
1244
+ font-size: var(--v-font-size-2xl);
1245
+ font-weight: 700;
1246
+ color: var(--v-content-default);
1247
+ }
1248
+ .v-billing-chart .v-billing-period {
1249
+ font-size: var(--v-font-size-sm);
1250
+ color: var(--v-content-secondary);
1251
+ }
1252
+ .v-billing-chart .v-billing-canvas {
1253
+ width: 100%;
1254
+ height: 160px;
1255
+ border-radius: var(--v-radius-md);
1256
+ overflow: hidden;
1257
+ }
1258
+ .v-billing-chart .v-billing-legend {
1259
+ display: flex;
1260
+ flex-wrap: wrap;
1261
+ gap: var(--v-spacing-md);
1262
+ font-size: var(--v-font-size-xs);
1263
+ color: var(--v-content-secondary);
1264
+ }
1265
+ .v-billing-chart .v-billing-legend-item {
1266
+ display: flex;
1267
+ align-items: center;
1268
+ gap: var(--v-spacing-xs);
1269
+ }
1270
+ .v-billing-chart .v-billing-legend-dot {
1271
+ width: 8px;
1272
+ height: 8px;
1273
+ border-radius: 50%;
1274
+ }
1275
+
1276
+ /* Boarding Pass */
1277
+ .v-boarding-pass {
1278
+ background: var(--v-surface-base);
1279
+ border: 1px solid var(--v-border-base);
1280
+ border-radius: var(--v-radius-lg);
1281
+ padding: var(--v-spacing-lg);
1282
+ display: flex;
1283
+ flex-direction: column;
1284
+ gap: var(--v-spacing-lg);
1285
+ position: relative;
1286
+ overflow: hidden;
1287
+ }
1288
+ .v-boarding-pass::before {
1289
+ content: "";
1290
+ position: absolute;
1291
+ left: -8px;
1292
+ top: 50%;
1293
+ width: 16px;
1294
+ height: 16px;
1295
+ border-radius: 50%;
1296
+ background: var(--v-surface-overlay);
1297
+ }
1298
+ .v-boarding-pass::after {
1299
+ content: "";
1300
+ position: absolute;
1301
+ right: -8px;
1302
+ top: 50%;
1303
+ width: 16px;
1304
+ height: 16px;
1305
+ border-radius: 50%;
1306
+ background: var(--v-surface-overlay);
1307
+ }
1308
+ .v-boarding-pass .v-bp-header {
1309
+ display: flex;
1310
+ justify-content: space-between;
1311
+ align-items: center;
1312
+ font-weight: 600;
1313
+ color: var(--v-content-default);
1314
+ }
1315
+ .v-boarding-pass .v-bp-route {
1316
+ display: flex;
1317
+ justify-content: space-between;
1318
+ align-items: center;
1319
+ }
1320
+ .v-boarding-pass .v-bp-city {
1321
+ font-size: var(--v-font-size-2xl);
1322
+ font-weight: 700;
1323
+ color: var(--v-content-default);
1324
+ }
1325
+ .v-boarding-pass .v-bp-details {
1326
+ display: grid;
1327
+ grid-template-columns: repeat(auto-fit, minmax(80px, 1fr));
1328
+ gap: var(--v-spacing-md);
1329
+ padding-top: var(--v-spacing-md);
1330
+ border-top: 1px dashed var(--v-border-base);
1331
+ }
1332
+ .v-boarding-pass .v-bp-field {
1333
+ display: flex;
1334
+ flex-direction: column;
1335
+ gap: var(--v-spacing-xxs);
1336
+ }
1337
+ .v-boarding-pass .v-bp-field-label {
1338
+ font-size: var(--v-font-size-xs);
1339
+ color: var(--v-content-tertiary);
1340
+ text-transform: uppercase;
1341
+ letter-spacing: 0.05em;
1342
+ }
1343
+ .v-boarding-pass .v-bp-field-value {
1344
+ font-size: var(--v-font-size-lg);
1345
+ font-weight: 700;
1346
+ color: var(--v-content-default);
1347
+ }
1348
+
1349
+ /* Itinerary */
1350
+ .v-itinerary {
1351
+ display: flex;
1352
+ flex-direction: column;
1353
+ gap: var(--v-spacing-lg);
1354
+ }
1355
+ .v-itinerary .v-itinerary-day {
1356
+ display: flex;
1357
+ flex-direction: column;
1358
+ gap: var(--v-spacing-sm);
1359
+ }
1360
+ .v-itinerary .v-itinerary-date {
1361
+ font-size: var(--v-font-size-sm);
1362
+ font-weight: 600;
1363
+ color: var(--v-primary-base);
1364
+ text-transform: uppercase;
1365
+ letter-spacing: 0.04em;
1366
+ }
1367
+ .v-itinerary .v-itinerary-item {
1368
+ background: var(--v-surface-base);
1369
+ border: 1px solid var(--v-border-base);
1370
+ border-radius: var(--v-radius-md);
1371
+ padding: var(--v-spacing-md) var(--v-spacing-lg);
1372
+ display: flex;
1373
+ align-items: center;
1374
+ gap: var(--v-spacing-md);
1375
+ }
1376
+ .v-itinerary .v-itinerary-time {
1377
+ font-size: var(--v-font-size-sm);
1378
+ color: var(--v-content-tertiary);
1379
+ font-weight: 500;
1380
+ white-space: nowrap;
1381
+ }
1382
+ .v-itinerary .v-itinerary-content {
1383
+ flex: 1;
1384
+ }
1385
+ .v-itinerary .v-itinerary-title {
1386
+ font-weight: 500;
1387
+ color: var(--v-content-default);
1388
+ }
1389
+ .v-itinerary .v-itinerary-location {
1390
+ font-size: var(--v-font-size-sm);
1391
+ color: var(--v-content-secondary);
1392
+ }
1393
+
1394
+ /* Receipt */
1395
+ .v-receipt {
1396
+ background: var(--v-surface-base);
1397
+ border: 1px solid var(--v-border-base);
1398
+ border-radius: var(--v-radius-lg);
1399
+ padding: var(--v-spacing-xl);
1400
+ display: flex;
1401
+ flex-direction: column;
1402
+ gap: var(--v-spacing-md);
1403
+ max-width: 400px;
1404
+ font-family: var(--v-font-mono);
1405
+ }
1406
+ .v-receipt .v-receipt-header {
1407
+ text-align: center;
1408
+ padding-bottom: var(--v-spacing-md);
1409
+ border-bottom: 1px dashed var(--v-border-base);
1410
+ }
1411
+ .v-receipt .v-receipt-store {
1412
+ font-size: var(--v-font-size-lg);
1413
+ font-weight: 700;
1414
+ color: var(--v-content-default);
1415
+ font-family: var(--v-font-family);
1416
+ }
1417
+ .v-receipt .v-receipt-items {
1418
+ display: flex;
1419
+ flex-direction: column;
1420
+ gap: var(--v-spacing-xs);
1421
+ }
1422
+ .v-receipt .v-receipt-line {
1423
+ display: flex;
1424
+ justify-content: space-between;
1425
+ font-size: var(--v-font-size-sm);
1426
+ color: var(--v-content-default);
1427
+ }
1428
+ .v-receipt .v-receipt-divider {
1429
+ border: none;
1430
+ border-top: 1px dashed var(--v-border-base);
1431
+ margin: var(--v-spacing-sm) 0;
1432
+ }
1433
+ .v-receipt .v-receipt-total {
1434
+ display: flex;
1435
+ justify-content: space-between;
1436
+ font-weight: 700;
1437
+ font-size: var(--v-font-size-base);
1438
+ color: var(--v-content-default);
1439
+ padding-top: var(--v-spacing-sm);
1440
+ border-top: 2px solid var(--v-border-base);
1441
+ }
1442
+
1443
+ /* Invoice */
1444
+ .v-invoice {
1445
+ background: var(--v-surface-base);
1446
+ border: 1px solid var(--v-border-base);
1447
+ border-radius: var(--v-radius-lg);
1448
+ padding: var(--v-spacing-xl);
1449
+ display: flex;
1450
+ flex-direction: column;
1451
+ gap: var(--v-spacing-lg);
1452
+ }
1453
+ .v-invoice .v-invoice-header {
1454
+ display: flex;
1455
+ justify-content: space-between;
1456
+ align-items: flex-start;
1457
+ }
1458
+ .v-invoice .v-invoice-title {
1459
+ font-size: var(--v-font-size-xl);
1460
+ font-weight: 700;
1461
+ color: var(--v-content-default);
1462
+ }
1463
+ .v-invoice .v-invoice-number {
1464
+ font-size: var(--v-font-size-sm);
1465
+ color: var(--v-content-secondary);
1466
+ font-family: var(--v-font-mono);
1467
+ }
1468
+ .v-invoice .v-invoice-parties {
1469
+ display: grid;
1470
+ grid-template-columns: 1fr 1fr;
1471
+ gap: var(--v-spacing-xl);
1472
+ }
1473
+ .v-invoice .v-invoice-party-label {
1474
+ font-size: var(--v-font-size-xs);
1475
+ color: var(--v-content-tertiary);
1476
+ text-transform: uppercase;
1477
+ letter-spacing: 0.04em;
1478
+ margin-bottom: var(--v-spacing-xs);
1479
+ }
1480
+ .v-invoice .v-invoice-party-name {
1481
+ font-weight: 600;
1482
+ color: var(--v-content-default);
1483
+ }
1484
+ .v-invoice .v-invoice-party-detail {
1485
+ font-size: var(--v-font-size-sm);
1486
+ color: var(--v-content-secondary);
1487
+ }
1488
+ .v-invoice .v-invoice-table {
1489
+ width: 100%;
1490
+ border-collapse: collapse;
1491
+ }
1492
+ .v-invoice .v-invoice-table th {
1493
+ text-align: left;
1494
+ font-size: var(--v-font-size-xs);
1495
+ color: var(--v-content-tertiary);
1496
+ text-transform: uppercase;
1497
+ letter-spacing: 0.04em;
1498
+ padding: var(--v-spacing-sm) var(--v-spacing-md);
1499
+ border-bottom: 2px solid var(--v-border-base);
1500
+ }
1501
+ .v-invoice .v-invoice-table td {
1502
+ padding: var(--v-spacing-sm) var(--v-spacing-md);
1503
+ border-bottom: 1px solid var(--v-border-base);
1504
+ font-size: var(--v-font-size-sm);
1505
+ color: var(--v-content-default);
1506
+ }
1507
+ .v-invoice .v-invoice-table td:last-child,
1508
+ .v-invoice .v-invoice-table th:last-child {
1509
+ text-align: right;
1510
+ }
1511
+ .v-invoice .v-invoice-totals {
1512
+ display: flex;
1513
+ flex-direction: column;
1514
+ align-items: flex-end;
1515
+ gap: var(--v-spacing-xs);
1516
+ }
1517
+ .v-invoice .v-invoice-totals .v-invoice-line {
1518
+ display: flex;
1519
+ gap: var(--v-spacing-xxl);
1520
+ font-size: var(--v-font-size-sm);
1521
+ color: var(--v-content-secondary);
1522
+ }
1523
+ .v-invoice .v-invoice-totals .v-invoice-line.total {
1524
+ font-weight: 700;
1525
+ font-size: var(--v-font-size-lg);
1526
+ color: var(--v-content-default);
1527
+ padding-top: var(--v-spacing-sm);
1528
+ border-top: 2px solid var(--v-border-base);
1529
+ }
1530
+ .v-invoice .v-invoice-footer {
1531
+ font-size: var(--v-font-size-xs);
1532
+ color: var(--v-content-tertiary);
1533
+ padding-top: var(--v-spacing-md);
1534
+ border-top: 1px solid var(--v-border-base);
1535
+ }
1536
+
1537
+ /* ── Tier 3: Content & Landing Page Components ─────────────── */
1538
+
1539
+ /* Page — centered content container for landing pages */
1540
+ .v-page {
1541
+ margin: 0 auto;
1542
+ display: flex;
1543
+ flex-direction: column;
1544
+ gap: var(--v-spacing-xxl);
1545
+ width: 100%;
1546
+ }
1547
+
1548
+ /* Hero — top-of-page banner with gradient background */
1549
+ .v-hero {
1550
+ position: relative;
1551
+ background: linear-gradient(135deg, var(--v-system-positive-weak) 0%, var(--v-border-active) 100%);
1552
+ border-radius: var(--v-radius-xl);
1553
+ padding: var(--v-spacing-xxxl) var(--v-spacing-xl);
1554
+ text-align: center;
1555
+ overflow: hidden;
1556
+ display: flex;
1557
+ flex-direction: column;
1558
+ align-items: center;
1559
+ gap: var(--v-spacing-md);
1560
+ }
1561
+ .v-hero::before {
1562
+ content: "";
1563
+ position: absolute;
1564
+ top: -40%;
1565
+ left: 50%;
1566
+ transform: translateX(-50%);
1567
+ width: 120%;
1568
+ height: 80%;
1569
+ background: radial-gradient(ellipse, color-mix(in srgb, var(--v-primary-base) 30%, transparent) 0%, transparent 70%);
1570
+ pointer-events: none;
1571
+ }
1572
+ .v-hero-badge {
1573
+ display: inline-block;
1574
+ padding: var(--v-spacing-xs) var(--v-spacing-lg);
1575
+ background: rgba(255, 255, 255, 0.1);
1576
+ backdrop-filter: blur(8px);
1577
+ -webkit-backdrop-filter: blur(8px);
1578
+ border: 1px solid rgba(255, 255, 255, 0.15);
1579
+ border-radius: var(--v-radius-pill);
1580
+ font-size: var(--v-font-size-xs);
1581
+ font-weight: 600;
1582
+ text-transform: uppercase;
1583
+ letter-spacing: 0.06em;
1584
+ color: var(--v-content-disabled);
1585
+ position: relative;
1586
+ }
1587
+ .v-hero h1 {
1588
+ font-size: 2.5rem;
1589
+ font-weight: 800;
1590
+ background: linear-gradient(180deg, #fff 30%, var(--v-content-background) 100%);
1591
+ -webkit-background-clip: text;
1592
+ -webkit-text-fill-color: transparent;
1593
+ background-clip: text;
1594
+ margin: 0;
1595
+ position: relative;
1596
+ line-height: 1.15;
1597
+ }
1598
+ .v-hero-subtitle {
1599
+ font-size: var(--v-font-size-base);
1600
+ color: var(--v-content-tertiary);
1601
+ max-width: 500px;
1602
+ margin: 0 auto;
1603
+ line-height: 1.5;
1604
+ position: relative;
1605
+ }
1606
+
1607
+ /* Section Header — labeled section intro */
1608
+ .v-section-header {
1609
+ display: flex;
1610
+ flex-direction: column;
1611
+ gap: var(--v-spacing-xs);
1612
+ margin-bottom: var(--v-spacing-lg);
1613
+ }
1614
+ .v-section-label {
1615
+ font-size: var(--v-font-size-xs);
1616
+ font-weight: 600;
1617
+ text-transform: uppercase;
1618
+ letter-spacing: 0.06em;
1619
+ color: var(--v-primary-base);
1620
+ }
1621
+ .v-section-header h2 {
1622
+ margin: 0;
1623
+ }
1624
+ .v-section-desc {
1625
+ font-size: var(--v-font-size-base);
1626
+ color: var(--v-content-secondary);
1627
+ margin: 0;
1628
+ }
1629
+
1630
+ /* Pullquote — dramatic blockquote with glassmorphism */
1631
+ .v-pullquote {
1632
+ position: relative;
1633
+ background: var(--v-surface-base);
1634
+ border: 1px solid var(--v-border-base);
1635
+ border-radius: var(--v-radius-lg);
1636
+ padding: var(--v-spacing-xl);
1637
+ display: flex;
1638
+ flex-direction: column;
1639
+ gap: var(--v-spacing-md);
1640
+ }
1641
+ .v-pullquote::before {
1642
+ content: "";
1643
+ position: absolute;
1644
+ left: 0;
1645
+ top: var(--v-spacing-lg);
1646
+ bottom: var(--v-spacing-lg);
1647
+ width: 3px;
1648
+ background: linear-gradient(180deg, var(--v-primary-hover) 0%, var(--v-primary-active) 100%);
1649
+ border-radius: var(--v-radius-pill);
1650
+ }
1651
+ .v-pullquote-text {
1652
+ font-size: var(--v-font-size-lg);
1653
+ font-style: italic;
1654
+ color: var(--v-content-default);
1655
+ line-height: 1.5;
1656
+ margin: 0;
1657
+ padding-left: var(--v-spacing-lg);
1658
+ }
1659
+ .v-pullquote-points {
1660
+ list-style: none;
1661
+ padding: 0;
1662
+ margin: 0;
1663
+ display: flex;
1664
+ flex-direction: column;
1665
+ gap: var(--v-spacing-sm);
1666
+ padding-left: var(--v-spacing-lg);
1667
+ }
1668
+ .v-pullquote-points li {
1669
+ position: relative;
1670
+ padding-left: var(--v-spacing-lg);
1671
+ font-size: var(--v-font-size-base);
1672
+ color: var(--v-content-secondary);
1673
+ }
1674
+ .v-pullquote-points li::before {
1675
+ content: "";
1676
+ position: absolute;
1677
+ left: 0;
1678
+ top: 0.55em;
1679
+ width: 6px;
1680
+ height: 6px;
1681
+ border-radius: 50%;
1682
+ background: var(--v-primary-base);
1683
+ }
1684
+
1685
+ /* Comparison — before/after or contrasting ideas */
1686
+ .v-comparison {
1687
+ display: grid;
1688
+ grid-template-columns: 1fr auto 1fr;
1689
+ gap: var(--v-spacing-md);
1690
+ align-items: center;
1691
+ }
1692
+ .v-comparison-card {
1693
+ background: var(--v-surface-base);
1694
+ border: 1px solid var(--v-border-base);
1695
+ border-radius: var(--v-radius-lg);
1696
+ padding: var(--v-spacing-lg);
1697
+ display: flex;
1698
+ flex-direction: column;
1699
+ gap: var(--v-spacing-sm);
1700
+ }
1701
+ .v-comparison-card.before {
1702
+ background: color-mix(in srgb, var(--v-surface-base) 60%, var(--v-surface-overlay));
1703
+ }
1704
+ .v-comparison-card.before .v-comparison-label {
1705
+ color: var(--v-content-tertiary);
1706
+ }
1707
+ .v-comparison-card.after {
1708
+ background: color-mix(in srgb, var(--v-primary-base) 8%, var(--v-surface-base));
1709
+ border-color: color-mix(in srgb, var(--v-primary-base) 25%, var(--v-border-base));
1710
+ }
1711
+ .v-comparison-card.after .v-comparison-label {
1712
+ color: var(--v-primary-base);
1713
+ }
1714
+ .v-comparison-label {
1715
+ font-size: var(--v-font-size-xs);
1716
+ font-weight: 600;
1717
+ text-transform: uppercase;
1718
+ letter-spacing: 0.06em;
1719
+ }
1720
+ .v-comparison-arrow {
1721
+ font-size: var(--v-font-size-xl);
1722
+ color: var(--v-content-tertiary);
1723
+ text-align: center;
1724
+ }
1725
+
1726
+ /* Feature Grid — auto-fit grid of feature cards */
1727
+ .v-feature-grid {
1728
+ display: grid;
1729
+ grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
1730
+ gap: var(--v-spacing-lg);
1731
+ }
1732
+ .v-feature-card {
1733
+ background: var(--v-surface-base);
1734
+ border: 1px solid var(--v-border-base);
1735
+ border-radius: var(--v-radius-lg);
1736
+ padding: var(--v-spacing-lg);
1737
+ display: flex;
1738
+ flex-direction: column;
1739
+ gap: var(--v-spacing-sm);
1740
+ transition: transform var(--v-duration-fast) ease-out,
1741
+ box-shadow var(--v-duration-fast) ease-out;
1742
+ }
1743
+ .v-feature-card:hover {
1744
+ transform: translateY(-2px);
1745
+ box-shadow: var(--v-shadow-md);
1746
+ }
1747
+ .v-feature-card .v-feature-icon {
1748
+ font-size: 24px;
1749
+ line-height: 1;
1750
+ }
1751
+ .v-feature-card .v-feature-title {
1752
+ font-size: var(--v-font-size-base);
1753
+ font-weight: 600;
1754
+ color: var(--v-content-default);
1755
+ }
1756
+ .v-feature-card .v-feature-desc {
1757
+ font-size: var(--v-font-size-sm);
1758
+ color: var(--v-content-secondary);
1759
+ line-height: 1.4;
1760
+ }
1761
+
1762
+ /* Gradient Text — forest gradient text fill */
1763
+ .v-gradient-text {
1764
+ background: linear-gradient(135deg, var(--v-primary-active) 0%, var(--v-system-positive-weak) 100%);
1765
+ -webkit-background-clip: text;
1766
+ -webkit-text-fill-color: transparent;
1767
+ background-clip: text;
1768
+ }
1769
+
1770
+ /* Staggered Fade-In Animation */
1771
+ @keyframes v-fade-in {
1772
+ from {
1773
+ opacity: 0;
1774
+ transform: translateY(12px);
1775
+ }
1776
+ to {
1777
+ opacity: 1;
1778
+ transform: translateY(0);
1779
+ }
1780
+ }
1781
+ .v-animate-in {
1782
+ animation: v-fade-in var(--v-duration-slow) ease-out both;
1783
+ }
1784
+ .v-animate-in:nth-child(1) { animation-delay: 0s; }
1785
+ .v-animate-in:nth-child(2) { animation-delay: 0.1s; }
1786
+ .v-animate-in:nth-child(3) { animation-delay: 0.2s; }
1787
+ .v-animate-in:nth-child(4) { animation-delay: 0.3s; }
1788
+ .v-animate-in:nth-child(5) { animation-delay: 0.4s; }
1789
+ .v-animate-in:nth-child(6) { animation-delay: 0.5s; }
1790
+
1791
+ /* ── Pill Toggles — time range / filter toggle group ────────── */
1792
+ .v-pill-toggles {
1793
+ display: inline-flex;
1794
+ gap: var(--v-spacing-xxs);
1795
+ background: var(--v-surface-base);
1796
+ border: 1px solid var(--v-border-base);
1797
+ border-radius: var(--v-radius-md);
1798
+ padding: var(--v-spacing-xxs);
1799
+ }
1800
+ .v-pill-toggle {
1801
+ padding: var(--v-spacing-xs) var(--v-spacing-md);
1802
+ border-radius: var(--v-radius-md);
1803
+ border: none;
1804
+ background: none;
1805
+ font-size: var(--v-font-size-sm);
1806
+ font-weight: 500;
1807
+ color: var(--v-content-secondary);
1808
+ cursor: pointer;
1809
+ transition: all var(--v-duration-fast) ease-out;
1810
+ }
1811
+ .v-pill-toggle:hover {
1812
+ color: var(--v-content-default);
1813
+ }
1814
+ .v-pill-toggle.active {
1815
+ background: var(--v-primary-base);
1816
+ color: var(--v-aux-white);
1817
+ font-weight: 600;
1818
+ box-shadow: var(--v-shadow-sm);
1819
+ }
1820
+
1821
+ /* ── Chip Group — suggestion / filter chip row ─────────────── */
1822
+ .v-chip-group {
1823
+ display: flex;
1824
+ flex-wrap: wrap;
1825
+ gap: var(--v-spacing-xs);
1826
+ }
1827
+ .v-chip {
1828
+ padding: var(--v-spacing-xs) var(--v-spacing-md);
1829
+ border-radius: var(--v-radius-md);
1830
+ border: 1px solid var(--v-border-base);
1831
+ background: var(--v-surface-base);
1832
+ font-size: var(--v-font-size-sm);
1833
+ color: var(--v-content-secondary);
1834
+ cursor: pointer;
1835
+ transition: all var(--v-duration-fast) ease-out;
1836
+ }
1837
+ .v-chip:hover {
1838
+ border-color: var(--v-primary-base);
1839
+ color: var(--v-content-default);
1840
+ }
1841
+ .v-chip.active {
1842
+ background: color-mix(in srgb, var(--v-primary-base) 12%, transparent);
1843
+ border-color: var(--v-primary-base);
1844
+ color: var(--v-primary-base);
1845
+ font-weight: 600;
1846
+ }
1847
+
1848
+ /* ── Metric Icon — emoji icon for metric cards ─────────────── */
1849
+ .v-metric-card .v-metric-icon {
1850
+ font-size: 28px;
1851
+ line-height: 1;
1852
+ }
1853
+
1854
+ /* ── Action Bar — sticky bulk-action bar for multi-select UIs ── */
1855
+ .v-action-bar {
1856
+ position: sticky;
1857
+ top: 0;
1858
+ z-index: 100;
1859
+ display: none;
1860
+ align-items: center;
1861
+ gap: var(--v-spacing-md);
1862
+ padding: var(--v-spacing-sm) var(--v-spacing-lg);
1863
+ background: var(--v-surface-base);
1864
+ border-bottom: 1px solid var(--v-border-base);
1865
+ backdrop-filter: blur(12px);
1866
+ -webkit-backdrop-filter: blur(12px);
1867
+ }
1868
+ .v-action-bar.visible {
1869
+ display: flex;
1870
+ }
1871
+ .v-action-bar-count {
1872
+ font-size: var(--v-font-size-sm);
1873
+ font-weight: 600;
1874
+ color: var(--v-primary-base);
1875
+ white-space: nowrap;
1876
+ }
1877
+ .v-action-bar-buttons {
1878
+ display: flex;
1879
+ gap: var(--v-spacing-sm);
1880
+ margin-left: auto;
1881
+ }
1882
+
1883
+ /* ── Action Progress — inline progress bar during bulk ops ───── */
1884
+ .v-action-progress {
1885
+ width: 100%;
1886
+ height: 4px;
1887
+ border-radius: var(--v-radius-pill);
1888
+ background: var(--v-border-base);
1889
+ overflow: hidden;
1890
+ }
1891
+ .v-action-progress::after {
1892
+ content: '';
1893
+ display: block;
1894
+ height: 100%;
1895
+ width: var(--progress, 0%);
1896
+ background: var(--v-primary-base);
1897
+ border-radius: var(--v-radius-pill);
1898
+ transition: width 0.3s ease-out;
1899
+ }
1900
+
1901
+ /* ── Group Header — collapsible section with checkbox + chevron ─ */
1902
+ .v-group-header {
1903
+ display: flex;
1904
+ align-items: center;
1905
+ gap: var(--v-spacing-sm);
1906
+ padding: var(--v-spacing-sm) var(--v-spacing-md);
1907
+ background: color-mix(in srgb, var(--v-surface-base) 60%, transparent);
1908
+ border-radius: var(--v-radius-md);
1909
+ cursor: pointer;
1910
+ user-select: none;
1911
+ -webkit-user-select: none;
1912
+ transition: background var(--v-duration-fast) ease-out;
1913
+ }
1914
+ .v-group-header:hover {
1915
+ background: var(--v-surface-base);
1916
+ }
1917
+ .v-group-header .v-group-title {
1918
+ flex: 1;
1919
+ font-weight: 600;
1920
+ font-size: var(--v-font-size-base);
1921
+ color: var(--v-content-default);
1922
+ }
1923
+ .v-group-header .v-group-count {
1924
+ font-size: var(--v-font-size-sm);
1925
+ color: var(--v-content-tertiary);
1926
+ }
1927
+ .v-group-header .v-group-chevron {
1928
+ font-size: 12px;
1929
+ color: var(--v-content-tertiary);
1930
+ transition: transform var(--v-duration-fast) ease-out;
1931
+ }
1932
+ .v-group-header[aria-expanded="true"] .v-group-chevron {
1933
+ transform: rotate(90deg);
1934
+ }
1935
+
1936
+ /* ── Group Body — indented container for group items ─────────── */
1937
+ .v-group-body {
1938
+ padding-left: var(--v-spacing-xl);
1939
+ overflow: hidden;
1940
+ }
1941
+
1942
+ /* ── Row Removing — fade-out + slide animation for processed items */
1943
+ .v-row-removing {
1944
+ opacity: 0;
1945
+ transform: translateX(20px);
1946
+ max-height: 0;
1947
+ padding-top: 0 !important;
1948
+ padding-bottom: 0 !important;
1949
+ margin-top: 0 !important;
1950
+ margin-bottom: 0 !important;
1951
+ overflow: hidden;
1952
+ transition: opacity 0.25s ease-out,
1953
+ transform 0.25s ease-out,
1954
+ max-height 0.3s 0.1s ease-out,
1955
+ padding 0.3s 0.1s ease-out,
1956
+ margin 0.3s 0.1s ease-out;
1957
+ }
1958
+
1959
+ } /* end @layer vellum-design-system */