@assemble-inc/chat-widget 0.1.3 → 0.1.5
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.
- package/README.md +34 -58
- package/dist/Widget.d.ts +69 -3
- package/dist/embed.d.ts +25 -0
- package/dist/embed.iife.js +7 -7
- package/dist/index.d.ts +2 -3
- package/dist/index.js +10023 -3227
- package/dist/server.cjs +31 -8
- package/dist/server.d.cts +29 -5
- package/dist/server.d.ts +29 -5
- package/dist/server.js +31 -8
- package/package.json +1 -1
- package/dist/index.css +0 -1
package/dist/server.cjs
CHANGED
|
@@ -27,18 +27,40 @@ var import_anthropic = require("@ai-sdk/anthropic");
|
|
|
27
27
|
var import_ai = require("ai");
|
|
28
28
|
var import_streamableHttp = require("@modelcontextprotocol/sdk/client/streamableHttp.js");
|
|
29
29
|
var import_client = require("@modelcontextprotocol/sdk/client/index.js");
|
|
30
|
-
var
|
|
30
|
+
var DEFAULT_SYSTEM_PROMPT = `You are a helpful assistant. You must ONLY answer questions using information returned by the tools available to you \u2014 never draw on your own training knowledge. If the tools do not return relevant information, respond with: "I don't have that information available." Do not guess or speculate.`;
|
|
31
31
|
function createChatHandler(config) {
|
|
32
32
|
const anthropicClient = (0, import_anthropic.createAnthropic)({ apiKey: config.apiKey });
|
|
33
|
-
const
|
|
34
|
-
const transportOptions = config.mcpBearerToken ? { requestInit: { headers: { Authorization: `Bearer ${config.mcpBearerToken}` } } } : {};
|
|
33
|
+
const defaultModel = "claude-sonnet-4-5";
|
|
35
34
|
return async (req, res) => {
|
|
36
|
-
const {
|
|
35
|
+
const {
|
|
36
|
+
messages: uiMessages,
|
|
37
|
+
systemPrompt: widgetSystemPrompt,
|
|
38
|
+
context,
|
|
39
|
+
mcpServerUrl: requestedUrl,
|
|
40
|
+
model: widgetModel,
|
|
41
|
+
temperature: widgetTemperature,
|
|
42
|
+
user
|
|
43
|
+
} = req.body;
|
|
37
44
|
const messages = await (0, import_ai.convertToModelMessages)(uiMessages);
|
|
45
|
+
const allowlist = config.mcpCredentials ?? {};
|
|
46
|
+
const resolvedUrl = requestedUrl && (requestedUrl === config.mcpServerUrl || Object.prototype.hasOwnProperty.call(allowlist, requestedUrl)) ? requestedUrl : config.mcpServerUrl;
|
|
47
|
+
const resolvedToken = resolvedUrl === config.mcpServerUrl ? config.mcpBearerToken : allowlist[resolvedUrl];
|
|
48
|
+
const base = config.systemPrompt ?? widgetSystemPrompt ?? DEFAULT_SYSTEM_PROMPT;
|
|
49
|
+
const userContext = [
|
|
50
|
+
context,
|
|
51
|
+
user ? `User: ${JSON.stringify(user)}` : void 0
|
|
52
|
+
].filter(Boolean).join("\n");
|
|
53
|
+
const system = userContext ? `${base}
|
|
54
|
+
|
|
55
|
+
## Context
|
|
56
|
+
${userContext}` : base;
|
|
57
|
+
const resolvedModel = config.model ?? widgetModel ?? defaultModel;
|
|
58
|
+
const temperature = config.temperature ?? widgetTemperature;
|
|
59
|
+
const transportOptions = resolvedToken ? { requestInit: { headers: { Authorization: `Bearer ${resolvedToken}` } } } : {};
|
|
38
60
|
const mcpClient = new import_client.Client({ name: "@assemble-inc/chat-widget", version: "0.1.0" });
|
|
39
61
|
try {
|
|
40
62
|
await mcpClient.connect(
|
|
41
|
-
new import_streamableHttp.StreamableHTTPClientTransport(new URL(
|
|
63
|
+
new import_streamableHttp.StreamableHTTPClientTransport(new URL(resolvedUrl), transportOptions)
|
|
42
64
|
);
|
|
43
65
|
const { tools: mcpTools } = await mcpClient.listTools();
|
|
44
66
|
const tools = Object.fromEntries(
|
|
@@ -58,17 +80,18 @@ function createChatHandler(config) {
|
|
|
58
80
|
])
|
|
59
81
|
);
|
|
60
82
|
const result = (0, import_ai.streamText)({
|
|
61
|
-
model: anthropicClient(
|
|
62
|
-
system
|
|
83
|
+
model: anthropicClient(resolvedModel),
|
|
84
|
+
system,
|
|
63
85
|
messages,
|
|
64
86
|
tools,
|
|
87
|
+
temperature,
|
|
65
88
|
stopWhen: (0, import_ai.stepCountIs)(10)
|
|
66
89
|
});
|
|
67
90
|
result.pipeUIMessageStreamToResponse(res);
|
|
68
91
|
} catch (err) {
|
|
69
92
|
console.error("[chat handler] error:", err);
|
|
70
93
|
if (!res.headersSent) {
|
|
71
|
-
res.status(502).json({ error: "Failed to connect
|
|
94
|
+
res.status(502).json({ error: "Failed to connect. Check server credentials." });
|
|
72
95
|
}
|
|
73
96
|
} finally {
|
|
74
97
|
await mcpClient.close();
|
package/dist/server.d.cts
CHANGED
|
@@ -3,16 +3,40 @@ import { Request, Response } from 'express';
|
|
|
3
3
|
interface ChatHandlerConfig {
|
|
4
4
|
/** Anthropic API key */
|
|
5
5
|
apiKey: string;
|
|
6
|
-
/** URL
|
|
6
|
+
/** Default MCP server URL used when no per-embed URL is provided */
|
|
7
7
|
mcpServerUrl: string;
|
|
8
|
-
/** Bearer token for
|
|
8
|
+
/** Bearer token for the default mcpServerUrl */
|
|
9
9
|
mcpBearerToken?: string;
|
|
10
|
-
/**
|
|
10
|
+
/**
|
|
11
|
+
* Claude model to use. Defaults to 'claude-sonnet-4-5'.
|
|
12
|
+
* Takes precedence over any model sent by the widget embed.
|
|
13
|
+
*/
|
|
11
14
|
model?: string;
|
|
15
|
+
/**
|
|
16
|
+
* Operator-defined system prompt. Replaces the built-in default when set.
|
|
17
|
+
* Takes precedence over any systemPrompt sent by the widget embed.
|
|
18
|
+
*/
|
|
19
|
+
systemPrompt?: string;
|
|
20
|
+
/**
|
|
21
|
+
* Model temperature (0–1). Overrides any temperature sent by the widget when set.
|
|
22
|
+
*/
|
|
23
|
+
temperature?: number;
|
|
24
|
+
/**
|
|
25
|
+
* Allowlist of additional MCP server URLs that embeds may request,
|
|
26
|
+
* mapped to their bearer tokens. Credentials never leave the server.
|
|
27
|
+
* When omitted, only mcpServerUrl is accepted from embeds.
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* { 'https://mcp.acme.com/hr': process.env.MCP_HR_TOKEN }
|
|
31
|
+
*/
|
|
32
|
+
mcpCredentials?: Record<string, string | undefined>;
|
|
12
33
|
}
|
|
13
34
|
/**
|
|
14
|
-
* Returns an Express-compatible request handler that streams chat responses
|
|
15
|
-
*
|
|
35
|
+
* Returns an Express-compatible request handler that streams chat responses.
|
|
36
|
+
*
|
|
37
|
+
* The server-side config (systemPrompt, temperature, mcpCredentials) always takes
|
|
38
|
+
* precedence over values sent by the widget embed, allowing operators to lock
|
|
39
|
+
* behaviour while still enabling per-embed customisation where desired.
|
|
16
40
|
*
|
|
17
41
|
* @example
|
|
18
42
|
* ```ts
|
package/dist/server.d.ts
CHANGED
|
@@ -3,16 +3,40 @@ import { Request, Response } from 'express';
|
|
|
3
3
|
interface ChatHandlerConfig {
|
|
4
4
|
/** Anthropic API key */
|
|
5
5
|
apiKey: string;
|
|
6
|
-
/** URL
|
|
6
|
+
/** Default MCP server URL used when no per-embed URL is provided */
|
|
7
7
|
mcpServerUrl: string;
|
|
8
|
-
/** Bearer token for
|
|
8
|
+
/** Bearer token for the default mcpServerUrl */
|
|
9
9
|
mcpBearerToken?: string;
|
|
10
|
-
/**
|
|
10
|
+
/**
|
|
11
|
+
* Claude model to use. Defaults to 'claude-sonnet-4-5'.
|
|
12
|
+
* Takes precedence over any model sent by the widget embed.
|
|
13
|
+
*/
|
|
11
14
|
model?: string;
|
|
15
|
+
/**
|
|
16
|
+
* Operator-defined system prompt. Replaces the built-in default when set.
|
|
17
|
+
* Takes precedence over any systemPrompt sent by the widget embed.
|
|
18
|
+
*/
|
|
19
|
+
systemPrompt?: string;
|
|
20
|
+
/**
|
|
21
|
+
* Model temperature (0–1). Overrides any temperature sent by the widget when set.
|
|
22
|
+
*/
|
|
23
|
+
temperature?: number;
|
|
24
|
+
/**
|
|
25
|
+
* Allowlist of additional MCP server URLs that embeds may request,
|
|
26
|
+
* mapped to their bearer tokens. Credentials never leave the server.
|
|
27
|
+
* When omitted, only mcpServerUrl is accepted from embeds.
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* { 'https://mcp.acme.com/hr': process.env.MCP_HR_TOKEN }
|
|
31
|
+
*/
|
|
32
|
+
mcpCredentials?: Record<string, string | undefined>;
|
|
12
33
|
}
|
|
13
34
|
/**
|
|
14
|
-
* Returns an Express-compatible request handler that streams chat responses
|
|
15
|
-
*
|
|
35
|
+
* Returns an Express-compatible request handler that streams chat responses.
|
|
36
|
+
*
|
|
37
|
+
* The server-side config (systemPrompt, temperature, mcpCredentials) always takes
|
|
38
|
+
* precedence over values sent by the widget embed, allowing operators to lock
|
|
39
|
+
* behaviour while still enabling per-embed customisation where desired.
|
|
16
40
|
*
|
|
17
41
|
* @example
|
|
18
42
|
* ```ts
|
package/dist/server.js
CHANGED
|
@@ -3,18 +3,40 @@ import { createAnthropic } from "@ai-sdk/anthropic";
|
|
|
3
3
|
import { streamText, tool, jsonSchema, stepCountIs, convertToModelMessages } from "ai";
|
|
4
4
|
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
5
5
|
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
6
|
-
var
|
|
6
|
+
var DEFAULT_SYSTEM_PROMPT = `You are a helpful assistant. You must ONLY answer questions using information returned by the tools available to you \u2014 never draw on your own training knowledge. If the tools do not return relevant information, respond with: "I don't have that information available." Do not guess or speculate.`;
|
|
7
7
|
function createChatHandler(config) {
|
|
8
8
|
const anthropicClient = createAnthropic({ apiKey: config.apiKey });
|
|
9
|
-
const
|
|
10
|
-
const transportOptions = config.mcpBearerToken ? { requestInit: { headers: { Authorization: `Bearer ${config.mcpBearerToken}` } } } : {};
|
|
9
|
+
const defaultModel = "claude-sonnet-4-5";
|
|
11
10
|
return async (req, res) => {
|
|
12
|
-
const {
|
|
11
|
+
const {
|
|
12
|
+
messages: uiMessages,
|
|
13
|
+
systemPrompt: widgetSystemPrompt,
|
|
14
|
+
context,
|
|
15
|
+
mcpServerUrl: requestedUrl,
|
|
16
|
+
model: widgetModel,
|
|
17
|
+
temperature: widgetTemperature,
|
|
18
|
+
user
|
|
19
|
+
} = req.body;
|
|
13
20
|
const messages = await convertToModelMessages(uiMessages);
|
|
21
|
+
const allowlist = config.mcpCredentials ?? {};
|
|
22
|
+
const resolvedUrl = requestedUrl && (requestedUrl === config.mcpServerUrl || Object.prototype.hasOwnProperty.call(allowlist, requestedUrl)) ? requestedUrl : config.mcpServerUrl;
|
|
23
|
+
const resolvedToken = resolvedUrl === config.mcpServerUrl ? config.mcpBearerToken : allowlist[resolvedUrl];
|
|
24
|
+
const base = config.systemPrompt ?? widgetSystemPrompt ?? DEFAULT_SYSTEM_PROMPT;
|
|
25
|
+
const userContext = [
|
|
26
|
+
context,
|
|
27
|
+
user ? `User: ${JSON.stringify(user)}` : void 0
|
|
28
|
+
].filter(Boolean).join("\n");
|
|
29
|
+
const system = userContext ? `${base}
|
|
30
|
+
|
|
31
|
+
## Context
|
|
32
|
+
${userContext}` : base;
|
|
33
|
+
const resolvedModel = config.model ?? widgetModel ?? defaultModel;
|
|
34
|
+
const temperature = config.temperature ?? widgetTemperature;
|
|
35
|
+
const transportOptions = resolvedToken ? { requestInit: { headers: { Authorization: `Bearer ${resolvedToken}` } } } : {};
|
|
14
36
|
const mcpClient = new Client({ name: "@assemble-inc/chat-widget", version: "0.1.0" });
|
|
15
37
|
try {
|
|
16
38
|
await mcpClient.connect(
|
|
17
|
-
new StreamableHTTPClientTransport(new URL(
|
|
39
|
+
new StreamableHTTPClientTransport(new URL(resolvedUrl), transportOptions)
|
|
18
40
|
);
|
|
19
41
|
const { tools: mcpTools } = await mcpClient.listTools();
|
|
20
42
|
const tools = Object.fromEntries(
|
|
@@ -34,17 +56,18 @@ function createChatHandler(config) {
|
|
|
34
56
|
])
|
|
35
57
|
);
|
|
36
58
|
const result = streamText({
|
|
37
|
-
model: anthropicClient(
|
|
38
|
-
system
|
|
59
|
+
model: anthropicClient(resolvedModel),
|
|
60
|
+
system,
|
|
39
61
|
messages,
|
|
40
62
|
tools,
|
|
63
|
+
temperature,
|
|
41
64
|
stopWhen: stepCountIs(10)
|
|
42
65
|
});
|
|
43
66
|
result.pipeUIMessageStreamToResponse(res);
|
|
44
67
|
} catch (err) {
|
|
45
68
|
console.error("[chat handler] error:", err);
|
|
46
69
|
if (!res.headersSent) {
|
|
47
|
-
res.status(502).json({ error: "Failed to connect
|
|
70
|
+
res.status(502).json({ error: "Failed to connect. Check server credentials." });
|
|
48
71
|
}
|
|
49
72
|
} finally {
|
|
50
73
|
await mcpClient.close();
|
package/package.json
CHANGED
package/dist/index.css
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
/*! tailwindcss v4.2.4 | MIT License | https://tailwindcss.com */@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-scale-x:1;--tw-scale-y:1;--tw-scale-z:1;--tw-border-style:solid;--tw-gradient-position:initial;--tw-gradient-from:#0000;--tw-gradient-via:#0000;--tw-gradient-to:#0000;--tw-gradient-stops:initial;--tw-gradient-via-stops:initial;--tw-gradient-from-position:0%;--tw-gradient-via-position:50%;--tw-gradient-to-position:100%;--tw-leading:initial;--tw-font-weight:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-duration:initial;--tw-ease:initial}}}@layer theme{:root,:host{--font-sans:ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--color-slate-400:oklch(70.4% .04 256.788);--color-gray-200:oklch(92.8% .006 264.531);--color-gray-300:oklch(87.2% .01 258.338);--color-gray-500:oklch(55.1% .027 264.364);--color-gray-600:oklch(44.6% .03 256.802);--color-neutral-300:oklch(87% 0 0);--color-white:#fff;--spacing:.25rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-lg:1.125rem;--text-lg--line-height:calc(1.75 / 1.125);--text-2xl:1.5rem;--text-2xl--line-height:calc(2 / 1.5);--font-weight-semibold:600;--font-weight-bold:700;--radius-lg:.5rem;--radius-xl:.75rem;--radius-3xl:1.5rem;--ease-in-out:cubic-bezier(.4, 0, .2, 1);--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono);--color-asm-white:#fff;--color-asm-purple:#2e2438;--color-asm-pink-400:#ffa2f6;--color-asm-blue:#a5d5d8;--color-asm-gray-500:#f1f1f1}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;-moz-tab-size:4;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab,red,red)){::placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){-webkit-appearance:button;-moz-appearance:button;appearance:button}::file-selector-button{-webkit-appearance:button;-moz-appearance:button;appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.sr-only{clip-path:inset(50%);white-space:nowrap;border-width:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.start{inset-inline-start:var(--spacing)}.top-1\/2{top:50%}.top-2{top:calc(var(--spacing) * 2)}.top-4{top:calc(var(--spacing) * 4)}.right-0{right:calc(var(--spacing) * 0)}.right-2{right:calc(var(--spacing) * 2)}.right-4{right:calc(var(--spacing) * 4)}.right-6{right:calc(var(--spacing) * 6)}.-bottom-4{bottom:calc(var(--spacing) * -4)}.bottom-0{bottom:calc(var(--spacing) * 0)}.bottom-1{bottom:calc(var(--spacing) * 1)}.bottom-2{bottom:calc(var(--spacing) * 2)}.bottom-6{bottom:calc(var(--spacing) * 6)}.bottom-20{bottom:calc(var(--spacing) * 20)}.left-0{left:calc(var(--spacing) * 0)}.left-1\/2{left:50%}.left-4{left:calc(var(--spacing) * 4)}.z-10{z-index:10}.z-40{z-index:40}.z-50{z-index:50}.z-\[1\]{z-index:1}.z-\[2\]{z-index:2}.z-\[3\]{z-index:3}.-mt-2{margin-top:calc(var(--spacing) * -2)}.mt-2{margin-top:calc(var(--spacing) * 2)}.-mr-\[2px\]{margin-right:-2px}.-mr-\[4\.5rem\]{margin-right:-4.5rem}.mr-0{margin-right:calc(var(--spacing) * 0)}.mr-1{margin-right:calc(var(--spacing) * 1)}.mb-24{margin-bottom:calc(var(--spacing) * 24)}.ml-0{margin-left:calc(var(--spacing) * 0)}.ml-1{margin-left:calc(var(--spacing) * 1)}.ml-2{margin-left:calc(var(--spacing) * 2)}.flex{display:flex}.grid{display:grid}.inline-block{display:inline-block}.h-0{height:calc(var(--spacing) * 0)}.h-3\/4{height:75%}.h-5\/6{height:83.3333%}.h-6{height:calc(var(--spacing) * 6)}.h-10{height:calc(var(--spacing) * 10)}.h-16{height:calc(var(--spacing) * 16)}.h-24{height:calc(var(--spacing) * 24)}.h-full{height:100%}.max-h-\[500px\]{max-height:500px}.max-h-\[800px\]{max-height:800px}.min-h-\[46px\]{min-height:46px}.w-0{width:calc(var(--spacing) * 0)}.w-6{width:calc(var(--spacing) * 6)}.w-10{width:calc(var(--spacing) * 10)}.w-16{width:calc(var(--spacing) * 16)}.w-56{width:calc(var(--spacing) * 56)}.w-80{width:calc(var(--spacing) * 80)}.w-full{width:100%}.shrink-0{flex-shrink:0}.origin-bottom-right{transform-origin:100% 100%}.-translate-x-1\/2{--tw-translate-x: -50% ;translate:var(--tw-translate-x) var(--tw-translate-y)}.-translate-x-\[2rem\]{--tw-translate-x: -2rem ;translate:var(--tw-translate-x) var(--tw-translate-y)}.translate-x-0{--tw-translate-x:calc(var(--spacing) * 0);translate:var(--tw-translate-x) var(--tw-translate-y)}.translate-y-0{--tw-translate-y:calc(var(--spacing) * 0);translate:var(--tw-translate-x) var(--tw-translate-y)}.translate-y-28{--tw-translate-y:calc(var(--spacing) * 28);translate:var(--tw-translate-x) var(--tw-translate-y)}.translate-y-full{--tw-translate-y:100%;translate:var(--tw-translate-x) var(--tw-translate-y)}.scale-0{--tw-scale-x:0%;--tw-scale-y:0%;--tw-scale-z:0%;scale:var(--tw-scale-x) var(--tw-scale-y)}.scale-100{--tw-scale-x:100%;--tw-scale-y:100%;--tw-scale-z:100%;scale:var(--tw-scale-x) var(--tw-scale-y)}.-rotate-45{rotate:-45deg}.transform-gpu{transform:translateZ(0) var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)}.cursor-pointer{cursor:pointer}.flex-col{flex-direction:column}.flex-row{flex-direction:row}.flex-row-reverse{flex-direction:row-reverse}.place-content-center{place-content:center}.items-center{align-items:center}.items-end{align-items:flex-end}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.justify-end{justify-content:flex-end}.gap-2{gap:calc(var(--spacing) * 2)}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.rounded-3xl{border-radius:var(--radius-3xl)}.rounded-\[43px\]{border-radius:43px}.rounded-full{border-radius:3.40282e38px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-xl{border-radius:var(--radius-xl)}.rounded-t-\[43px\]{border-top-left-radius:43px;border-top-right-radius:43px}.rounded-tl-\[50\%\]{border-top-left-radius:50%}.rounded-tl-none{border-top-left-radius:0}.rounded-tr-\[50\%\]{border-top-right-radius:50%}.rounded-tr-none{border-top-right-radius:0}.rounded-br{border-bottom-right-radius:.25rem}.rounded-bl-\[50\%\]{border-bottom-left-radius:50%}.border{border-style:var(--tw-border-style);border-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-b-0{border-bottom-style:var(--tw-border-style);border-bottom-width:0}.border-gray-300{border-color:var(--color-gray-300)}.border-slate-400{border-color:var(--color-slate-400)}.bg-asm-gray-500{background-color:var(--color-asm-gray-500)}.bg-asm-pink-400{background-color:var(--color-asm-pink-400)}.bg-asm-purple{background-color:var(--color-asm-purple)}.bg-asm-white{background-color:var(--color-asm-white)}.bg-gray-200{background-color:var(--color-gray-200)}.bg-transparent{background-color:#0000}.bg-white{background-color:var(--color-white)}.bg-gradient-to-br{--tw-gradient-position:to bottom right in oklab;background-image:linear-gradient(var(--tw-gradient-stops))}.from-gray-500{--tw-gradient-from:var(--color-gray-500);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.to-neutral-300{--tw-gradient-to:var(--color-neutral-300);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.p-2{padding:calc(var(--spacing) * 2)}.p-3{padding:calc(var(--spacing) * 3)}.p-4{padding:calc(var(--spacing) * 4)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-4{padding-inline:calc(var(--spacing) * 4)}.py-1{padding-block:calc(var(--spacing) * 1)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-6{padding-block:calc(var(--spacing) * 6)}.py-\[\.625rem\]{padding-block:.625rem}.pb-2{padding-bottom:calc(var(--spacing) * 2)}.text-center{text-align:center}.text-2xl{font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}.text-lg{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.leading-5{--tw-leading:calc(var(--spacing) * 5);line-height:calc(var(--spacing) * 5)}.leading-none{--tw-leading:1;line-height:1}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.whitespace-nowrap{white-space:nowrap}.text-asm-purple{color:var(--color-asm-purple)}.text-gray-600{color:var(--color-gray-600)}.text-white{color:var(--color-white)}.opacity-8{opacity:.08}.shadow{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-lg{--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a), 0 4px 6px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-md{--tw-shadow:0 4px 6px -1px var(--tw-shadow-color,#0000001a), 0 2px 4px -2px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.transition-all{transition-property:all;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.duration-300{--tw-duration:.3s;transition-duration:.3s}.ease-in-out{--tw-ease:var(--ease-in-out);transition-timing-function:var(--ease-in-out)}.first\:pt-4:first-child{padding-top:calc(var(--spacing) * 4)}.last\:pb-4:last-child{padding-bottom:calc(var(--spacing) * 4)}@media(hover:hover){.hover\:bg-asm-blue\/30:hover{background-color:#a5d5d84d}@supports (color:color-mix(in lab,red,red)){.hover\:bg-asm-blue\/30:hover{background-color:color-mix(in oklab,var(--color-asm-blue) 30%,transparent)}}}.focus\:outline-asm-gray-500:focus{outline-color:var(--color-asm-gray-500)}@media(prefers-reduced-motion:reduce){.motion-reduce\:transition-none{transition-property:none}}}html,body{height:100%;font-family:Inter,sans-serif}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}@property --tw-scale-x{syntax:"*";inherits:false;initial-value:1}@property --tw-scale-y{syntax:"*";inherits:false;initial-value:1}@property --tw-scale-z{syntax:"*";inherits:false;initial-value:1}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-gradient-position{syntax:"*";inherits:false}@property --tw-gradient-from{syntax:"<color>";inherits:false;initial-value:#0000}@property --tw-gradient-via{syntax:"<color>";inherits:false;initial-value:#0000}@property --tw-gradient-to{syntax:"<color>";inherits:false;initial-value:#0000}@property --tw-gradient-stops{syntax:"*";inherits:false}@property --tw-gradient-via-stops{syntax:"*";inherits:false}@property --tw-gradient-from-position{syntax:"<length-percentage>";inherits:false;initial-value:0%}@property --tw-gradient-via-position{syntax:"<length-percentage>";inherits:false;initial-value:50%}@property --tw-gradient-to-position{syntax:"<length-percentage>";inherits:false;initial-value:100%}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-duration{syntax:"*";inherits:false}@property --tw-ease{syntax:"*";inherits:false}
|