@helpai/elements 0.20.0 → 0.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/schema.mjs CHANGED
@@ -17,7 +17,7 @@ var localeSchema = z.string().min(1).max(35).describe("BCP-47 locale tag (e.g. `
17
17
  var uuid7Schema = z.uuidv7().describe("UUID v7 (RFC 9562) \u2014 the single id format for visitor / conversation / message / file / content ids.");
18
18
 
19
19
  // src/schema/widget.ts
20
- import { z as z16 } from "zod";
20
+ import { z as z15 } from "zod";
21
21
 
22
22
  // src/schema/widget/presentation.ts
23
23
  import { z as z3 } from "zod";
@@ -341,33 +341,21 @@ var composerOptionsSchema = z10.object({
341
341
  ]
342
342
  });
343
343
 
344
- // src/schema/widget/welcome.ts
345
- import { z as z11 } from "zod";
346
- var welcomeAnimationSchema = z11.enum(["typewriter", "instant"]);
347
- var welcomeOptionsSchema = z11.object({
348
- animation: welcomeAnimationSchema.default("instant").describe(
349
- "How welcome messages render \u2014 `typewriter` types each message in character-by-character; `instant` shows them whole."
350
- ),
351
- speed: z11.number().int().min(1).max(2e3).default(60).describe("Typewriter speed in characters per second. Only meaningful when `animation = typewriter`.")
352
- }).loose().describe("How welcome messages render \u2014 instant by default; opt into a typewriter effect with adjustable cps speed.").meta({
353
- examples: [{ animation: "instant" }, { animation: "typewriter", speed: 60 }]
354
- });
355
-
356
344
  // src/schema/widget/footer.ts
