@runtypelabs/persona 4.8.0 → 4.10.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 (130) hide show
  1. package/README.md +14 -1
  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-BsZtXPKK.d.cts → types-4ROVJ1gA.d.cts} +42 -0
  5. package/dist/animations/{types-BsZtXPKK.d.ts → types-4ROVJ1gA.d.ts} +42 -0
  6. package/dist/animations/wipe.d.cts +1 -1
  7. package/dist/animations/wipe.d.ts +1 -1
  8. package/dist/chunk-IO5VVUKP.js +3 -0
  9. package/dist/chunk-IPVK3KOM.js +1 -0
  10. package/dist/chunk-UPO4GUFC.js +1 -0
  11. package/dist/codegen.cjs +6 -6
  12. package/dist/codegen.js +8 -8
  13. package/dist/context-mentions-7S5KVUTG.js +169 -0
  14. package/dist/context-mentions-inline-TTCN7ZM2.js +4 -0
  15. package/dist/context-mentions-inline.cjs +4 -0
  16. package/dist/context-mentions-inline.d.cts +203 -0
  17. package/dist/context-mentions-inline.d.ts +203 -0
  18. package/dist/context-mentions-inline.js +4 -0
  19. package/dist/context-mentions.cjs +295 -0
  20. package/dist/context-mentions.d.cts +7025 -0
  21. package/dist/context-mentions.d.ts +7025 -0
  22. package/dist/context-mentions.js +295 -0
  23. package/dist/index.cjs +72 -64
  24. package/dist/index.cjs.map +1 -1
  25. package/dist/index.d.cts +634 -3
  26. package/dist/index.d.ts +634 -3
  27. package/dist/index.global.js +59 -51
  28. package/dist/index.global.js.map +1 -1
  29. package/dist/index.js +64 -56
  30. package/dist/index.js.map +1 -1
  31. package/dist/launcher.global.js +2 -2
  32. package/dist/launcher.global.js.map +1 -1
  33. package/dist/plugin-kit.cjs +1 -1
  34. package/dist/plugin-kit.d.cts +17 -0
  35. package/dist/plugin-kit.d.ts +17 -0
  36. package/dist/plugin-kit.js +1 -1
  37. package/dist/smart-dom-reader.cjs +17 -16
  38. package/dist/smart-dom-reader.d.cts +507 -1
  39. package/dist/smart-dom-reader.d.ts +507 -1
  40. package/dist/smart-dom-reader.js +17 -16
  41. package/dist/theme-editor-preview.cjs +236 -57
  42. package/dist/theme-editor-preview.d.cts +485 -1
  43. package/dist/theme-editor-preview.d.ts +485 -1
  44. package/dist/theme-editor-preview.js +53 -47
  45. package/dist/theme-editor.cjs +7 -7
  46. package/dist/theme-editor.d.cts +473 -0
  47. package/dist/theme-editor.d.ts +473 -0
  48. package/dist/theme-editor.js +5 -5
  49. package/dist/theme-reference.cjs +1 -1
  50. package/dist/theme-reference.d.cts +2 -0
  51. package/dist/theme-reference.d.ts +2 -0
  52. package/dist/widget.css +1 -1
  53. package/package.json +15 -3
  54. package/src/client.test.ts +69 -0
  55. package/src/client.ts +65 -51
  56. package/src/components/artifact-pane.test.ts +47 -0
  57. package/src/components/artifact-pane.ts +25 -2
  58. package/src/components/composer-parts.ts +3 -12
  59. package/src/components/context-mention-button.test.ts +70 -0
  60. package/src/components/context-mention-button.ts +82 -0
  61. package/src/components/context-mention-chip.ts +134 -0
  62. package/src/components/context-mention-menu.test.ts +508 -0
  63. package/src/components/context-mention-menu.ts +0 -0
  64. package/src/components/message-bubble.test.ts +175 -0
  65. package/src/components/message-bubble.ts +177 -19
  66. package/src/components/panel.ts +7 -10
  67. package/src/context-mentions-bundle.test.ts +163 -0
  68. package/src/context-mentions-entry.ts +185 -0
  69. package/src/context-mentions-inline-entry.test.ts +136 -0
  70. package/src/context-mentions-inline-entry.ts +226 -0
  71. package/src/context-mentions-inline-loader.test.ts +30 -0
  72. package/src/context-mentions-inline-loader.ts +36 -0
  73. package/src/context-mentions-inline.ts +15 -0
  74. package/src/context-mentions-loader.ts +32 -0
  75. package/src/context-mentions.ts +16 -0
  76. package/src/index-core.ts +27 -0
  77. package/src/index-global.ts +51 -0
  78. package/src/markdown-parsers-loader.ts +35 -44
  79. package/src/plugin-kit.test.ts +40 -0
  80. package/src/plugin-kit.ts +39 -5
  81. package/src/runtime/init-update-reset.test.ts +81 -0
  82. package/src/runtime/init.test.ts +62 -0
  83. package/src/runtime/init.ts +7 -14
  84. package/src/session.mentions.test.ts +175 -0
  85. package/src/session.test.ts +52 -4
  86. package/src/session.ts +121 -5
  87. package/src/smart-dom-reader.test.ts +129 -2
  88. package/src/smart-dom-reader.ts +127 -1
  89. package/src/styles/context-mention-menu-css.ts +176 -0
  90. package/src/styles/widget.css +243 -126
  91. package/src/theme-editor/sections.ts +3 -3
  92. package/src/types/theme.ts +2 -0
  93. package/src/types.ts +542 -0
  94. package/src/ui.artifact-pane-gating.test.ts +11 -1
  95. package/src/ui.attachments-drop.test.ts +90 -0
  96. package/src/ui.header-update-stability.test.ts +149 -0
  97. package/src/ui.launcher-update-merge.test.ts +83 -0
  98. package/src/ui.mention-submit.test.ts +235 -0
  99. package/src/ui.send-button-stream-update.test.ts +69 -0
  100. package/src/ui.ts +379 -84
  101. package/src/utils/chunk-loader.test.ts +97 -0
  102. package/src/utils/chunk-loader.ts +88 -0
  103. package/src/utils/composer-contenteditable.test.ts +507 -0
  104. package/src/utils/composer-contenteditable.ts +626 -0
  105. package/src/utils/composer-document.test.ts +280 -0
  106. package/src/utils/composer-document.ts +293 -0
  107. package/src/utils/composer-history.test.ts +35 -7
  108. package/src/utils/composer-history.ts +30 -20
  109. package/src/utils/composer-input.ts +159 -0
  110. package/src/utils/config-merge.test.ts +131 -0
  111. package/src/utils/config-merge.ts +61 -0
  112. package/src/utils/context-mention-controller.test.ts +1215 -0
  113. package/src/utils/context-mention-controller.ts +1186 -0
  114. package/src/utils/context-mention-manager.test.ts +422 -0
  115. package/src/utils/context-mention-manager.ts +410 -0
  116. package/src/utils/context-mention-orchestrator.test.ts +538 -0
  117. package/src/utils/context-mention-orchestrator.ts +348 -0
  118. package/src/utils/live-region.test.ts +108 -0
  119. package/src/utils/live-region.ts +94 -0
  120. package/src/utils/mention-channels.ts +63 -0
  121. package/src/utils/mention-llm-format.test.ts +91 -0
  122. package/src/utils/mention-llm-format.ts +79 -0
  123. package/src/utils/mention-matcher.test.ts +86 -0
  124. package/src/utils/mention-matcher.ts +221 -0
  125. package/src/utils/mention-token.ts +72 -0
  126. package/src/utils/mention-trigger.test.ts +155 -0
  127. package/src/utils/mention-trigger.ts +156 -0
  128. package/src/utils/theme.test.ts +54 -4
  129. package/src/utils/theme.ts +6 -3
  130. package/src/utils/tokens.ts +27 -11
