@runtypelabs/persona 4.14.0 → 4.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (119) hide show
  1. package/README.md +4 -4
  2. package/dist/animations/glyph-cycle.d.cts +1 -1
  3. package/dist/animations/glyph-cycle.d.ts +1 -1
  4. package/dist/animations/{types-DveIaNx6.d.cts → types-BpWGm7_6.d.cts} +17 -0
  5. package/dist/animations/{types-DveIaNx6.d.ts → types-BpWGm7_6.d.ts} +17 -0
  6. package/dist/animations/wipe.d.cts +1 -1
  7. package/dist/animations/wipe.d.ts +1 -1
  8. package/dist/chunk-QJ4LV2KW.js +1 -0
  9. package/dist/codegen.cjs +12 -11
  10. package/dist/codegen.js +14 -13
  11. package/dist/{context-mentions-ONG7A7M6.js → context-mentions-BTSTIBFC.js} +1 -1
  12. package/dist/context-mentions.cjs +11 -8
  13. package/dist/context-mentions.d.cts +520 -21
  14. package/dist/context-mentions.d.ts +520 -21
  15. package/dist/context-mentions.js +11 -8
  16. package/dist/index.cjs +69 -68
  17. package/dist/index.cjs.map +1 -1
  18. package/dist/index.d.cts +595 -46
  19. package/dist/index.d.ts +595 -46
  20. package/dist/index.global.js +60 -57
  21. package/dist/index.global.js.map +1 -1
  22. package/dist/index.js +69 -68
  23. package/dist/index.js.map +1 -1
  24. package/dist/launcher.global.js +5 -2
  25. package/dist/launcher.global.js.map +1 -1
  26. package/dist/smart-dom-reader.d.cts +520 -21
  27. package/dist/smart-dom-reader.d.ts +520 -21
  28. package/dist/testing.cjs +3 -3
  29. package/dist/testing.d.cts +7 -0
  30. package/dist/testing.d.ts +7 -0
  31. package/dist/testing.js +3 -3
  32. package/dist/theme-editor-preview.cjs +67 -67
  33. package/dist/theme-editor-preview.d.cts +534 -22
  34. package/dist/theme-editor-preview.d.ts +534 -22
  35. package/dist/theme-editor-preview.js +57 -57
  36. package/dist/theme-editor.cjs +10 -10
  37. package/dist/theme-editor.d.cts +521 -23
  38. package/dist/theme-editor.d.ts +521 -23
  39. package/dist/theme-editor.js +10 -10
  40. package/dist/theme-reference.cjs +1 -1
  41. package/dist/theme-reference.d.cts +104 -3
  42. package/dist/theme-reference.d.ts +104 -3
  43. package/dist/theme-reference.js +1 -1
  44. package/dist/widget.css +1 -1
  45. package/package.json +1 -1
  46. package/src/ask-user-question-tool.ts +10 -7
  47. package/src/components/artifact-pane.test.ts +27 -0
  48. package/src/components/artifact-pane.ts +7 -3
  49. package/src/components/artifact-preview.ts +1 -1
  50. package/src/components/composer-parts.test.ts +103 -4
  51. package/src/components/composer-parts.ts +53 -15
  52. package/src/components/header-builder.ts +27 -2
  53. package/src/components/header-layouts.test.ts +56 -0
  54. package/src/components/header-layouts.ts +29 -9
  55. package/src/components/launcher-surface.test.ts +403 -0
  56. package/src/components/launcher.ts +297 -2
  57. package/src/components/messages.ts +5 -2
  58. package/src/components/panel.ts +92 -71
  59. package/src/components/pill-composer-builder.test.ts +18 -0
  60. package/src/components/suggestions.test.ts +273 -0
  61. package/src/components/suggestions.ts +528 -86
  62. package/src/components/welcome.test.ts +121 -0
  63. package/src/components/welcome.ts +305 -0
  64. package/src/components/widget-view.test.ts +5 -3
  65. package/src/components/widget-view.ts +18 -7
  66. package/src/defaults.ts +7 -5
  67. package/src/generated/runtype-openapi-contract.ts +17 -0
  68. package/src/index-core.ts +29 -2
  69. package/src/launcher-global.ts +11 -8
  70. package/src/plugins/types.ts +136 -3
  71. package/src/presets.ts +3 -3
  72. package/src/session.ts +10 -8
  73. package/src/styles/widget-styles.test.ts +382 -0
  74. package/src/styles/widget.css +778 -4
  75. package/src/suggest-replies-tool.test.ts +233 -2
  76. package/src/suggest-replies-tool.ts +115 -39
  77. package/src/testing/mock-stream.test.ts +19 -0
  78. package/src/testing/mock-stream.ts +20 -0
  79. package/src/theme-editor/preview-utils.test.ts +34 -0
  80. package/src/theme-editor/preview-utils.ts +77 -2
  81. package/src/theme-editor/sections.test.ts +33 -0
  82. package/src/theme-editor/sections.ts +83 -6
  83. package/src/theme-reference.ts +34 -5
  84. package/src/types/theme.ts +72 -3
  85. package/src/types.ts +312 -18
  86. package/src/ui.body-top-slot.test.ts +95 -0
  87. package/src/ui.content-width.test.ts +91 -0
  88. package/src/ui.detached-panel.test.ts +1 -1
  89. package/src/ui.docked.test.ts +7 -4
  90. package/src/ui.launcher-teaser.test.ts +162 -0
  91. package/src/ui.rebuild-composer.test.ts +491 -0
  92. package/src/ui.render-welcome.test.ts +505 -0
  93. package/src/ui.scroll-additive.test.ts +91 -21
  94. package/src/ui.scroll.test.ts +302 -14
  95. package/src/ui.suggest-replies.test.ts +1112 -1
  96. package/src/ui.ts +1008 -149
  97. package/src/ui.welcome.test.ts +504 -0
  98. package/src/utils/artifact-file.test.ts +1 -1
  99. package/src/utils/artifact-gate.test.ts +27 -0
  100. package/src/utils/artifact-gate.ts +9 -0
  101. package/src/utils/attachment-manager.test.ts +37 -0
  102. package/src/utils/attachment-manager.ts +15 -0
  103. package/src/utils/auto-follow.test.ts +23 -0
  104. package/src/utils/auto-follow.ts +11 -1
  105. package/src/utils/code-generators.test.ts +40 -0
  106. package/src/utils/code-generators.ts +22 -0
  107. package/src/utils/config-merge.test.ts +24 -0
  108. package/src/utils/config-merge.ts +2 -0
  109. package/src/utils/content-width.test.ts +37 -0
  110. package/src/utils/content-width.ts +17 -0
  111. package/src/utils/icons.test.ts +26 -0
  112. package/src/utils/icons.ts +8 -0
  113. package/src/utils/plugin-storage.test.ts +94 -0
  114. package/src/utils/plugin-storage.ts +98 -0
  115. package/src/utils/theme.test.ts +216 -0
  116. package/src/utils/tokens.ts +113 -3
  117. package/src/welcome.test.ts +213 -0
  118. package/src/welcome.ts +130 -0
  119. package/dist/chunk-MMUPR2JW.js +0 -1