357
- import { z as z12 } from "zod";
358
- var poweredBySchema = z12.object({
359
- text: z12.string().max(200).optional().describe("Visible attribution text (e.g. `Powered by Help AI`)."),
360
- href: z12.url().max(2048).optional().describe("Click target \u2014 the attribution becomes a link. Must be a full URL (`https://\u2026`)."),
361
- logoUrl: z12.url().max(2048).optional().describe("Small logo rendered before the text. Must be a full URL.")
345
+ import { z as z11 } from "zod";
346
+ var poweredBySchema = z11.object({
347
+ text: z11.string().max(200).optional().describe("Visible attribution text (e.g. `Powered by Help AI`)."),
348
+ href: z11.url().max(2048).optional().describe("Click target \u2014 the attribution becomes a link. Must be a full URL (`https://\u2026`)."),
349
+ logoUrl: z11.url().max(2048).optional().describe("Small logo rendered before the text. Must be a full URL.")
362
350
  }).loose().describe('"Powered by \u2026" attribution shown below the composer.').meta({
363
351
  examples: [
364
352
  { text: "Powered by Help AI" },
365
353
  { text: "Powered by Help AI", href: "https://help.ai", logoUrl: "https://help.ai/logo.svg" }
366
354
  ]
367
355
  });
368
- var footerSchema = z12.object({
356
+ var footerSchema = z11.object({
369
357
  poweredBy: poweredBySchema.optional(),
370
- composerDisclaimer: z12.string().max(500).optional().describe("Small muted text under the composer (like ChatGPT's 'ChatGPT can make mistakes.'). Empty = hidden.")
358
+ composerDisclaimer: z11.string().max(500).optional().describe("Small muted text under the composer (like ChatGPT's 'ChatGPT can make mistakes.'). Empty = hidden.")
371
359
  }).loose().describe("Footer \u2014 attribution + composer disclaimer.").meta({
372
360
  examples: [
373
361
  { poweredBy: { text: "Powered by Help AI", href: "https://help.ai" } },
@@ -376,8 +364,8 @@ var footerSchema = z12.object({
376
364
  });
377
365
 
378
366
  // src/schema/widget/forms.ts
379
- import { z as z13 } from "zod";
380
- var fieldTypeSchema = z13.enum([
367
+ import { z as z12 } from "zod";
368
+ var fieldTypeSchema = z12.enum([
381
369
  "text",
382
370
  "email",
383
371
  "tel",
@@ -391,59 +379,59 @@ var fieldTypeSchema = z13.enum([
391
379
  "checkbox",
392
380
  "multiselect"
393
381
  ]);
394
- var fieldOptionSchema = z13.object({
395
- value: z13.string().min(1).max(200).describe("The value recorded when this choice is picked."),
396
- label: z13.string().min(1).max(200).optional().describe("Display text; falls back to `value`."),
397
- description: z13.string().max(280).optional().describe("Optional sub-label under the choice.")
382
+ var fieldOptionSchema = z12.object({
383
+ value: z12.string().min(1).max(200).describe("The value recorded when this choice is picked."),
384
+ label: z12.string().min(1).max(200).optional().describe("Display text; falls back to `value`."),
385
+ description: z12.string().max(280).optional().describe("Optional sub-label under the choice.")
398
386
  }).loose();
399
- var fieldValidationSchema = z13.object({
400
- pattern: z13.string().max(500).optional().describe("Regex source string \u2014 text-like fields (e.g. `^\\d{5}$`)."),
401
- minLength: z13.number().int().min(0).max(1e4).optional(),
402
- maxLength: z13.number().int().min(1).max(1e4).optional(),
403
- min: z13.number().optional().describe("Minimum \u2014 `number` fields."),
404
- max: z13.number().optional().describe("Maximum \u2014 `number` fields."),
405
- minSelections: z13.number().int().min(0).max(50).optional().describe("Minimum picks \u2014 `multiselect`."),
406
- maxSelections: z13.number().int().min(1).max(50).optional().describe("Maximum picks \u2014 `multiselect`.")
387
+ var fieldValidationSchema = z12.object({
388
+ pattern: z12.string().max(500).optional().describe("Regex source string \u2014 text-like fields (e.g. `^\\d{5}$`)."),
389
+ minLength: z12.number().int().min(0).max(1e4).optional(),
390
+ maxLength: z12.number().int().min(1).max(1e4).optional(),
391
+ min: z12.number().optional().describe("Minimum \u2014 `number` fields."),
392
+ max: z12.number().optional().describe("Maximum \u2014 `number` fields."),
393
+ minSelections: z12.number().int().min(0).max(50).optional().describe("Minimum picks \u2014 `multiselect`."),
394
+ maxSelections: z12.number().int().min(1).max(50).optional().describe("Maximum picks \u2014 `multiselect`.")
407
395
  }).loose();
408
- var formFieldSchema = z13.object({
409
- name: z13.string().min(1).max(80).describe("Stable key the answer is recorded under (e.g. `email`)."),
410
- label: z13.string().min(1).max(200).describe("Visible field label."),
396
+ var formFieldSchema = z12.object({
397
+ name: z12.string().min(1).max(80).describe("Stable key the answer is recorded under (e.g. `email`)."),
398
+ label: z12.string().min(1).max(200).describe("Visible field label."),
411
399
  type: fieldTypeSchema.describe("Field renderer + built-in validation (email/tel/url/number/date/time checked)."),
412
- placeholder: z13.string().max(200).optional(),
413
- required: z13.boolean().optional().default(true).describe("Must be answered to submit. `false` allows skipping."),
414
- defaultValue: z13.string().max(2e3).optional().describe("Pre-filled value (comma-join for `multiselect`)."),
415
- options: z13.array(fieldOptionSchema).max(50).optional().describe("Choices for `select` / `radio` / `multiselect`."),
400
+ placeholder: z12.string().max(200).optional(),
401
+ required: z12.boolean().optional().default(true).describe("Must be answered to submit. `false` allows skipping."),
402
+ defaultValue: z12.string().max(2e3).optional().describe("Pre-filled value (comma-join for `multiselect`)."),
403
+ options: z12.array(fieldOptionSchema).max(50).optional().describe("Choices for `select` / `radio` / `multiselect`."),
416
404
  validation: fieldValidationSchema.optional(),
417
- allowOther: z13.boolean().optional().describe("`select`/`radio`/`multiselect` \u2014 allow a free-text 'Other' answer."),
418
- validationHint: z13.string().max(280).optional().describe("Small helper line under the field.")
405
+ allowOther: z12.boolean().optional().describe("`select`/`radio`/`multiselect` \u2014 allow a free-text 'Other' answer."),
406
+ validationHint: z12.string().max(280).optional().describe("Small helper line under the field.")
419
407
  }).loose();
420
- var formTriggerSchema = z13.string().regex(
408
+ var formTriggerSchema = z12.string().regex(
421
409
  /^(pre-chat|conversation-closed|panel-close|manual|after-messages:\d+|idle:\d+|page-area:.+)$/,
422
410
  "Unrecognised form trigger"
423
411
  ).describe(
424
412
  "When the form fires: `pre-chat`, `after-messages:N`, `conversation-closed`, `panel-close`, `idle:Nseconds`, `page-area:<area>`, or `manual`."
425
413
  );
426
- var formConditionSchema = z13.object({
427
- missingContext: z13.array(z13.string().max(80)).max(20).optional().describe("Only show if `userContext` lacks ALL of these keys (progressive profiling)."),
428
- pageArea: z13.union([z13.string().max(64), z13.array(z13.string().max(64)).max(20)]).optional().describe("Only on these `pageContext.area` values."),
429
- minMessages: z13.number().int().min(0).max(1e3).optional(),
430
- maxMessages: z13.number().int().min(0).max(1e3).optional()
414
+ var formConditionSchema = z12.object({
415
+ missingContext: z12.array(z12.string().max(80)).max(20).optional().describe("Only show if `userContext` lacks ALL of these keys (progressive profiling)."),
416
+ pageArea: z12.union([z12.string().max(64), z12.array(z12.string().max(64)).max(20)]).optional().describe("Only on these `pageContext.area` values."),
417
+ minMessages: z12.number().int().min(0).max(1e3).optional(),
418
+ maxMessages: z12.number().int().min(0).max(1e3).optional()
431
419
  }).loose();
432
- var formDefSchema = z13.object({
433
- id: z13.string().min(1).max(80).describe("Stable id \u2014 persistence dedupe + `manual` openForm(id)."),
434
- on: z13.union([formTriggerSchema, z13.array(formTriggerSchema).min(1).max(8)]).describe("Trigger(s) that surface this form."),
420
+ var formDefSchema = z12.object({
421
+ id: z12.string().min(1).max(80).describe("Stable id \u2014 persistence dedupe + `manual` openForm(id)."),
422
+ on: z12.union([formTriggerSchema, z12.array(formTriggerSchema).min(1).max(8)]).describe("Trigger(s) that surface this form."),
435
423
  when: formConditionSchema.optional().describe("Extra eligibility predicate evaluated when a trigger fires."),
436
- fields: z13.array(formFieldSchema).max(20).default([]).describe("The questions, in order. \u22651 required to show."),
437
- title: z13.string().max(120).optional(),
438
- description: z13.string().max(500).optional(),
439
- submitLabel: z13.string().max(60).optional(),
440
- skippable: z13.boolean().default(false).describe("Show a Skip control so the visitor can dismiss the form."),
441
- frequency: z13.enum(["once", "conversation", "always"]).default("once").describe("`once` (per device, persisted), `conversation` (re-eligible each new conversation), or `always`."),
442
- mirrorToContext: z13.boolean().default(true).describe(
424
+ fields: z12.array(formFieldSchema).max(20).default([]).describe("The questions, in order. \u22651 required to show."),
425
+ title: z12.string().max(120).optional(),
426
+ description: z12.string().max(500).optional(),
427
+ submitLabel: z12.string().max(60).optional(),
428
+ skippable: z12.boolean().default(false).describe("Show a Skip control so the visitor can dismiss the form."),
429
+ frequency: z12.enum(["once", "conversation", "always"]).default("once").describe("`once` (per device, persisted), `conversation` (re-eligible each new conversation), or `always`."),
430
+ mirrorToContext: z12.boolean().default(true).describe(
443
431
  "Mirror the answers into `userContext` so they ride every request. Set `false` for PII (DOB, policy #, symptoms) \u2014 those then go only to the submit endpoint."
444
432
  )
445
433
  }).loose();
446
- var formsSchema = z13.array(formDefSchema).max(20).describe(
434
+ var formsSchema = z12.array(formDefSchema).max(20).describe(
447
435
  "Event-driven forms \u2014 an ordered list (order = priority). Each binds to trigger event(s), gates the chat until submit/skip, dedupes by frequency, and records via `endpoints.submitForm`. Generic across verticals."
448
436
  ).meta({
449
437
  examples: [
@@ -486,9 +474,9 @@ var formsSchema = z13.array(formDefSchema).max(20).describe(
486
474
  });
487
475
 
488
476
  // src/schema/widget/i18n.ts
489
- import { z as z14 } from "zod";
490
- var localeStringsSchema = z14.record(z14.string(), z14.string());
491
- var stringsOverrideSchema = z14.union([localeStringsSchema, z14.record(localeSchema, localeStringsSchema)]).describe(
477
+ import { z as z13 } from "zod";
478
+ var localeStringsSchema = z13.record(z13.string(), z13.string());
479
+ var stringsOverrideSchema = z13.union([localeStringsSchema, z13.record(localeSchema, localeStringsSchema)]).describe(
492
480
  "Per-instance UI string overrides. Flat = active-locale only; nested = multi-locale map. Both forms are partial \u2014 missing keys fall through to built-in defaults."
493
481
  ).meta({
494
482
  examples: [
@@ -499,10 +487,10 @@ var stringsOverrideSchema = z14.union([localeStringsSchema, z14.record(localeSch
499
487
  }
500
488
  ]
501
489
  });
502
- var i18nSchema = z14.object({
490
+ var i18nSchema = z13.object({
503
491
  locale: localeSchema.optional().describe("BCP-47 locale tag forced for this widget instance (e.g. `fr-CA`). Page-owner explicit override."),
504
- defaultLocale: z14.union([z14.literal("auto"), localeSchema]).default("auto").describe("Initial / fallback locale for users who haven't picked one. `auto` sniffs `navigator.language`."),
505
- availableLocales: z14.array(localeSchema).max(200).optional().describe("BCP-47 locale tags shown in the runtime language switcher. Hidden when fewer than 2 entries."),
492
+ defaultLocale: z13.union([z13.literal("auto"), localeSchema]).default("auto").describe("Initial / fallback locale for users who haven't picked one. `auto` sniffs `navigator.language`."),
493
+ availableLocales: z13.array(localeSchema).max(200).optional().describe("BCP-47 locale tags shown in the runtime language switcher. Hidden when fewer than 2 entries."),
506
494
  strings: stringsOverrideSchema.optional()
507
495
  }).loose().describe("Locale + i18n overrides.").meta({
508
496
  examples: [
@@ -513,44 +501,44 @@ var i18nSchema = z14.object({
513
501
  });
514
502
 
515
503
  // src/schema/widget/modules.ts
516
- import { z as z15 } from "zod";
517
- var moduleLayoutSchema = z15.enum(["chat", "home", "help", "news"]);
518
- var moduleSchema = z15.object({
519
- label: z15.string().min(1).max(40).describe(
504
+ import { z as z14 } from "zod";
505
+ var moduleLayoutSchema = z14.enum(["chat", "home", "help", "news"]);
506
+ var moduleSchema = z14.object({
507
+ label: z14.string().min(1).max(40).describe(
520
508
  "Tab label \u2014 an i18n key (resolved against the i18n strings, e.g. `tabHome`) or a literal. Translations ride `i18n.strings`."
521
509
  ),
522
510
  layout: moduleLayoutSchema.describe(
523
511
  "UI layout that renders this tab: `chat` (the conversation), `home`, `help`, or `news`."
524
512
  ),
525
- contentTags: z15.array(z15.string().max(60)).max(20).optional().describe(
513
+ contentTags: z14.array(z14.string().max(60)).max(20).optional().describe(
526
514
  "Content tags this tab scopes to \u2014 the `tags` filter on `GET /ai/agent/content` (matches content tagged with ANY of them). Omit for the `chat` layout."
527
515
  ),
528
- id: z15.string().max(60).optional().describe(
516
+ id: z14.string().max(60).optional().describe(
529
517
  "Stable id for navigation + last-tab persistence. Defaults to the first `contentTags` entry, else `layout`."
530
518
  ),
531
519
  // ── `home` layout config (flat feature flags — no block authoring) ──────
532
- brandName: z15.string().max(80).optional().describe("`home` \u2014 hero wordmark (e.g. your company name)."),
533
- showGreeting: z15.boolean().optional().describe("`home` \u2014 show the greeting hero (default true)."),
534
- greetingText: z15.string().max(280).optional().describe("`home` \u2014 override the greeting headline (default 'How can we help?'); supports a `{name}` token."),
535
- userAvatars: z15.array(
536
- z15.object({
537
- name: z15.string().min(1).max(80),
538
- avatar: z15.string().max(2048).optional().describe("Image URL; falls back to initials of `name`."),
539
- role: z15.string().max(80).optional()
520
+ brandName: z14.string().max(80).optional().describe("`home` \u2014 hero wordmark (e.g. your company name)."),
521
+ showGreeting: z14.boolean().optional().describe("`home` \u2014 show the greeting hero (default true)."),
522
+ greetingText: z14.string().max(280).optional().describe("`home` \u2014 override the greeting headline (default 'How can we help?'); supports a `{name}` token."),
523
+ userAvatars: z14.array(
524
+ z14.object({
525
+ name: z14.string().min(1).max(80),
526
+ avatar: z14.string().max(2048).optional().describe("Image URL; falls back to initials of `name`."),
527
+ role: z14.string().max(80).optional()
540
528
  }).loose()
541
529
  ).max(10).optional().describe("`home` \u2014 team/agent avatars shown in the hero."),
542
- showSearchBar: z15.boolean().optional().describe("`home` \u2014 show the 'Search for help' bar (default true)."),
543
- showRecentConversations: z15.boolean().optional().describe("`home` \u2014 show the visitor's most recent conversation card (default true)."),
544
- status: z15.object({
545
- text: z15.string().min(1).max(120),
546
- level: z15.string().max(40).optional().describe(
530
+ showSearchBar: z14.boolean().optional().describe("`home` \u2014 show the 'Search for help' bar (default true)."),
531
+ showRecentConversations: z14.boolean().optional().describe("`home` \u2014 show the visitor's most recent conversation card (default true)."),
532
+ status: z14.object({
533
+ text: z14.string().min(1).max(120),
534
+ level: z14.string().max(40).optional().describe(
547
535
  "`home` \u2014 status severity, drives the status icon colour. Free text; `operational` (green, default), `degraded` (amber), and `down` (red) are styled, any other value falls back to the operational style."
548
536
  ).meta({ examples: ["operational", "degraded", "down"] }),
549
- url: z15.string().max(2048).optional().describe("Opens in an in-widget iframe when tapped.")
537
+ url: z14.string().max(2048).optional().describe("Opens in an in-widget iframe when tapped.")
550
538
  }).optional().describe("`home` \u2014 system-status card. Omit to hide."),
551
- contentBlockTitle: z15.string().max(80).optional().describe("`home` \u2014 heading for the content list built from `contentTags` (default 'Popular articles').")
539
+ contentBlockTitle: z14.string().max(80).optional().describe("`home` \u2014 heading for the content list built from `contentTags` (default 'Popular articles').")
552
540
  }).loose();
553
- var modulesSchema = z15.array(moduleSchema).max(4).describe(
541
+ var modulesSchema = z14.array(moduleSchema).max(4).describe(
554
542
  "Messenger tabs \u2014 an ordered list of up to 4 tabs, each picking a `layout` + optional content `contentTags` (the content scope) + a translatable `label`. One tab \u2192 no tab bar (just that content); zero \u2192 an empty state. Floating / drawer / modal only."
555
543
  ).meta({
556
544
  examples: [
@@ -573,10 +561,10 @@ var modulesSchema = z15.array(moduleSchema).max(4).describe(
573
561
  });
574
562
 
575
563
  // src/schema/widget.ts
576
- var endpointsSchema = z16.object({
577
- upload: z16.string().min(1).max(2048).default("/ai/agent/upload-file"),
578
- transcribe: z16.string().min(1).max(2048).default("/ai/agent/transcribe-audio"),
579
- submitForm: z16.string().min(1).max(2048).default("/ai/agent/submit-form").describe(
564
+ var endpointsSchema = z15.object({
565
+ upload: z15.string().min(1).max(2048).default("/ai/agent/upload-file"),
566
+ transcribe: z15.string().min(1).max(2048).default("/ai/agent/transcribe-audio"),
567
+ submitForm: z15.string().min(1).max(2048).default("/ai/agent/submit-form").describe(
580
568
  "Form submission endpoint. The widget POSTs each completed form's values here (fire-and-forget), keyed by the same visitorId + conversationId as the conversation; the payload carries `formId` + `trigger` so the backend can route. Optional \u2014 a 404 is ignored."
581
569
  )
582
570
  }).loose().describe("HTTP endpoint overrides. Paths are appended to baseUrl; absolute URLs are accepted too.").meta({
@@ -586,14 +574,14 @@ var endpointsSchema = z16.object({
586
574
  { submitForm: "https://crm.acme.com/leads" }
587
575
  ]
588
576
  });
589
- var userContextSchema = z16.object({
590
- id: z16.string().min(1).max(200).optional().describe("Host's stable id for the user \u2014 informational context the agent/backend can key on (not auth)."),
591
- email: z16.string().min(1).max(320).optional().describe("User email \u2014 surfaced to the agent for context (optional)."),
592
- name: z16.string().min(1).max(200).optional().describe("Display name \u2014 shown in the Home greeting (`{name}`) and conversation transcripts (optional)."),
593
- plan: z16.string().min(1).max(120).optional().describe("Subscription / pricing tier, e.g. `pro` (optional)."),
594
- role: z16.string().min(1).max(120).optional().describe("The user's role on the host site, e.g. `admin` (optional)."),
595
- phone: z16.string().min(1).max(40).optional().describe("Phone number (optional).")
596
- }).catchall(z16.union([z16.string(), z16.number(), z16.boolean()])).describe(
577
+ var userContextSchema = z15.object({
578
+ id: z15.string().min(1).max(200).optional().describe("Host's stable id for the user \u2014 informational context the agent/backend can key on (not auth)."),
579
+ email: z15.string().min(1).max(320).optional().describe("User email \u2014 surfaced to the agent for context (optional)."),
580
+ name: z15.string().min(1).max(200).optional().describe("Display name \u2014 shown in the Home greeting (`{name}`) and conversation transcripts (optional)."),
581
+ plan: z15.string().min(1).max(120).optional().describe("Subscription / pricing tier, e.g. `pro` (optional)."),
582
+ role: z15.string().min(1).max(120).optional().describe("The user's role on the host site, e.g. `admin` (optional)."),
583
+ phone: z15.string().min(1).max(40).optional().describe("Phone number (optional).")
584
+ }).catchall(z15.union([z15.string(), z15.number(), z15.boolean()])).describe(
597
585
  "Host-asserted end-user context (informational, untrusted \u2014 not authentication). Recognised `id` / `email` / `name` / `plan` / `role` / `phone` plus any extra custom scalar fields forwarded to the agent."
598
586
  ).meta({
599
587
  examples: [{ id: "u_123" }, { id: "u_123", email: "alex@acme.com", name: "Alex Lee", plan: "pro" }]
@@ -609,31 +597,31 @@ var PAGE_AREA_SUGGESTIONS = [
609
597
  "account",
610
598
  "blog"
611
599
  ];
612
- var pageContextSchema = z16.object({
613
- area: z16.string().min(1).max(64).optional().describe(`Host-defined surface the visitor is on. Free-form; suggested: ${PAGE_AREA_SUGGESTIONS.join(" | ")}.`),
614
- url: z16.string().min(1).max(2048).optional().describe("Full page URL. Auto-filled from the host page when omitted."),
615
- path: z16.string().min(1).max(2048).optional().describe("Page path, e.g. `/pricing/enterprise`."),
616
- title: z16.string().min(1).max(300).optional().describe("Human-readable page title.")
617
- }).catchall(z16.union([z16.string(), z16.number(), z16.boolean()])).describe(
600
+ var pageContextSchema = z15.object({
601
+ area: z15.string().min(1).max(64).optional().describe(`Host-defined surface the visitor is on. Free-form; suggested: ${PAGE_AREA_SUGGESTIONS.join(" | ")}.`),
602
+ url: z15.string().min(1).max(2048).optional().describe("Full page URL. Auto-filled from the host page when omitted."),
603
+ path: z15.string().min(1).max(2048).optional().describe("Page path, e.g. `/pricing/enterprise`."),
604
+ title: z15.string().min(1).max(300).optional().describe("Human-readable page title.")
605
+ }).catchall(z15.union([z15.string(), z15.number(), z15.boolean()])).describe(
618
606
  "Host-asserted page/visit context (informational, untrusted). Where the visitor is + the surface (`area`) they're using, plus any custom scalar fields, forwarded to the agent."
619
607
  ).meta({ examples: [{ area: "pricing", path: "/pricing" }, { area: "help-desk" }] });
620
- var connectionConfigSchema = z16.object({
621
- widgetId: z16.string().min(1).max(80).default("default").describe(
608
+ var connectionConfigSchema = z15.object({
609
+ widgetId: z15.string().min(1).max(80).default("default").describe(
622
610
  "Stable per-instance id used to namespace localStorage keys. Set this when mounting more than one widget on the same page so their conversation state doesn't collide."
623
611
  ),
624
- publicKey: z16.string().min(1).max(200).optional().describe(
612
+ publicKey: z15.string().min(1).max(200).optional().describe(
625
613
  "Workspace-scoped public key (`agent_pk_\u2026`) issued from the dashboard. Sent on every API call as the `x-public-key` header."
626
614
  ),
627
- aiAgentDeploymentId: z16.string().min(1).max(200).optional().describe(
615
+ aiAgentDeploymentId: z15.string().min(1).max(200).optional().describe(
628
616
  "Deployment UUID from the dashboard. Picks which agent / settings bundle answers this mount. Sent as `x-ai-agent-deployment-id`."
629
617
  ),
630
- baseUrl: z16.string().min(1).max(2048).optional().describe(
618
+ baseUrl: z15.string().min(1).max(2048).optional().describe(
631
619
  "Full backend origin (e.g. `https://help.ai/api`). Set this to point at your staging / self-hosted / custom backend. Default: the brand's `defaultBaseUrl` baked at build time."
632
620
  ),
633
621
  userContext: userContextSchema.optional(),
634
622
  pageContext: pageContextSchema.optional(),
635
623
  endpoints: endpointsSchema.optional(),
636
- debug: z16.union([z16.boolean(), z16.enum(["off", "error", "warn", "info", "debug", "trace"])]).optional().describe(
624
+ debug: z15.union([z15.boolean(), z15.enum(["off", "error", "warn", "info", "debug", "trace"])]).optional().describe(
637
625
  'Console log verbosity. `false` / `"off"` silences everything (default in production). `true` \u2192 `"debug"`. Levels `error` / `warn` / `info` / `debug` / `trace` gate output additively. Use `"trace"` to capture per-chunk SSE frames + every state transition. Also toggleable at runtime via `chat.setDebug(level)` or `?<brand>-debug=trace` in the page URL \u2014 the URL beats this option, this option beats the persisted `localStorage` value.'
638
626
  )
639
627
  }).loose().describe(
@@ -653,14 +641,13 @@ var connectionConfigSchema = z16.object({
653
641
  }
654
642
  ]
655
643
  });
656
- var widgetSettingsSchema = z16.object({
644
+ var widgetSettingsSchema = z15.object({
657
645
  presentation: presentationSchema.optional(),
658
646
  behavior: behaviorSchema.optional(),
659
647
  theme: themeFieldSchema.default("auto").describe("Theme preference (`auto` follows OS) or a tokens override object (`accent`, `radius`, `fontFamily`)."),
660
648
  launcher: launcherOptionsSchema.optional(),
661
649
  header: headerSchema.optional(),
662
650
  composer: composerOptionsSchema.optional(),
663
- welcome: welcomeOptionsSchema.optional(),
664
651
  feedback: feedbackSchema.optional(),
665
652
  i18n: i18nSchema.optional(),
666
653
  footer: footerSchema.optional(),
@@ -686,10 +673,10 @@ var widgetSettingsSchema = z16.object({
686
673
  });
687
674
  var widgetConfigSchema = connectionConfigSchema.extend({
688
675
  ...widgetSettingsSchema.shape,
689
- site: z16.unknown().optional().describe(
676
+ site: z15.unknown().optional().describe(
690
677
  'Site config \u2014 applies in `mode: "page"`. Comes from the start-conversation response, not user-edited.'
691
678
  ),
692
- blocks: z16.unknown().optional().describe('Blocks (nav + link cards) \u2014 applies in `mode: "page"`. Comes from the start-conversation response.')
679
+ blocks: z15.unknown().optional().describe('Blocks (nav + link cards) \u2014 applies in `mode: "page"`. Comes from the start-conversation response.')
693
680
  }).describe(
694
681
  "Full client widget config \u2014 connection (where + auth) + widget settings (look + behaviour) + page-mode extras. This is what the runtime parses on `mount()` / `init()`. Mode-specific constraints (e.g. `position` only meaningful in `floating`) are NOT enforced here \u2014 the runtime silently ignores irrelevant fields rather than rejecting them so the same object can flow across mode changes."
695
682
  ).meta({
@@ -712,49 +699,49 @@ var widgetSettingsPartialSchema = widgetSettingsSchema.partial();
712
699
  var connectionConfigPartialSchema = connectionConfigSchema.partial();
713
700
 
714
701
  // src/schema/deployment.ts
715
- import { z as z17 } from "zod";
702
+ import { z as z16 } from "zod";
716
703
  var serverConfigSchema = widgetSettingsSchema.partial();
717
- var siteConfigSchema = z17.object({
718
- title: z17.string().min(1).max(120).optional().describe("Brand / site name. Used as the logo's alt-text fallback."),
704
+ var siteConfigSchema = z16.object({
705
+ title: z16.string().min(1).max(120).optional().describe("Brand / site name. Used as the logo's alt-text fallback."),
719
706
  logo: assetSchema.optional().describe("Brand logo shown at the top of the page-mode sidebar."),
720
707
  logoDark: assetSchema.optional().describe(
721
708
  "Optional dark-theme logo variant. Falls back to `logo` when the active theme is light or `logoDark` is unset."
722
709
  )
723
710
  }).loose();
724
- var blocksConfigSchema = z17.object({
725
- navigation: z17.array(linkSchema).max(100).optional().describe("Sidebar navigation links (vertical list, primary nav)."),
726
- linkCards: z17.array(linkSchema).max(100).optional().describe("Sidebar link cards (richer entries with optional `description`).")
711
+ var blocksConfigSchema = z16.object({
712
+ navigation: z16.array(linkSchema).max(100).optional().describe("Sidebar navigation links (vertical list, primary nav)."),
713
+ linkCards: z16.array(linkSchema).max(100).optional().describe("Sidebar link cards (richer entries with optional `description`).")
727
714
  }).loose();
728
- var handshakeWelcomeMessageSchema = z17.object({
729
- id: z17.string(),
730
- role: z17.enum(["assistant", "system"]),
731
- text: z17.string()
715
+ var handshakeWelcomeMessageSchema = z16.object({
716
+ id: z16.string(),
717
+ role: z16.enum(["assistant", "system"]),
718
+ text: z16.string()
732
719
  }).loose();
733
- var handshakeWelcomeSuggestionSchema = z17.object({
734
- id: z17.string(),
735
- label: z17.string(),
736
- text: z17.string().optional()
720
+ var handshakeWelcomeSuggestionSchema = z16.object({
721
+ id: z16.string(),
722
+ label: z16.string(),
723
+ text: z16.string().optional()
737
724
  }).loose();
738
- var rebindReasonSchema = z17.enum(["conflict", "expired", "invalid"]);
739
- var startConversationResponseSchema = z17.object({
740
- deployment: z17.object({
741
- id: z17.string(),
742
- name: z17.string(),
725
+ var rebindReasonSchema = z16.enum(["conflict", "expired", "invalid"]);
726
+ var startConversationResponseSchema = z16.object({
727
+ deployment: z16.object({
728
+ id: z16.string(),
729
+ name: z16.string(),
743
730
  // Page URL identifier — present on every deployment; unique per host.
744
731
  // Used to mount page deployments via `?slug=…`.
745
- slug: z17.string().optional(),
746
- publicKey: z17.string().optional()
732
+ slug: z16.string().optional(),
733
+ publicKey: z16.string().optional()
747
734
  // Deliberately no `type` / `channel` here. Deployment-level
748
735
  // taxonomy is a backend categorization concern — the widget's
749
736
  // rendering choice flows from `widget.presentation.mode`, not
750
737
  // the deployment record's category. `.loose()` lets any such
751
738
  // backend field pass through without typing.
752
739
  }).loose(),
753
- agent: z17.object({
754
- id: z17.string(),
755
- name: z17.string(),
756
- title: z17.string().optional(),
757
- status: z17.enum(["online", "away", "offline"]).optional()
740
+ agent: z16.object({
741
+ id: z16.string(),
742
+ name: z16.string(),
743
+ title: z16.string().optional(),
744
+ status: z16.enum(["online", "away", "offline"]).optional()
758
745
  }).loose(),
759
746
  /**
760
747
  * Deployment-wide widget configuration the dashboard admin saved
@@ -764,26 +751,26 @@ var startConversationResponseSchema = z17.object({
764
751
  config: serverConfigSchema.optional(),
765
752
  site: siteConfigSchema.optional(),
766
753
  blocks: blocksConfigSchema.optional(),
767
- welcome: z17.object({
768
- messages: z17.array(handshakeWelcomeMessageSchema).optional(),
769
- suggestions: z17.array(handshakeWelcomeSuggestionSchema).optional()
754
+ welcome: z16.object({
755
+ messages: z16.array(handshakeWelcomeMessageSchema).optional(),
756
+ suggestions: z16.array(handshakeWelcomeSuggestionSchema).optional()
770
757
  }).loose().optional(),
771
- visitorId: z17.string(),
772
- conversationId: z17.string(),
773
- canContinue: z17.boolean(),
774
- messages: z17.array(z17.unknown()),
758
+ visitorId: z16.string(),
759
+ conversationId: z16.string(),
760
+ canContinue: z16.boolean(),
761
+ messages: z16.array(z16.unknown()),
775
762
  /**
776
763
  * Form submissions recorded for this conversation — echoed like
777
764
  * `messages` so the widget reconstructs the collapsed "form submitted"
778
765
  * timeline markers on resume. `createdAt` is ISO-8601 (a serialized
779
766
  * Mongo ISODate — same format as message `createdAt`).
780
767
  */
781
- formSubmissions: z17.array(
782
- z17.object({
783
- formId: z17.string(),
784
- trigger: z17.string(),
785
- skipped: z17.boolean().optional(),
786
- createdAt: z17.iso.datetime().optional()
768
+ formSubmissions: z16.array(
769
+ z16.object({
770
+ formId: z16.string(),
771
+ trigger: z16.string(),
772
+ skipped: z16.boolean().optional(),
773
+ createdAt: z16.iso.datetime().optional()
787
774
  }).loose()
788
775
  ).optional(),
789
776
  /**
@@ -792,11 +779,11 @@ var startConversationResponseSchema = z17.object({
792
779
  * what THIS visitor toggled inside the widget, not the
793
780
  * deployment's admin-set defaults.
794
781
  */
795
- userPrefs: z17.record(z17.string(), z17.unknown()).optional(),
782
+ userPrefs: z16.record(z16.string(), z16.unknown()).optional(),
796
783
  // Present only when the server rotated the request `visitorId` /
797
784
  // `conversationId`. Purely advisory — client must adopt the response ids
798
785
  // verbatim regardless of whether this block is present.
799
- rebind: z17.object({
786
+ rebind: z16.object({
800
787
  visitorId: rebindReasonSchema.optional(),
801
788
  conversationId: rebindReasonSchema.optional()
802
789
  }).loose().optional()
@@ -806,7 +793,6 @@ var startConversationResponseSchema = z17.object({
806
793
  import "zod";
807
794
  var COMMON_SECTIONS = [
808
795
  "theme",
809
- "welcome",
810
796
  "header",
811
797
  "composer",
812
798
  "footer",
@@ -833,15 +819,15 @@ function widgetSettingsSchemaForMode(mode) {
833
819
  var ALL_MODES = ["floating", "inline", "standalone", "page", "modal", "drawer"];
834
820
 
835
821
  // src/schema/json-schema.ts
836
- import { z as z19 } from "zod";
822
+ import { z as z18 } from "zod";
837
823
  function emitJsonSchema() {
838
824
  return {
839
825
  $schema: "https://json-schema.org/draft/2020-12/schema",
840
826
  title: "@helpai/elements config",
841
827
  description: "Canonical config schemas for the embeddable AI agent elements widget.",
842
828
  definitions: {
843
- WidgetConfig: z19.toJSONSchema(widgetConfigSchema),
844
- StartConversationResponse: z19.toJSONSchema(startConversationResponseSchema)
829
+ WidgetConfig: z18.toJSONSchema(widgetConfigSchema),
830
+ StartConversationResponse: z18.toJSONSchema(startConversationResponseSchema)
845
831
  }
846
832
  };
847
833
  }
@@ -912,8 +898,6 @@ export {
912
898
  userContextSchema,
913
899
  uuid7Schema,
914
900
  voiceModeSchema,
915
- welcomeAnimationSchema,
916
- welcomeOptionsSchema,
917
901
  widgetConfigPartialSchema,
918
902
  widgetConfigSchema,
919
903
  widgetSettingsPartialSchema,
package/style.css CHANGED
@@ -1,4 +1,4 @@
1
- :host{--helpai-accent-user: #5B5BD6;--helpai-accent: var(--helpai-accent-user);--helpai-accent-text: #FFFFFF;--helpai-radius: 12px;--helpai-radius-sm: 8px;--helpai-radius-md: 10px;--helpai-radius-lg: 16px;--helpai-font: Inter, system-ui, -apple-system, 'Segoe UI', sans-serif;--helpai-font-display: var(--helpai-font);--helpai-font-mono: ui-monospace, "SF Mono", Menlo, Consolas, monospace;--helpai-bg: oklch(1 0 0);--helpai-bg-elevated: oklch(.9789 .0029 278.3);--helpai-surface: var(--helpai-bg-elevated);--helpai-muted: var(--helpai-fg-muted);--helpai-hover: oklch(.1686 .011 278.3 / .06);--helpai-fg: oklch(.1686 .011 278.3);--helpai-fg-muted: oklch(.4932 .0301 278.3);--helpai-border: oklch(.9312 .0084 278.3);--helpai-border-strong: oklch(.8757 .0131 278.3);--helpai-bubble-user: var(--helpai-accent);--helpai-bubble-user-text: var(--helpai-accent-text);--helpai-bubble-assistant: oklch(.9638 .0058 278.3);--helpai-bubble-assistant-text: var(--helpai-fg);--helpai-on-accent: var(--helpai-accent-text);--helpai-success: oklch(.6456 .1654 151.53);--helpai-warning: oklch(.7135 .1494 74.05);--helpai-danger: oklch(.5966 .1818 24.51);--helpai-danger-text: oklch(.5054 .1905 27.52);--helpai-danger-bg: oklch(.5966 .1818 24.51 / .1);--helpai-neutral: oklch(.7137 .0192 278.3);--helpai-focus: var(--helpai-accent);--helpai-shadow-panel: 0 8px 24px -8px rgba(13, 15, 20, .18), 0 24px 64px -24px rgba(13, 15, 20, .24);--helpai-shadow-card: 0 1px 2px rgba(13, 15, 20, .06), 0 4px 12px -6px rgba(13, 15, 20, .12);--helpai-backdrop: oklch(.1686 .011 278.3 / .55);--helpai-shadow-fab: 0 6px 16px -4px color-mix(in oklch, var(--helpai-accent) 45%, transparent), 0 12px 32px -12px rgba(13, 15, 20, .25);--helpai-z-fab: 2147483600;--helpai-z-panel: 2147483601;--helpai-panel-w: 380px;--helpai-panel-h: 600px;--helpai-fab-size: 56px;--helpai-space-1: 4px;--helpai-space-2: 8px;--helpai-space-3: 12px;--helpai-space-4: 16px;--helpai-space-5: 20px;--helpai-space-6: 24px;--helpai-space-8: 32px;--helpai-text-scale: 1;--helpai-text-xs: calc(12px * var(--helpai-text-scale));--helpai-text-sm: calc(13px * var(--helpai-text-scale));--helpai-text-base: calc(15px * var(--helpai-text-scale));--helpai-text-md: calc(16px * var(--helpai-text-scale));--helpai-text-lg: calc(18px * var(--helpai-text-scale));--helpai-text-xl: calc(22px * var(--helpai-text-scale));--helpai-text-2xl: calc(30px * var(--helpai-text-scale))}:host([data-text-size="small"]){--helpai-text-scale: .9}:host([data-text-size="large"]){--helpai-text-scale: 1.15}:host{--helpai-ease: cubic-bezier(.2, .7, .2, 1);--helpai-ease-out: cubic-bezier(.2, .7, .2, 1);--helpai-ease-in: cubic-bezier(.4, 0, 1, 1);--helpai-ease-in-out: cubic-bezier(.65, 0, .35, 1);--helpai-dur-quick: .12s;--helpai-dur-base: .22s;--helpai-dur-slow: .32s;font-family:var(--helpai-font);color:var(--helpai-fg);color-scheme:light;--helpai-color-scheme: light}:host([data-theme="dark"]){--helpai-bg: oklch(.1783 .0128 278.3);--helpai-bg-elevated: oklch(.2232 .0182 278.3);--helpai-fg: oklch(.9368 .01 278.3);--helpai-fg-muted: oklch(.7048 .0296 278.3);--helpai-border: oklch(.2752 .0266 278.3);--helpai-border-strong: oklch(.335 .0291 278.3);--helpai-hover: oklch(.9368 .01 278.3 / .08);--helpai-bubble-assistant: oklch(.2474 .0311 278.3);--helpai-bubble-assistant-text: var(--helpai-fg);--helpai-danger-text: oklch(.8077 .1035 19.57);--helpai-danger-bg: oklch(.5966 .1818 24.51 / .18);--helpai-shadow-panel: 0 8px 24px -8px rgba(0, 0, 0, .6), 0 24px 64px -24px rgba(0, 0, 0, .7);--helpai-shadow-card: 0 1px 2px rgba(0, 0, 0, .4), 0 4px 12px -6px rgba(0, 0, 0, .5);--helpai-backdrop: rgba(0, 0, 0, .65);color-scheme:dark;--helpai-color-scheme: dark}@media(prefers-color-scheme:dark){:host([data-theme="auto"]){--helpai-bg: oklch(.1783 .0128 278.3);--helpai-bg-elevated: oklch(.2232 .0182 278.3);--helpai-fg: oklch(.9368 .01 278.3);--helpai-fg-muted: oklch(.7048 .0296 278.3);--helpai-border: oklch(.2752 .0266 278.3);--helpai-border-strong: oklch(.335 .0291 278.3);--helpai-hover: oklch(.9368 .01 278.3 / .08);--helpai-bubble-assistant: oklch(.2474 .0311 278.3);--helpai-bubble-assistant-text: var(--helpai-fg);--helpai-shadow-panel: 0 8px 24px -8px rgba(0, 0, 0, .6), 0 24px 64px -24px rgba(0, 0, 0, .7);color-scheme:dark;--helpai-color-scheme: dark}}@supports (color: oklch(from red l c h)){:host{--helpai-accent: oklch(from var(--helpai-accent-user) clamp(.3, l, .62) c h);--helpai-accent-text: oklch(from var(--helpai-accent) clamp(0, (l / .623 - 1) * -infinity, 1) 0 h)}:host([data-theme="dark"]){--helpai-accent: oklch(from var(--helpai-accent-user) clamp(.65, l, .85) c h)}@media(prefers-color-scheme:dark){:host([data-theme="auto"]){--helpai-accent: oklch(from var(--helpai-accent-user) clamp(.65, l, .85) c h)}}}@media(prefers-reduced-motion:reduce){:host{--helpai-dur-quick: 1ms;--helpai-dur-base: 1ms;--helpai-dur-slow: 1ms}}
1
+ :host{--helpai-accent-user: #5B5BD6;--helpai-accent: var(--helpai-accent-user);--helpai-accent-text-user: #FFFFFF;--helpai-accent-text: var(--helpai-accent-text-user);--helpai-radius: 12px;--helpai-radius-sm: 8px;--helpai-radius-md: 10px;--helpai-radius-lg: 16px;--helpai-font: Inter, system-ui, -apple-system, 'Segoe UI', sans-serif;--helpai-font-display: var(--helpai-font);--helpai-font-mono: ui-monospace, "SF Mono", Menlo, Consolas, monospace;--helpai-bg: oklch(1 0 0);--helpai-bg-elevated: oklch(.9789 .0029 278.3);--helpai-surface: var(--helpai-bg-elevated);--helpai-muted: var(--helpai-fg-muted);--helpai-hover: oklch(.1686 .011 278.3 / .06);--helpai-fg: oklch(.1686 .011 278.3);--helpai-fg-muted: oklch(.4932 .0301 278.3);--helpai-border: oklch(.9312 .0084 278.3);--helpai-border-strong: oklch(.8757 .0131 278.3);--helpai-bubble-user: var(--helpai-accent);--helpai-bubble-user-text: var(--helpai-accent-text);--helpai-bubble-assistant: oklch(.9638 .0058 278.3);--helpai-bubble-assistant-text: var(--helpai-fg);--helpai-on-accent: var(--helpai-accent-text);--helpai-success: oklch(.6456 .1654 151.53);--helpai-warning: oklch(.7135 .1494 74.05);--helpai-danger: oklch(.5966 .1818 24.51);--helpai-danger-text: oklch(.5054 .1905 27.52);--helpai-danger-bg: oklch(.5966 .1818 24.51 / .1);--helpai-neutral: oklch(.7137 .0192 278.3);--helpai-focus: var(--helpai-accent);--helpai-shadow-panel: 0 8px 24px -8px rgba(13, 15, 20, .18), 0 24px 64px -24px rgba(13, 15, 20, .24);--helpai-shadow-card: 0 1px 2px rgba(13, 15, 20, .06), 0 4px 12px -6px rgba(13, 15, 20, .12);--helpai-backdrop: oklch(.1686 .011 278.3 / .55);--helpai-shadow-fab: 0 6px 16px -4px color-mix(in oklch, var(--helpai-accent) 45%, transparent), 0 12px 32px -12px rgba(13, 15, 20, .25);--helpai-z-fab: 2147483600;--helpai-z-panel: 2147483601;--helpai-panel-w: 380px;--helpai-panel-h: 600px;--helpai-fab-size: 56px;--helpai-space-1: 4px;--helpai-space-2: 8px;--helpai-space-3: 12px;--helpai-space-4: 16px;--helpai-space-5: 20px;--helpai-space-6: 24px;--helpai-space-8: 32px;--helpai-text-scale: 1;--helpai-text-xs: calc(12px * var(--helpai-text-scale));--helpai-text-sm: calc(13px * var(--helpai-text-scale));--helpai-text-base: calc(15px * var(--helpai-text-scale));--helpai-text-md: calc(16px * var(--helpai-text-scale));--helpai-text-lg: calc(18px * var(--helpai-text-scale));--helpai-text-xl: calc(22px * var(--helpai-text-scale));--helpai-text-2xl: calc(30px * var(--helpai-text-scale))}:host([data-text-size="small"]){--helpai-text-scale: .9}:host([data-text-size="large"]){--helpai-text-scale: 1.15}:host{--helpai-ease: cubic-bezier(.2, .7, .2, 1);--helpai-ease-out: cubic-bezier(.2, .7, .2, 1);--helpai-ease-in: cubic-bezier(.4, 0, 1, 1);--helpai-ease-in-out: cubic-bezier(.65, 0, .35, 1);--helpai-dur-quick: .12s;--helpai-dur-base: .22s;--helpai-dur-slow: .32s;font-family:var(--helpai-font);color:var(--helpai-fg);color-scheme:light;--helpai-color-scheme: light}:host([data-theme="dark"]){--helpai-bg: oklch(.1783 .0128 278.3);--helpai-bg-elevated: oklch(.2232 .0182 278.3);--helpai-fg: oklch(.9368 .01 278.3);--helpai-fg-muted: oklch(.7048 .0296 278.3);--helpai-border: oklch(.2752 .0266 278.3);--helpai-border-strong: oklch(.335 .0291 278.3);--helpai-hover: oklch(.9368 .01 278.3 / .08);--helpai-bubble-assistant: oklch(.2474 .0311 278.3);--helpai-bubble-assistant-text: var(--helpai-fg);--helpai-danger-text: oklch(.8077 .1035 19.57);--helpai-danger-bg: oklch(.5966 .1818 24.51 / .18);--helpai-shadow-panel: 0 8px 24px -8px rgba(0, 0, 0, .6), 0 24px 64px -24px rgba(0, 0, 0, .7);--helpai-shadow-card: 0 1px 2px rgba(0, 0, 0, .4), 0 4px 12px -6px rgba(0, 0, 0, .5);--helpai-backdrop: rgba(0, 0, 0, .65);color-scheme:dark;--helpai-color-scheme: dark}@media(prefers-color-scheme:dark){:host([data-theme="auto"]){--helpai-bg: oklch(.1783 .0128 278.3);--helpai-bg-elevated: oklch(.2232 .0182 278.3);--helpai-fg: oklch(.9368 .01 278.3);--helpai-fg-muted: oklch(.7048 .0296 278.3);--helpai-border: oklch(.2752 .0266 278.3);--helpai-border-strong: oklch(.335 .0291 278.3);--helpai-hover: oklch(.9368 .01 278.3 / .08);--helpai-bubble-assistant: oklch(.2474 .0311 278.3);--helpai-bubble-assistant-text: var(--helpai-fg);--helpai-shadow-panel: 0 8px 24px -8px rgba(0, 0, 0, .6), 0 24px 64px -24px rgba(0, 0, 0, .7);color-scheme:dark;--helpai-color-scheme: dark}}@supports (color: oklch(from red l c h)){:host{--helpai-accent: oklch(from var(--helpai-accent-user) clamp(.3, l, .62) c h);--helpai-accent-text: oklch(from var(--helpai-accent) clamp(0, (l / .623 - 1) * -infinity, 1) 0 h)}:host([data-theme="dark"]){--helpai-accent: oklch(from var(--helpai-accent-user) clamp(.65, l, .85) c h)}@media(prefers-color-scheme:dark){:host([data-theme="auto"]){--helpai-accent: oklch(from var(--helpai-accent-user) clamp(.65, l, .85) c h)}}}@media(prefers-reduced-motion:reduce){:host{--helpai-dur-quick: 1ms;--helpai-dur-base: 1ms;--helpai-dur-slow: 1ms}}
2
2
 
3
3
  *,*:before,*:after{box-sizing:border-box;margin:0;padding:0;border:0}button{font:inherit;color:inherit;background:none;cursor:pointer;-webkit-appearance:none;appearance:none;line-height:1}button:focus-visible,[tabindex]:focus-visible,textarea:focus-visible,input:focus-visible{outline:2px solid var(--helpai-accent);outline-offset:2px}textarea,input{font:inherit;color:inherit;background:none;border:0;outline:0;resize:none}a{color:var(--helpai-accent);text-decoration:underline;text-underline-offset:2px}img,svg{display:block;max-width:100%}ul,ol{list-style:none}.helpai-app{display:block;width:100%;height:100%;font-family:var(--helpai-font);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-feature-settings:"cv11","ss01","ss03"}.helpai-sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}
4
4