@@ -53,10 +53,6 @@
53
53
  align-items: center;
54
54
  }
55
55
 
56
- .persona-items-end {
57
- align-items: flex-end;
58
- }
59
-
60
56
  .persona-items-start {
61
57
  align-items: flex-start;
62
58
  }
@@ -238,6 +234,24 @@
238
234
  border-radius: var(--persona-button-radius);
239
235
  }
240
236
 
237
+ /* Composer ghost icon buttons (attachment + mention): transparent, neutral
238
+ foreground, subtle hover. Themeable via `components.button.ghost.*`
239
+ → `--persona-button-ghost-*`. The `[data-persona-root]` prefix outranks the
240
+ `.persona-rounded-button` full-radius above so the ghost radius wins. */
241
+ [data-persona-root] .persona-mention-button,
242
+ [data-persona-root] .persona-attachment-button {
243
+ background-color: var(--persona-button-ghost-bg, transparent);
244
+ color: var(--persona-button-ghost-fg, var(--persona-text, #111827));
245
+ border: none;
246
+ border-radius: var(--persona-button-ghost-radius, var(--persona-radius-md, 0.375rem));
247
+ transition: background-color 0.15s ease;
248
+ }
249
+
250
+ [data-persona-root] .persona-mention-button:hover,
251
+ [data-persona-root] .persona-attachment-button:hover {
252
+ background-color: var(--persona-button-ghost-hover-bg, rgba(0, 0, 0, 0.05));
253
+ }
254
+
241
255
  .persona-overflow-hidden {
242
256
  overflow: hidden;
243
257
  }
@@ -274,10 +288,6 @@
274
288
  background-color: #f3f4f6;
275
289
  }
276
290
 
277
- .persona-bg-gray-200 {
278
- background-color: #e5e7eb;
279
- }
280
-
281
291
  .persona-text-persona-primary {
282
292
  color: var(--persona-primary, #171717);
283
293
  }
@@ -436,14 +446,6 @@
436
446
  padding-left: 0.75rem;
437
447
  }
438
448
 
439
- .persona-pl-7 {
440
- padding-left: 1.75rem;
441
- }
442
-
443
- .persona-pr-7 {
444
- padding-right: 1.75rem;
445
- }
446
-
447
449
  .persona-pl-8 {
448
450
  padding-left: 2rem;
449
451
  }
@@ -526,22 +528,10 @@
526
528
  opacity: 0.5;
527
529
  }