@@ -4,6 +4,10 @@
4
4
  font-size: var(--persona-font-size, 1rem);
5
5
  font-weight: var(--persona-font-weight, 400);
6
6
  line-height: var(--persona-line-height, 1.5);
7
+
8
+ /* Column widths plugin content can consume; --persona-content-max-width is
9
+ re-set inline from layout.contentMaxWidth (default 768px). */
10
+ --persona-welcome-max-width: 640px;
7
11
 
8
12
  /* Theme-aware markdown variables - inherit from theme colors set by JavaScript */
9
13
  --persona-md-code-block-bg: var(--persona-container, #f3f4f6);
@@ -236,6 +240,748 @@
236
240
  border-radius: var(--persona-button-radius);
237
241
  }
238
242
 
243
+ /* Launcher surface + teaser --------------------------------------------- */
244
+
245
+ /* Without a teaser the wrapper generates no box, so the launcher button keeps
246
+ its own fixed placement exactly as it did before the wrapper existed. */
247
+ .persona-launcher-surface {
248
+ display: contents;
249
+ }
250
+
251
+ .persona-launcher-surface[data-teaser] {
252
+ display: flex;
253
+ position: fixed;
254
+ flex-direction: column;
255
+ align-items: flex-end;
256
+ gap: 10px;
257
+ }
258
+
259
+ .persona-launcher-surface[data-teaser^="top"] {
260
+ flex-direction: column-reverse;
261
+ }
262
+
263
+ .persona-launcher-surface[data-teaser$="left"] {
264
+ align-items: flex-start;
265
+ }
266
+
267
+ .persona-launcher-teaser {
268
+ display: flex;
269
+ align-items: flex-start;
270
+ gap: 2px;
271
+ max-width: min(260px, calc(100vw - 48px));
272
+ padding: 2px;
273
+ border: 1px solid var(--persona-border, #e5e7eb);
274
+ border-radius: var(--persona-radius-lg, 1rem);
275
+ background-color: var(--persona-surface, #ffffff);
276
+ box-shadow: var(
277
+ --persona-launcher-shadow,
278
+ 0 10px 15px -3px rgba(0, 0, 0, 0.1),
279
+ 0 4px 6px -4px rgba(0, 0, 0, 0.1)
280
+ );
281
+ }
282
+
283
+ .persona-launcher-teaser[hidden] {
284
+ display: none;
285
+ }
286
+
287
+ .persona-launcher-teaser-text {
288
+ flex: 1 1 auto;
289
+ min-width: 0;
290
+ padding: 8px 10px;
291
+ border: 0;
292
+ border-radius: inherit;
293
+ background: transparent;
294
+ color: var(--persona-text, #111827);
295
+ font: inherit;
296
+ font-size: 0.875rem;
297
+ line-height: 1.4;
298
+ text-align: left;
299
+ cursor: pointer;
300
+ }
301
+
302
+ .persona-launcher-teaser-dismiss {
303
+ flex: 0 0 auto;
304
+ display: grid;
305
+ place-items: center;
306
+ width: 22px;
307
+ height: 22px;
308
+ margin-top: 4px;
309
+ padding: 0;
310
+ border: 0;
311
+ border-radius: var(--persona-launcher-radius, 9999px);
312
+ background: transparent;
313
+ color: var(--persona-muted, #6b7280);
314
+ font-size: 0.875rem;
315
+ line-height: 1;
316
+ cursor: pointer;
317
+ }
318
+
319
+ .persona-launcher-teaser-dismiss:hover {
320
+ background-color: var(--persona-border, #e5e7eb);
321
+ }
322
+
323
+ /* display: grid above beats the UA [hidden] rule; dismissible: false relies on this. */
324
+ .persona-launcher-teaser-dismiss[hidden] {
325
+ display: none;
326
+ }
327
+
328
+ /* An empty transcript still counts as a flex child, so the body's gap
329
+ inserts phantom space below the welcome and fakes scrollable height. */
330
+ .persona-widget-messages:empty {
331
+ display: none;
332
+ }
333
+
334
+ /* Scrollbars ------------------------------------------------------------- */
335
+
336
+ /* One appearance for every scroller in the widget: thin, themed thumb, bare
337
+ track. Standard properties only: mixing ::-webkit-scrollbar styling with
338
+ them makes Chromium drop the pseudo-element rules, so webkit selectors are
339
+ reserved for the hidden states below, where both mechanisms agree.
340
+ scrollbar-color inherits from the root; scrollbar-width does not, hence
341
+ the descendant rule. */
342
+ [data-persona-root] {
343
+ scrollbar-color: var(
344
+ --persona-scrollbar-thumb,
345
+ var(--persona-border, #e5e7eb)
346
+ )
347
+ var(--persona-scrollbar-track, transparent);
348
+ }
349
+ [data-persona-root],
350
+ [data-persona-root] * {
351
+ scrollbar-width: thin;
352
+ }
353
+
354
+ /* "on-scroll" policy (the default): bars hide at rest. ui.ts stamps the
355
+ resolved policy on the root and flips data-persona-scrollbar-visible on
356
+ the transcript while the reader is scrolling or away from the resting
357
+ position. The reserved gutter keeps classic scrollbars (Windows,
358
+ always-show macOS) from reflowing the transcript on toggle. */
359
+ [data-persona-scrollbar="on-scroll"] .persona-widget-body {
360
+ scrollbar-gutter: stable;
361
+ }
362
+ [data-persona-scrollbar="on-scroll"]
363
+ .persona-widget-body:not([data-persona-scrollbar-visible]),
364
+ [data-persona-scrollbar="hidden"] .persona-widget-body {
365
+ scrollbar-width: none;
366
+ }
367
+ [data-persona-scrollbar="on-scroll"]
368
+ .persona-widget-body:not([data-persona-scrollbar-visible])::-webkit-scrollbar,
369
+ [data-persona-scrollbar="hidden"] .persona-widget-body::-webkit-scrollbar {
370
+ display: none;
371
+ }
372
+
373
+ /* Inner scrollers under the same policy: hidden at rest, hover reveals for
374
+ pointer users. Edge fades stay the primary overflow affordance there, and
375
+ morph re-renders make per-element JS wiring fragile, so hover is the whole
376
+ reveal story for these surfaces. */
377
+ [data-persona-scrollbar="on-scroll"] .persona-artifact-list:not(:hover),
378
+ [data-persona-scrollbar="on-scroll"]
379
+ .persona-suggestions[data-overflow="scroll"]:not(:hover),
380
+ [data-persona-scrollbar="hidden"] .persona-artifact-list,
381
+ [data-persona-scrollbar="hidden"] .persona-suggestions[data-overflow="scroll"] {
382
+ scrollbar-width: none;
383
+ }
384
+ [data-persona-scrollbar="on-scroll"]
385
+ .persona-artifact-list:not(:hover)::-webkit-scrollbar,
386
+ [data-persona-scrollbar="on-scroll"]
387
+ .persona-suggestions[data-overflow="scroll"]:not(:hover)::-webkit-scrollbar,
388
+ [data-persona-scrollbar="hidden"] .persona-artifact-list::-webkit-scrollbar,
389
+ [data-persona-scrollbar="hidden"]
390
+ .persona-suggestions[data-overflow="scroll"]::-webkit-scrollbar {
391
+ display: none;
392
+ }
393
+
394
+ /* Suggestions ----------------------------------------------------------- */
395
+
396
+ .persona-suggestions {
397
+ --persona-suggestion-icon-size: var(
398
+ --persona-components-suggestion-chip-iconSize,
399
+ 16px
400
+ );
401
+ display: flex;
402
+ align-items: stretch;
403
+ flex-shrink: 0;
404
+ gap: 8px;
405
+ min-width: 0;
406
+ }
407
+
408
+ .persona-suggestions[hidden] {
409
+ display: none !important;
410
+ }
411
+
412
+ /* `itemGap` is the space between items; the variant-less 8px above stays the
413
+ fallback for containers rendered before a variant is assigned. */
414
+ .persona-suggestions[data-variant="chip"] {
415
+ gap: var(--persona-components-suggestion-chip-itemGap, 8px);
416
+ }
417
+
418
+ .persona-suggestions[data-variant="card"] {
419
+ gap: var(--persona-components-suggestion-card-itemGap, 8px);
420
+ }
421
+
422
+ .persona-suggestions[data-variant="list"] {
423
+ gap: var(--persona-components-suggestion-list-itemGap, 8px);
424
+ }
425
+
426
+ .persona-suggestions[data-persona-suggestion-surface="starter"] {
427
+ margin-top: 16px;
428
+ }
429
+
430
+ /* Follow-ups sit 12px from their answer. The body gap is 24px with the
431
+ welcome host visible and already 12px when it is hidden, so the pull-up
432
+ only applies in the roomy case. */
433
+ .persona-gap-6 > [data-persona-suggestions="follow-up"] {
434
+ margin-top: -12px;
435
+ }
436
+
437
+ .persona-suggestions[data-variant="card"] {
438
+ --persona-suggestion-icon-size: var(
439
+ --persona-components-suggestion-card-iconSize,
440
+ 18px
441
+ );
442
+ display: grid;
443
+ grid-template-columns: repeat(auto-fit, minmax(min(100%, 240px), 1fr));
444
+ }
445
+
446
+ /* Welcome-surface policy, not a card property: the cap keeps a wide inline
447
+ panel at two starter columns instead of one stretched row. */
448
+ .persona-suggestions[data-variant="card"][data-persona-suggestion-surface="starter"] {
449
+ max-width: 600px;
450
+ }
451
+
452
+ .persona-suggestions[data-variant="list"] {
453
+ --persona-suggestion-icon-size: var(
454
+ --persona-components-suggestion-list-iconSize,
455
+ 17px
456
+ );
457
+ flex-direction: column;
458
+ }
459
+
460
+ .persona-suggestions[data-variant="chip"][data-overflow="scroll"] {
461
+ --persona-suggestion-scroll-fade-size: 32px;
462
+ flex-wrap: nowrap;
463
+ overflow-x: auto;
464
+ overscroll-behavior-inline: contain;
465
+ scrollbar-width: thin;
466
+ scroll-snap-type: inline proximity;
467
+ padding: 2px;
468
+ }
469
+
470
+ .persona-suggestions[data-variant="chip"][data-overflow="scroll"][data-scroll-right]:not(
471
+ [data-scroll-left]
472
+ ) {
473
+ -webkit-mask-image: linear-gradient(
474
+ to right,
475
+ #000 0,
476
+ #000 calc(100% - var(--persona-suggestion-scroll-fade-size)),
477
+ transparent 100%
478
+ );
479
+ mask-image: linear-gradient(
480
+ to right,
481
+ #000 0,
482
+ #000 calc(100% - var(--persona-suggestion-scroll-fade-size)),
483
+ transparent 100%
484
+ );
485
+ }
486
+
487
+ .persona-suggestions[data-variant="chip"][data-overflow="scroll"][data-scroll-left]:not(
488
+ [data-scroll-right]
489
+ ) {
490
+ -webkit-mask-image: linear-gradient(
491
+ to right,
492
+ transparent 0,
493
+ #000 var(--persona-suggestion-scroll-fade-size),
494
+ #000 100%
495
+ );
496
+ mask-image: linear-gradient(
497
+ to right,
498
+ transparent 0,
499
+ #000 var(--persona-suggestion-scroll-fade-size),
500
+ #000 100%
501
+ );
502
+ }
503
+
504
+ .persona-suggestions[data-variant="chip"][data-overflow="scroll"][data-scroll-left][data-scroll-right] {
505
+ -webkit-mask-image: linear-gradient(
506
+ to right,
507
+ transparent 0,
508
+ #000 var(--persona-suggestion-scroll-fade-size),
509
+ #000 calc(100% - var(--persona-suggestion-scroll-fade-size)),
510
+ transparent 100%
511
+ );
512
+ mask-image: linear-gradient(
513
+ to right,
514
+ transparent 0,
515
+ #000 var(--persona-suggestion-scroll-fade-size),
516
+ #000 calc(100% - var(--persona-suggestion-scroll-fade-size)),
517
+ transparent 100%
518
+ );
519
+ }
520
+
521
+ .persona-suggestions[data-variant="chip"][data-overflow="wrap"] {
522
+ flex-wrap: wrap;
523
+ }
524
+
525
+ /* Composer surface only: transcript follow-ups and welcome rows stay
526
+ left-aligned. fit-content centers a single row while wrapped rows keep a
527
+ shared left edge; per-row `justify-content: center` would rag them. */
528
+ [data-persona-composer-suggestions].persona-suggestions[data-variant="chip"] {
529
+ width: fit-content;
530
+ max-width: 100%;
531
+ margin-inline: auto;
532
+ }
533
+
534
+ .persona-suggestion {
535
+ appearance: none;
536
+ display: flex;
537
+ align-items: center;
538
+ justify-content: flex-start;
539
+ min-width: 0;
540
+ text-align: left;
541
+ font-family: inherit;
542
+ font-weight: 500;
543
+ cursor: pointer;
544
+ transition:
545
+ background-color 140ms ease,
546
+ border-color 140ms ease,
547
+ color 140ms ease,
548
+ box-shadow 140ms ease,
549
+ transform 100ms ease;
550
+ }
551
+
552
+ .persona-suggestion--chip {
553
+ flex: 0 0 auto;
554
+ scroll-snap-align: start;
555
+ min-height: var(--persona-components-suggestion-chip-minHeight, 36px);
556
+ gap: var(--persona-components-suggestion-chip-gap, 0.5rem);
557
+ padding: var(
558
+ --persona-components-suggestion-chip-padding,
559
+ 0.5rem 0.875rem
560
+ );
561
+ border: 1px solid
562
+ var(--persona-components-suggestion-chip-border, var(--persona-border));
563
+ border-radius: var(
564
+ --persona-components-suggestion-chip-borderRadius,
565
+ 9999px
566
+ );
567
+ background: var(
568
+ --persona-components-suggestion-chip-background,
569
+ var(--persona-surface)
570
+ );
571
+ color: var(
572
+ --persona-components-suggestion-chip-foreground,
573
+ var(--persona-text)
574
+ );
575
+ font-size: var(--persona-components-suggestion-chip-fontSize, 0.8125rem);
576
+ line-height: var(--persona-components-suggestion-chip-lineHeight, 1.25);
577
+ }
578
+
579
+ .persona-suggestion--card {
580
+ align-items: center;
581
+ min-height: var(--persona-components-suggestion-card-minHeight, 72px);
582
+ gap: var(--persona-components-suggestion-card-gap, 0.625rem);
583
+ padding: var(--persona-components-suggestion-card-padding, 1rem);
584
+ border: 1px solid
585
+ var(--persona-components-suggestion-card-border, var(--persona-border));
586
+ border-radius: var(
587
+ --persona-components-suggestion-card-borderRadius,
588
+ var(--persona-radius-xl)
589
+ );
590
+ background: var(
591
+ --persona-components-suggestion-card-background,
592
+ var(--persona-surface)
593
+ );
594
+ color: var(
595
+ --persona-components-suggestion-card-foreground,
596
+ var(--persona-text)
597
+ );
598
+ box-shadow: var(--persona-components-suggestion-card-shadow, none);
599
+ font-size: var(--persona-components-suggestion-card-fontSize, 0.875rem);
600
+ line-height: var(--persona-components-suggestion-card-lineHeight, 1.35);
601
+ }
602
+
603
+ .persona-suggestion--list {
604
+ align-items: center;
605
+ width: 100%;
606
+ min-height: var(--persona-components-suggestion-list-minHeight, 44px);
607
+ gap: var(--persona-components-suggestion-list-gap, 0.625rem);
608
+ padding: var(--persona-components-suggestion-list-padding, 0.75rem);
609
+ border: 1px solid
610
+ var(--persona-components-suggestion-list-border, var(--persona-border));
611
+ border-radius: var(
612
+ --persona-components-suggestion-list-borderRadius,
613
+ var(--persona-radius-md)
614
+ );
615
+ background: var(
616
+ --persona-components-suggestion-list-background,
617
+ transparent
618
+ );
619
+ color: var(
620
+ --persona-components-suggestion-list-foreground,
621
+ var(--persona-text)
622
+ );
623
+ font-size: var(--persona-components-suggestion-list-fontSize, 0.875rem);
624
+ line-height: var(--persona-components-suggestion-list-lineHeight, 1.35);
625
+ }
626
+
627
+ /* Title + description content reads top-aligned; a lone label centers in
628
+ the min-height instead of leaving dead space under the text. */
629
+ .persona-suggestion--card:has(.persona-suggestion__description),
630
+ .persona-suggestion--list:has(.persona-suggestion__description) {
631
+ align-items: flex-start;
632
+ }
633
+
634
+ .persona-suggestion__icon,
635
+ .persona-suggestion__arrow {
636
+ flex: 0 0 auto;
637
+ }
638
+
639
+ /* The taller viewport box centers the graphic on the label's first line box;
640
+ the icon keeps its size because the width constraint drives `meet` scaling. */
641
+ .persona-suggestion--card .persona-suggestion__icon {
642
+ block-size: calc(
643
+ 1em * var(--persona-components-suggestion-card-lineHeight, 1.35)
644
+ );
645
+ }
646
+
647
+ .persona-suggestion--list .persona-suggestion__icon {
648
+ block-size: calc(
649
+ 1em * var(--persona-components-suggestion-list-lineHeight, 1.35)
650
+ );
651
+ }
652
+
653
+ .persona-suggestion__copy {
654
+ display: flex;
655
+ flex: 1 1 auto;
656
+ min-width: 0;
657
+ flex-direction: column;
658
+ gap: 3px;
659
+ }
660
+
661
+ .persona-suggestion__label {
662
+ overflow-wrap: anywhere;
663
+ }
664
+
665
+ .persona-suggestion__description {
666
+ color: var(--persona-text-muted);
667
+ font-size: 0.75rem;
668
+ font-weight: 400;
669
+ line-height: 1.35;
670
+ }
671
+
672
+ /* Hover-revealed: the arrow is an affordance hint, not standing decoration. */
673
+ .persona-suggestion__arrow {
674
+ margin-left: auto;
675
+ opacity: 0;
676
+ transition: opacity 140ms ease;
677
+ }
678
+
679
+ .persona-suggestion:focus-visible .persona-suggestion__arrow {
680
+ opacity: 0.55;
681
+ }
682
+
683
+ /* Quiet accent, never a solid fill: an emphasized item reads as a sibling of
684
+ the set rather than a CTA among ghost buttons. */
685
+ .persona-suggestion[data-emphasis="primary"] {
686
+ border-color: var(--persona-primary);
687
+ background: transparent;
688
+ background: color-mix(in srgb, var(--persona-primary) 6%, transparent);
689
+ }
690
+
691
+ .persona-suggestion[data-emphasis="primary"] .persona-suggestion__icon {
692
+ color: var(--persona-primary);
693
+ }
694
+
695
+ @media (hover: hover) {
696
+ .persona-suggestion--chip:hover {
697
+ border-color: var(
698
+ --persona-components-suggestion-chip-hoverBorder,
699
+ var(--persona-border)
700
+ );
701
+ background: var(
702
+ --persona-components-suggestion-chip-hoverBackground,
703
+ var(--persona-container)
704
+ );
705
+ color: var(
706
+ --persona-components-suggestion-chip-hoverForeground,
707
+ inherit
708
+ );
709
+ }
710
+
711
+ .persona-suggestion:hover .persona-suggestion__arrow {
712
+ opacity: 0.55;
713
+ }
714
+
715
+ .persona-suggestion--card:hover {
716
+ border-color: var(
717
+ --persona-components-suggestion-card-hoverBorder,
718
+ var(--persona-border)
719
+ );
720
+ background: var(
721
+ --persona-components-suggestion-card-hoverBackground,
722
+ var(--persona-container)
723
+ );
724
+ box-shadow: var(--persona-shadow-sm);
725
+ transform: translateY(-1px);
726
+ }
727
+
728
+ .persona-suggestion--list:hover {
729
+ border-color: var(
730
+ --persona-components-suggestion-list-hoverBorder,
731
+ var(--persona-border)
732
+ );
733
+ background: var(
734
+ --persona-components-suggestion-list-hoverBackground,
735
+ var(--persona-container)
736
+ );
737
+ }
738
+
739
+ .persona-suggestion[data-emphasis="primary"]:hover {
740
+ border-color: var(--persona-primary);
741
+ background: transparent;
742
+ background: color-mix(in srgb, var(--persona-primary) 12%, transparent);
743
+ }
744
+ }
745
+
746
+ .persona-suggestion:focus-visible {
747
+ outline: 2px solid
748
+ var(
749
+ --persona-components-suggestion-chip-focusRing,
750
+ var(--persona-accent)
751
+ );
752
+ outline-offset: 2px;
753
+ }
754
+
755
+ .persona-suggestion--card:focus-visible {
756
+ outline-color: var(
757
+ --persona-components-suggestion-card-focusRing,
758
+ var(--persona-accent)
759
+ );
760
+ }
761
+
762
+ .persona-suggestion--list:focus-visible {
763
+ outline-color: var(
764
+ --persona-components-suggestion-list-focusRing,
765
+ var(--persona-accent)
766
+ );
767
+ }
768
+
769
+ .persona-suggestion--chip:active {
770
+ background: var(
771
+ --persona-components-suggestion-chip-pressedBackground,
772
+ var(--persona-container)
773
+ );
774
+ transform: scale(0.98);
775
+ }
776
+
777
+ .persona-suggestion--card:active {
778
+ background: var(
779
+ --persona-components-suggestion-card-pressedBackground,
780
+ var(--persona-container)
781
+ );
782
+ transform: translateY(1px);
783
+ }
784
+
785
+ .persona-suggestion--list:active {
786
+ background: var(
787
+ --persona-components-suggestion-list-pressedBackground,
788
+ var(--persona-container)
789
+ );
790
+ }
791
+
792
+ .persona-suggestion[data-emphasis="primary"]:active {
793
+ background: transparent;
794
+ background: color-mix(in srgb, var(--persona-primary) 16%, transparent);
795
+ }
796
+
797
+ .persona-suggestion:disabled {
798
+ cursor: not-allowed;
799
+ opacity: var(
800
+ --persona-components-suggestion-chip-disabledOpacity,
801
+ 0.5
802
+ );
803
+ }
804
+
805
+ .persona-suggestion--card:disabled {
806
+ opacity: var(
807
+ --persona-components-suggestion-card-disabledOpacity,
808
+ 0.5
809
+ );
810
+ }
811
+
812
+ .persona-suggestion--list:disabled {
813
+ opacity: var(
814
+ --persona-components-suggestion-list-disabledOpacity,
815
+ 0.5
816
+ );
817
+ }
818
+
819
+ @media (pointer: coarse) {
820
+ .persona-suggestion {
821
+ min-height: 44px;
822
+ }
823
+
824
+ /* No hover to reveal it, so the arrow would be permanent decoration. */
825
+ .persona-suggestion__arrow {
826
+ display: none;
827
+ }
828
+ }
829
+
830
+ @media (prefers-reduced-motion: reduce) {
831
+ .persona-suggestion,
832
+ .persona-suggestion__arrow {
833
+ transition: none;
834
+ }
835
+ }
836
+
837
+ /* Welcome surface ------------------------------------------------------- */
838
+
839
+ /* Interior padding rides the intro-card alias: the tokens layer zeroes the
840
+ horizontal component when the card resolves flat (no background, no
841
+ shadow), so default installs align the title with the content column
842
+ instead of indenting it by an invisible card inset. */
843
+ .persona-welcome {
844
+ padding: var(--persona-intro-card-padding, 1.5rem);
845
+ }
846
+
847
+ .persona-welcome[hidden],
848
+ .persona-welcome-greeting[hidden] {
849
+ display: none !important;
850
+ }
851
+
852
+ .persona-welcome-icon {
853
+ display: flex;
854
+ margin-bottom: 12px;
855
+ color: var(--persona-accent, currentColor);
856
+ }
857
+
858
+ .persona-welcome-icon[hidden] {
859
+ display: none !important;
860
+ }
861
+
862
+ .persona-welcome-icon-image {
863
+ width: 40px;
864
+ height: 40px;
865
+ border-radius: 999px;
866
+ object-fit: cover;
867
+ }
868
+
869
+ .persona-welcome-icon-text {
870
+ font-size: 32px;
871
+ line-height: 1;
872
+ }
873
+
874
+ /* Welcome copy: `components.introCard.title` / `.subtitle` typography.
875
+ Fallbacks reproduce the utility classes these rules replaced, so an
876
+ unset token renders pixel-identically. Margins stay untokenized. */
877
+ .persona-welcome-title {
878
+ font-family: var(--persona-components-introCard-title-fontFamily, inherit);
879
+ font-size: var(--persona-components-introCard-title-fontSize, 1.125rem);
880
+ font-weight: var(--persona-components-introCard-title-fontWeight, 600);
881
+ line-height: var(--persona-components-introCard-title-lineHeight, 1.75rem);
882
+ letter-spacing: var(--persona-components-introCard-title-letterSpacing, normal);
883
+ color: var(--persona-components-introCard-title-color, var(--persona-primary, #171717));
884
+ }
885
+
886
+ .persona-welcome-subtitle {
887
+ margin-top: 0.5rem;
888
+ font-family: var(--persona-components-introCard-subtitle-fontFamily, inherit);
889
+ font-size: var(--persona-components-introCard-subtitle-fontSize, 0.875rem);
890
+ font-weight: var(--persona-components-introCard-subtitle-fontWeight, inherit);
891
+ line-height: var(--persona-components-introCard-subtitle-lineHeight, 1.25rem);
892
+ letter-spacing: var(--persona-components-introCard-subtitle-letterSpacing, normal);
893
+ color: var(--persona-components-introCard-subtitle-color, var(--persona-muted, #6b7280));
894
+ }
895
+
896
+ /* Plugin-owned welcome (`renderWelcome`): the host keeps its position and the
897
+ default children are hidden by selector, so nothing about their own hidden
898
+ state has to be saved and restored when the plugin returns null again. */
899
+ .persona-welcome[data-persona-welcome-content="plugin"]
900
+ > :not([data-persona-welcome-plugin]) {
901
+ display: none !important;
902
+ }
903
+
904
+ .persona-welcome[data-persona-welcome-content="plugin"] {
905
+ background: transparent;
906
+ box-shadow: none;
907
+ }
908
+
909
+ /* Overlay state: a plugin element covers the messages area while it is active.
910
+ The body stops scrolling underneath so the absolute box maps to the visible
911
+ transcript rather than scrolling away with the content. */
912
+ /* Wide panels: the card variant shares the transcript column
913
+ (--persona-content-max-width, re-set inline from layout.contentMaxWidth)
914
+ so its left-aligned text lines up with messages and composer; at launcher
915
+ width the cap never bites. The plugin overlay stays full-bleed via the
916
+ :not(). */
917
+ .persona-welcome:not([data-persona-welcome-overlay]) {
918
+ width: 100%;
919
+ max-width: var(--persona-content-max-width, 768px);
920
+ margin-inline: auto;
921
+ }
922
+
923
+ /* The centered hero keeps the narrower consumer-product column, where
924
+ centered text makes the split against the transcript read as intended. */
925
+ .persona-welcome[data-persona-welcome-variant="hero"]:not(
926
+ [data-persona-welcome-overlay]
927
+ ) {
928
+ max-width: var(--persona-welcome-max-width, 640px);
929
+ }
930
+
931
+ /* The greeting bubble is a sibling of the transcript wrapper, outside its
932
+ inline width cap; mirror the cap so it shares the same column. */
933
+ .persona-welcome-greeting {
934
+ width: 100%;
935
+ max-width: var(--persona-content-max-width, 768px);
936
+ margin-inline: auto;
937
+ }
938
+
939
+ .persona-welcome[data-persona-welcome-overlay] {
940
+ position: absolute;
941
+ inset: 0;
942
+ z-index: 5;
943
+ overflow-y: auto;
944
+ /* Plugin overlays are opaque surfaces regardless of the intro-card theme,
945
+ so they keep full interior padding even when the card resolves flat. */
946
+ padding: 1.5rem;
947
+ /* !important: the host doubles as the intro card and carries an inline
948
+ background (--persona-intro-card-bg, default transparent); the overlay
949
+ must stay opaque or the transcript bleeds through the plugin stack. */
950
+ background: var(
951
+ --persona-container,
952
+ var(--persona-surface, #ffffff)
953
+ ) !important;
954
+ }
955
+
956
+ .persona-widget-body.persona-welcome-overlay-active {
957
+ overflow: hidden;
958
+ }
959
+
960
+ /* Hero: auto block margins center the surface in the empty conversation
961
+ without `justify-content`, which would make overflowing content
962
+ unreachable in the scroll body. */
963
+ .persona-welcome[data-persona-welcome-variant="hero"] {
964
+ margin-block: auto;
965
+ text-align: center;
966
+ }
967
+
968
+ .persona-welcome[data-persona-welcome-variant="hero"] .persona-welcome-icon {
969
+ justify-content: center;
970
+ }
971
+
972
+ .persona-welcome[data-persona-welcome-variant="hero"] .persona-suggestions {
973
+ margin-inline: auto;
974
+ justify-content: center;
975
+ }
976
+
977
+ .persona-welcome[data-persona-welcome-variant="hero"]
978
+ .persona-suggestions[data-variant="card"],
979
+ .persona-welcome[data-persona-welcome-variant="hero"]
980
+ .persona-suggestions[data-variant="list"] {
981
+ text-align: start;
982
+ width: 100%;
983
+ }
984
+
239
985
  /* Composer ghost icon buttons (attachment + mention): transparent, neutral
240
986
  foreground, subtle hover. Themeable via `components.button.ghost.*`
241
987
  → `--persona-button-ghost-*`. The `[data-persona-root]` prefix outranks the
@@ -990,6 +1736,27 @@
990
1736
  box-shadow: var(--persona-composer-shadow, none);
991
1737
  }
992
1738
 
1739
+ /* Composer spacing, themeable via `components.composer.padding` / `.gap`.
1740
+ The `[data-persona-root]` prefix outranks the `persona-px-4 persona-py-3
1741
+ persona-gap-2` utilities the form still carries; the fallbacks reproduce
1742
+ them exactly. The pill composer is excluded because it sets its own
1743
+ grid padding/gap (see `.persona-pill-composer`). */
1744
+ [data-persona-root] .persona-widget-composer:not(.persona-pill-composer) {
1745
+ padding: var(--persona-composer-padding, 0.75rem 1rem);
1746
+ gap: var(--persona-composer-gap, 0.5rem);
1747
+ /* `components.composer.borderColor`; the fallback matches the
1748
+ `persona-border-persona-border` utility the form carries. */
1749
+ border-color: var(--persona-composer-border-color, var(--persona-border, #e5e7eb));
1750
+ }
1751
+
1752
+ /* Composer type scale, themeable via `components.composer.fontSize` /
1753
+ `.lineHeight`. Outranks the `persona-text-sm` utility on the textarea;
1754
+ fallbacks match it. Applies to the pill composer's textarea too. */
1755
+ [data-persona-root] .persona-composer-textarea {
1756
+ font-size: var(--persona-composer-font-size, 0.875rem);
1757
+ line-height: var(--persona-composer-line-height, 1.25rem);
1758
+ }
1759
+
993
1760
  .persona-form-grid {
994
1761
  display: flex;
995
1762
  flex-direction: column;
@@ -2746,7 +3513,10 @@
2746
3513
  }
2747
3514
 
2748
3515
  [data-persona-root] .persona-artifact-list::-webkit-scrollbar-thumb {
2749
- background: var(--persona-artifact-tab-list-scrollbar, var(--persona-border, #e5e7eb));
3516
+ background: var(
3517
+ --persona-artifact-tab-list-scrollbar,
3518
+ var(--persona-scrollbar-thumb, var(--persona-border, #e5e7eb))
3519
+ );
2750
3520
  border-radius: 9999px;
2751
3521
  }
2752
3522
 
@@ -3807,13 +4577,17 @@
3807
4577
  }
3808
4578
 
3809
4579
  @media (min-width: 641px) {
4580
+ /* Drawer width is its own knob (`layout.drawerWidth`), not the split's
4581
+ pane vars: those are always materialized with split defaults, so reading
4582
+ them here would resize every host's drawer. The outer min() keeps an
4583
+ oversized value inside the panel. */
3810
4584
  [data-persona-root].persona-artifact-narrow-host .persona-artifact-pane {
3811
4585
  position: absolute;
3812
4586
  top: 0;
3813
4587
  right: 0;
3814
4588
  bottom: 0;
3815
- width: min(calc(100% - 1rem), 22rem) !important;
3816
- max-width: 22rem !important;
4589
+ width: min(100%, var(--persona-artifact-drawer-width, min(calc(100% - 1rem), 22rem))) !important;
4590
+ max-width: var(--persona-artifact-drawer-width, 22rem) !important;
3817
4591
  z-index: 60;
3818
4592
  transform: translateX(100%);
3819
4593
  transition: transform 0.2s ease;
@@ -3830,7 +4604,7 @@
3830
4604
  top: 0;
3831
4605
  right: 0;
3832
4606
  bottom: 0;
3833
- width: min(100vw - 1.5rem, 22rem);
4607
+ width: min(100vw, var(--persona-artifact-drawer-width, min(100vw - 1.5rem, 22rem)));
3834
4608
  z-index: 60;
3835
4609
  transform: translateX(100%);
3836
4610
  transition: transform 0.2s ease;