528
530
 
529
- .persona-shadow-2xl {
530
- box-shadow: 0 30px 60px -15px rgba(15, 23, 42, 0.35);
531
- }
532
-
533
531
  .persona-shadow-sm {
534
532
  box-shadow: 0 5px 15px rgba(15, 23, 42, 0.08);
535
533
  }
536
534
 
537
- .persona-shadow-md {
538
- box-shadow: 0 4px 6px -1px rgba(0,0,0,0.1), 0 2px 4px -2px rgba(0,0,0,0.1);
539
- }
540
-
541
- .persona-shadow-lg {
542
- box-shadow: 0 20px 40px rgba(15, 23, 42, 0.18);
543
- }
544
-
545
535
  .persona-border {
546
536
  border-width: 1px;
547
537
  border-style: solid;
@@ -558,14 +548,6 @@
558
548
  border-bottom-color: rgba(148, 163, 184, 0.28);
559
549
  }
560
550
 
561
- .persona-border-gray-100 {
562
- border-color: #f1f5f9;
563
- }
564
-
565
- .persona-border-persona-secondary {
566
- border-color: var(--persona-secondary, #7c3aed);
567
- }
568
-
569
551
  .persona-border-persona-border {
570
552
  border-color: var(--persona-border, #e5e7eb);
571
553
  }
@@ -576,18 +558,6 @@
576
558
  border-top-color: rgba(148, 163, 184, 0.28);
577
559
  }
578
560
 
579
- .persona-border-t-persona-border {
580
- border-top-width: 1px;
581
- border-top-style: solid;
582
- border-top-color: var(--persona-border, #f1f5f9);
583
- }
584
-
585
- .persona-border-b-persona-border {
586
- border-bottom-width: 1px;
587
- border-bottom-style: solid;
588
- border-bottom-color: var(--persona-border, #f1f5f9);
589
- }
590
-
591
561
  .persona-border-t-persona-divider {
592
562
  border-top-width: 1px;
593
563
  border-top-style: solid;
@@ -664,13 +634,6 @@
664
634
  width: 2.5rem;
665
635
  }
666
636
 
667
- .persona-h-12 {
668
- height: 3rem;
669
- }
670
-
671
- .persona-w-12 {
672
- width: 3rem;
673
- }
674
637
 
675
638
  .persona-leading-relaxed {
676
639
  line-height: 1.75;
@@ -777,8 +740,6 @@
777
740
  margin-top: 0.5rem;
778
741
  }
779
742
 
780
- .persona-h-12,
781
- .persona-w-12,
782
743
  .persona-h-10,
783
744
  .persona-w-10,
784
745
  .persona-h-8,
@@ -790,10 +751,6 @@
790
751
  text-align: right;
791
752
  }
792
753
 
793
- .hover\:persona-bg-gray-200:hover {
794
- background-color: #e5e7eb;
795
- }
796
-
797
754
  .hover\:persona-bg-persona-container:hover {
798
755
  background-color: var(--persona-container, #f8fafc);
799
756
  }
@@ -1348,68 +1305,6 @@
1348
1305
  font-size: 0.8125rem;
1349
1306
  }
1350
1307
 
1351
- /* Code block copy button */
1352
- .persona-code-block-wrapper {
1353
- position: relative;
1354
- margin: 0.5rem 0;
1355
- }
1356
-
1357
- .persona-code-block-wrapper pre {
1358
- margin: 0 !important;
1359
- border-top-left-radius: 0 !important;
1360
- border-top-right-radius: 0 !important;
1361
- }
1362
-
1363
- .persona-code-block-header {
1364
- display: flex;
1365
- align-items: center;
1366
- justify-content: space-between;
1367
- background-color: var(--persona-md-code-block-bg, #f3f4f6);
1368
- border: 1px solid var(--persona-md-code-block-border-color, #e5e7eb);
1369
- border-bottom: none;
1370
- border-top-left-radius: var(--persona-md-code-block-border-radius, 0.375rem);
1371
- border-top-right-radius: var(--persona-md-code-block-border-radius, 0.375rem);
1372
- padding: 0.25rem 0.5rem 0.25rem 0.75rem;
1373
- font-size: 0.75rem;
1374
- color: var(--persona-text-muted, #6b7280);
1375
- font-family: ui-monospace, SFMono-Regular, "SF Mono", Consolas, "Liberation Mono", Menlo, monospace;
1376
- }
1377
-
1378
- .persona-code-copy-btn {
1379
- display: inline-flex;
1380
- align-items: center;
1381
- gap: 0.25rem;
1382
- background: none;
1383
- border: 1px solid transparent;
1384
- border-radius: 0.25rem;
1385
- padding: 0.25rem 0.5rem;
1386
- cursor: pointer;
1387
- color: var(--persona-text-muted, #6b7280);
1388
- font-size: 0.75rem;
1389
- font-family: inherit;
1390
- line-height: 1;
1391
- transition: color 0.15s ease, border-color 0.15s ease;
1392
- }
1393
-
1394
- .persona-code-copy-btn:hover {
1395
- color: var(--persona-text, #111827);
1396
- border-color: var(--persona-md-code-block-border-color, #e5e7eb);
1397
- }
1398
-
1399
- .persona-code-copy-btn.persona-code-copied {
1400
- color: #16a34a;
1401
- }
1402
-
1403
- .persona-code-copy-btn.persona-code-copy-generating {
1404
- cursor: default;
1405
- opacity: 0.5;
1406
- }
1407
-
1408
- .persona-code-copy-btn.persona-code-copy-generating:hover {
1409
- color: var(--persona-text-muted, #6b7280);
1410
- border-color: transparent;
1411
- }
1412
-
1413
1308
  /* Ensure all links in chat bubbles have underlines */
1414
1309
  .persona-message-bubble a {
1415
1310
  text-decoration: underline;
@@ -2726,9 +2621,6 @@
2726
2621
  background: var(--persona-artifact-toolbar-icon-hover-bg, var(--persona-icon-btn-hover-bg, var(--persona-container, #f3f4f6)));
2727
2622
  }
2728
2623
 
2729
- [data-persona-root] .persona-artifact-toolbar-document .persona-artifact-doc-copy-label {
2730
- font-weight: 500;
2731
- }
2732
2624
 
2733
2625
  /* Artifact tab theming */
2734
2626
  [data-persona-root] .persona-artifact-tab {
@@ -3314,6 +3206,20 @@
3314
3206
  /* Shared artifact preview body wrapper (artifact-preview.ts): generates no box
3315
3207
  so children (e.g. the iframe's height: 100%) lay out against the host
3316
3208
  container exactly as if they were its direct children. */
3209
+ [data-persona-root] .persona-artifact-content {
3210
+ width: 100%;
3211
+ min-width: 0;
3212
+ max-width: 100%;
3213
+ }
3214
+
3215
+ [data-persona-root]
3216
+ .persona-artifact-content
3217
+ > .persona-artifact-preview-body
3218
+ > * {
3219
+ min-width: 0;
3220
+ max-width: 100%;
3221
+ }
3222
+
3317
3223
  [data-persona-root] .persona-artifact-preview-body {
3318
3224
  display: contents;
3319
3225
  }
@@ -4786,3 +4692,214 @@
4786
4692
  display: none;
4787
4693
  }
4788
4694
  }
4695
+
4696
+ /* ===========================================================================
4697
+ * Context mentions (composer @-mentions): chip row, menu, affordance button.
4698
+ * Tokens default off the existing palette vars so themed widgets pick them up.
4699
+ * =========================================================================== */
4700
+
4701
+ /* Composer size-query container. Both the full and pill composers carry
4702
+ * `data-persona-composer-form`; establishing a container here lets a host
4703
+ * stylesheet make composer controls responsive to the PANEL width rather than
4704
+ * the viewport — correct across floating / docked / fullscreen, where the
4705
+ * composer is frequently narrower than the screen. Safe: the form is block-level
4706
+ * and already sized by its parent, so inline-size containment doesn't change its
4707
+ * width, and the ask sheet + mention menu mount OUTSIDE the form, so layout
4708
+ * containment can't capture them. Query with `@container persona-composer (...)`;
4709
+ * `.persona-mention-button` is a supported, stable hook. */
4710
+ [data-persona-composer-form] {
4711
+ container-type: inline-size;
4712
+ container-name: persona-composer;
4713
+ }
4714
+
4715
+ .persona-mention-context-row {
4716
+ display: none; /* toggled to flex by the manager when chips exist */
4717
+ flex-wrap: wrap;
4718
+ gap: var(--persona-mention-chip-gap, 6px);
4719
+ margin-bottom: var(--persona-mention-row-gap, 8px);
4720
+ }
4721
+
4722
+ .persona-mention-chip {
4723
+ display: inline-flex;
4724
+ align-items: center;
4725
+ gap: 5px;
4726
+ height: var(--persona-mention-chip-height, 26px);
4727
+ padding: 0 6px 0 8px;
4728
+ border-radius: var(--persona-mention-chip-radius, 6px);
4729
+ background: var(--persona-mention-chip-bg, var(--persona-container, #f3f4f6));
4730
+ border: 1px solid var(--persona-mention-chip-border, var(--persona-border, #e5e7eb));
4731
+ color: var(--persona-mention-chip-fg, var(--persona-text, #111827));
4732
+ font-size: var(--persona-mention-chip-font-size, 12px);
4733
+ line-height: 1;
4734
+ max-width: 220px;
4735
+ }
4736
+
4737
+ .persona-mention-chip[data-status="error"] {
4738
+ border-color: var(--persona-mention-error, #dc2626);
4739
+ color: var(--persona-mention-error, #dc2626);
4740
+ }
4741
+
4742
+ .persona-mention-chip-icon {
4743
+ display: inline-flex;
4744
+ align-items: center;
4745
+ flex: 0 0 auto;
4746
+ opacity: 0.8;
4747
+ }
4748
+
4749
+ .persona-mention-chip-label {
4750
+ overflow: hidden;
4751
+ text-overflow: ellipsis;
4752
+ white-space: nowrap;
4753
+ }
4754
+
4755
+ .persona-mention-chip-spinner {
4756
+ flex: 0 0 auto;
4757
+ width: 12px;
4758
+ height: 12px;
4759
+ border-radius: 50%;
4760
+ border: 2px solid var(--persona-mention-chip-border, var(--persona-border, #d1d5db));
4761
+ border-top-color: var(--persona-mention-accent, var(--persona-accent, #0f0f0f));
4762
+ animation: persona-mention-spin 0.7s linear infinite;
4763
+ }
4764
+
4765
+ @keyframes persona-mention-spin {
4766
+ to {
4767
+ transform: rotate(360deg);
4768
+ }
4769
+ }
4770
+
4771
+ .persona-mention-chip-remove {
4772
+ display: inline-flex;
4773
+ align-items: center;
4774
+ justify-content: center;
4775
+ flex: 0 0 auto;
4776
+ width: 16px;
4777
+ height: 16px;
4778
+ padding: 0;
4779
+ border: none;
4780
+ border-radius: 4px;
4781
+ background: transparent;
4782
+ color: inherit;
4783
+ opacity: 0.6;
4784
+ cursor: pointer;
4785
+ transition: opacity 0.15s ease, background-color 0.15s ease;
4786
+ }
4787
+
4788
+ .persona-mention-chip-remove:hover {
4789
+ opacity: 1;
4790
+ background: var(--persona-palette-colors-black-alpha-50, rgba(0, 0, 0, 0.06));
4791
+ }
4792
+
4793
+ /* The mention MENU CSS (.persona-mention-menu / -list / -search / -group /
4794
+ * -option / -status / -error / -retry and its coarse-pointer row sizing) lives
4795
+ * in the lazy context-mentions chunk (src/styles/context-mention-menu-css.ts)
4796
+ * and is injected on first menu open — so it also styles the body-mounted menu
4797
+ * inside a useShadowDom widget. Only the eagerly-rendered chip / context-row
4798
+ * pieces stay here. */
4799
+
4800
+ .persona-mention-chip-readonly {
4801
+ padding-right: 8px;
4802
+ cursor: default;
4803
+ }
4804
+
4805
+ /* Inline mention token (display: "inline"). Atomic styled chip that sits INSIDE
4806
+ * the sentence — in the contenteditable composer and in the read-only sent
4807
+ * bubble. Kept in the core stylesheet (tiny) so tokens are styled the instant a
4808
+ * segmented bubble renders, without waiting on the inline chunk's CSS. */
4809
+ .persona-mention-token {
4810
+ /* Per-token accent — set inline from `ref.color`, per source via
4811
+ * `.persona-mention-token[data-mention-source="…"]`, or globally by overriding
4812
+ * this var. Recolors the whole pill (tint bg + icon + label). */
4813
+ --persona-mention-token-accent: var(--persona-accent, #4338ca);
4814
+ display: inline-flex;
4815
+ align-items: center;
4816
+ gap: var(--persona-mention-token-gap, 4px);
4817
+ padding: var(--persona-mention-token-padding, 1px 6px);
4818
+ border-radius: var(--persona-mention-token-radius, 6px);
4819
+ /* Fallback flat tint first (older browsers), then a per-accent translucent
4820
+ * tint via color-mix so each type reads as its own color (Slack/Cursor). */
4821
+ background: var(--persona-mention-token-bg, #eef2ff);
4822
+ background: var(
4823
+ --persona-mention-token-bg,
4824
+ color-mix(in srgb, var(--persona-mention-token-accent) 14%, transparent)
4825
+ );
4826
+ color: var(--persona-mention-token-fg, var(--persona-mention-token-accent));
4827
+ font-size: var(--persona-mention-token-font-size, 0.95em);
4828
+ font-weight: var(--persona-mention-token-font-weight, 550);
4829
+ line-height: 1.5;
4830
+ white-space: nowrap;
4831
+ vertical-align: baseline;
4832
+ user-select: none;
4833
+ }
4834
+
4835
+ .persona-mention-token-icon {
4836
+ display: inline-flex;
4837
+ align-items: center;
4838
+ }
4839
+
4840
+ .persona-mention-token-label {
4841
+ white-space: nowrap;
4842
+ }
4843
+
4844
+ /* Read-only token in a sent bubble: no editable affordances (the composer's
4845
+ * atomic caret/select behavior doesn't apply), so it reads as inert prose. */
4846
+ .persona-mention-token-readonly {
4847
+ cursor: default;
4848
+ user-select: text;
4849
+ }
4850
+
4851
+ /* Resolve failure on an inline token: recolor the pill to the danger accent and
4852
+ * add a subtle inset border ring, reusing the same accent custom-property the
4853
+ * token already themes on (so bg tint + icon + label all shift together). */
4854
+ .persona-mention-token-error {
4855
+ --persona-mention-token-accent: var(--persona-mention-error, #dc2626);
4856
+ box-shadow: inset 0 0 0 1px
4857
+ color-mix(in srgb, var(--persona-mention-token-accent) 45%, transparent);
4858
+ }
4859
+
4860
+ /* The contenteditable composer surface: behaves like the textarea it replaced. */
4861
+ .persona-composer-contenteditable {
4862
+ white-space: pre-wrap;
4863
+ overflow-wrap: anywhere;
4864
+ outline: none;
4865
+ max-height: var(--persona-composer-max-height, 200px);
4866
+ overflow-y: auto;
4867
+ }
4868
+
4869
+ .persona-composer-contenteditable:empty::before {
4870
+ content: attr(data-placeholder);
4871
+ color: var(--persona-placeholder, var(--persona-muted, #9ca3af));
4872
+ pointer-events: none;
4873
+ }
4874
+
4875
+ .persona-message-mentions {
4876
+ margin-top: 6px;
4877
+ margin-bottom: 0;
4878
+ }
4879
+
4880
+ /* Touch targets: on coarse pointers (phones/tablets) grow the chip + its remove
4881
+ * control to the ~44px minimum. Desktop keeps the compact sizing above. (The
4882
+ * menu row / retry coarse sizing ships with the menu CSS in the lazy chunk.) */
4883
+ @media (pointer: coarse) {
4884
+ .persona-mention-chip {
4885
+ height: auto;
4886
+ min-height: 40px;
4887
+ }
4888
+ .persona-mention-chip-remove {
4889
+ width: 36px;
4890
+ height: 36px;
4891
+ margin-right: -6px; /* keep the visual gap tight while the hit area grows */
4892
+ }
4893
+ }
4894
+
4895
+ @media (prefers-reduced-motion: reduce) {
4896
+ /* No spin: show a static neutral ring instead of a rotating arc. */
4897
+ .persona-mention-chip-spinner {
4898
+ animation: none;
4899
+ border-top-color: var(
4900
+ --persona-mention-chip-border,
4901
+ var(--persona-border, #d1d5db)
4902
+ );
4903
+ opacity: 0.6;
4904
+ }
4905
+ }
@@ -470,8 +470,8 @@ const SHADOW_SCALE_OPTIONS: { value: string; label: string }[] = [
470
470
  { value: 'palette.shadows.xl', label: 'Extra Large' },
471
471
  ];
472
472
 
473
- // The approval and intro-card defaults are a bespoke "card" shadow rather than a
474
- // palette step, so expose it as a leading "Default" option users can keep.
473
+ // The approval default is a bespoke "card" shadow rather than a palette step,
474
+ // so expose it as a leading "Default" option users can keep.
475
475
  const CARD_SHADOW = '0 5px 15px rgba(15, 23, 42, 0.08)';
476
476
  const CARD_SHADOW_OPTIONS = [{ value: CARD_SHADOW, label: 'Default' }, ...SHADOW_SCALE_OPTIONS];
477
477
 
@@ -486,7 +486,7 @@ const componentShadowsSectionDef: SectionDef = {
486
486
  { id: 'shadow-tool-bubble', label: 'Tool Call Bubble', type: 'select', path: 'theme.components.toolBubble.shadow', defaultValue: 'palette.shadows.sm', options: SHADOW_SCALE_OPTIONS },
487
487
  { id: 'shadow-reasoning-bubble', label: 'Reasoning Bubble', type: 'select', path: 'theme.components.reasoningBubble.shadow', defaultValue: 'palette.shadows.sm', options: SHADOW_SCALE_OPTIONS },
488
488
  { id: 'shadow-approval', label: 'Approval Bubble', type: 'select', path: 'theme.components.approval.requested.shadow', defaultValue: CARD_SHADOW, options: CARD_SHADOW_OPTIONS },
489
- { id: 'shadow-intro-card', label: 'Intro Card', type: 'select', path: 'theme.components.introCard.shadow', defaultValue: CARD_SHADOW, options: CARD_SHADOW_OPTIONS },
489
+ { id: 'shadow-intro-card', label: 'Intro Card', type: 'select', path: 'theme.components.introCard.shadow', defaultValue: 'palette.shadows.none', options: CARD_SHADOW_OPTIONS },
490
490
  { id: 'shadow-composer', label: 'Composer', type: 'select', path: 'theme.components.composer.shadow', defaultValue: 'palette.shadows.none', options: SHADOW_SCALE_OPTIONS },
491
491
  ],
492
492
  };
@@ -166,6 +166,8 @@ export interface ComponentTokenSet {
166
166
  margin?: TokenReference<'spacing'>;
167
167
  shadow?: TokenReference<'shadow'>;
168
168
  opacity?: number;
169
+ /** Hover background — used by transparent variants like `button.ghost`. */
170
+ hoverBackground?: TokenReference<'color'>;
169
171
  }
170
172
 
171
173
  export interface ButtonTokens extends ComponentTokenSet {