@helpway/react 0.2.0 → 0.3.1

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.
@@ -45,6 +45,15 @@
45
45
  .hw-widget {
46
46
  --hw-primary: #171717;
47
47
  --hw-primary-hover: #2a2a2a;
48
+ /* Brand surface used by team-avatar fallbacks and primary CTAs.
49
+ In light mode this is the host brand color (default near-black).
50
+ Dark overrides redefine to a high-contrast value so the brand tile
51
+ stays visible on dark surfaces. Customers override --hw-brand to
52
+ theme team avatars + primary CTAs in one shot. */
53
+ --hw-brand: #171717;
54
+ /* Foreground (text/svg) that sits on --hw-brand. Inverts in dark so
55
+ light-on-light never happens after the brand-token flip. */
56
+ --hw-on-brand: #ffffff;
48
57
  /* Focus ring tokens — used by composer + content search + any future
49
58
  input. Kept as variables so the dark override gets a proper contrast
50
59
  pair instead of a one-off per-component tweak. */
@@ -304,6 +313,20 @@
304
313
  flex-direction: column;
305
314
  overflow: hidden;
306
315
  animation: hw-window-open 0.35s cubic-bezier(0.34, 1.56, 0.64, 1);
316
+ /* Smooth size transition for reading-mode expansion. The open animation
317
+ is one-shot (transform/opacity) so it doesn't conflict with this. */
318
+ transition:
319
+ width 280ms cubic-bezier(0.4, 0, 0.2, 1),
320
+ height 280ms cubic-bezier(0.4, 0, 0.2, 1);
321
+ }
322
+
323
+ /* Reading mode — applied when the visitor enters a content detail view
324
+ (help article, changelog entry). Wider + taller for comfortable long-form
325
+ reading. Mobile (<480px) ignores this — the @media block forces 100% +
326
+ beats this rule by source order. */
327
+ .hw-window--reading {
328
+ width: min(720px, calc(100vw - 40px));
329
+ height: min(800px, calc(100vh - 100px));
307
330
  }
308
331
 
309
332
  @keyframes hw-window-open {
@@ -534,6 +557,20 @@
534
557
  width: 24px;
535
558
  height: 24px;
536
559
  }
560
+ .hw-header-bot-icon--team {
561
+ background: var(--hw-brand, #0a0a0a);
562
+ color: var(--hw-on-brand, #fff);
563
+ }
564
+ .hw-header-agent-img {
565
+ width: 100%;
566
+ height: 100%;
567
+ object-fit: cover;
568
+ }
569
+ .hw-header-agent-initials {
570
+ font-size: 11px;
571
+ font-weight: 600;
572
+ line-height: 1;
573
+ }
537
574
 
538
575
  .hw-header-info {
539
576
  flex: 1;
@@ -886,6 +923,21 @@
886
923
  width: 20px;
887
924
  height: 20px;
888
925
  }
926
+ .hw-conv-card-avatar-img {
927
+ width: 100%;
928
+ height: 100%;
929
+ object-fit: cover;
930
+ }
931
+ .hw-conv-card-avatar--team {
932
+ background: var(--hw-brand, #0a0a0a);
933
+ color: var(--hw-on-brand, #fff);
934
+ }
935
+ .hw-conv-card-avatar-initials {
936
+ font-size: 12px;
937
+ font-weight: 600;
938
+ line-height: 1;
939
+ letter-spacing: 0.02em;
940
+ }
889
941
 
890
942
  .hw-conv-card-content {
891
943
  flex: 1;
@@ -1086,6 +1138,43 @@
1086
1138
  /* Flex column with constrained children — min-width:0 allows children to
1087
1139
  honor their own max-width rather than inflating to content width. */
1088
1140
  min-width: 0;
1141
+ scrollbar-color: rgba(0, 0, 0, 0.2) transparent;
1142
+ scrollbar-width: thin;
1143
+ }
1144
+
1145
+ .hw-messages::-webkit-scrollbar {
1146
+ width: 10px;
1147
+ height: 10px;
1148
+ }
1149
+
1150
+ .hw-messages::-webkit-scrollbar-track {
1151
+ background: transparent;
1152
+ }
1153
+
1154
+ .hw-messages::-webkit-scrollbar-thumb {
1155
+ background: rgba(0, 0, 0, 0.16);
1156
+ background-clip: content-box;
1157
+ border: 3px solid transparent;
1158
+ border-radius: 999px;
1159
+ }
1160
+
1161
+ .hw-messages::-webkit-scrollbar-thumb:hover {
1162
+ background: rgba(0, 0, 0, 0.28);
1163
+ background-clip: content-box;
1164
+ }
1165
+
1166
+ .hw-widget[data-theme="dark"] .hw-messages {
1167
+ scrollbar-color: rgba(255, 255, 255, 0.26) transparent;
1168
+ }
1169
+
1170
+ .hw-widget[data-theme="dark"] .hw-messages::-webkit-scrollbar-thumb {
1171
+ background: rgba(255, 255, 255, 0.2);
1172
+ background-clip: content-box;
1173
+ }
1174
+
1175
+ .hw-widget[data-theme="dark"] .hw-messages::-webkit-scrollbar-thumb:hover {
1176
+ background: rgba(255, 255, 255, 0.32);
1177
+ background-clip: content-box;
1089
1178
  }
1090
1179
 
1091
1180
  /* ── Empty Messages ─────────────────────────── */
@@ -1107,6 +1196,11 @@
1107
1196
  opacity: 0.3;
1108
1197
  }
1109
1198
 
1199
+ .hw-empty-text {
1200
+ font-size: 13px;
1201
+ /* color inherited from .hw-empty (--hw-text-3) — adapts in dark */
1202
+ }
1203
+
1110
1204
  /* ── Date Separator ──────────────────────────── */
1111
1205
  .hw-date-sep {
1112
1206
  display: flex;
@@ -1164,6 +1258,11 @@
1164
1258
  align-self: flex-start;
1165
1259
  }
1166
1260
 
1261
+ .hw-msg--ai {
1262
+ width: 100%;
1263
+ max-width: 100%;
1264
+ }
1265
+
1167
1266
  .hw-msg-body {
1168
1267
  display: flex;
1169
1268
  flex-direction: column;
@@ -1206,22 +1305,51 @@
1206
1305
  color: var(--hw-text);
1207
1306
  border-bottom-left-radius: 4px;
1208
1307
  white-space: normal; /* AI messages use HTML rendering (markdown), not pre-wrap */
1308
+ max-width: min(100%, 640px);
1209
1309
  }
1210
1310
 
1211
- /* Meta (time + sender label) — hidden, show on hover */
1311
+ .hw-msg--ai .hw-msg-body {
1312
+ width: 100%;
1313
+ }
1314
+
1315
+ .hw-msg--ai .hw-msg-bubble:has(.hw-code),
1316
+ .hw-msg--ai .hw-msg-bubble:has(pre) {
1317
+ width: 100%;
1318
+ }
1319
+
1320
+ .hw-msg--ai .hw-code {
1321
+ width: 100%;
1322
+ box-sizing: border-box;
1323
+ }
1324
+
1325
+ /* Meta (fully hidden; sender label + copy icon reveal on hover) */
1212
1326
  .hw-msg-meta {
1327
+ display: inline-flex;
1328
+ align-items: center;
1329
+ gap: 4px;
1213
1330
  font-size: 11px;
1214
1331
  color: var(--hw-text-3);
1215
1332
  margin-top: 3px;
1216
1333
  padding: 0 4px;
1217
1334
  opacity: 0;
1218
- transition: opacity 0.15s;
1219
1335
  font-variant-numeric: tabular-nums;
1336
+ min-height: 0;
1337
+ height: 0;
1338
+ overflow: hidden;
1339
+ transition:
1340
+ opacity 140ms ease,
1341
+ height 140ms ease;
1220
1342
  }
1221
1343
 
1222
1344
  .hw-msg:hover .hw-msg-meta,
1223
1345
  .hw-msg:focus-within .hw-msg-meta {
1224
1346
  opacity: 1;
1347
+ height: 20px;
1348
+ min-height: 20px;
1349
+ }
1350
+
1351
+ .hw-msg-sender-label {
1352
+ white-space: nowrap;
1225
1353
  }
1226
1354
 
1227
1355
  .hw-msg--visitor .hw-msg-meta {
@@ -1452,6 +1580,59 @@
1452
1580
  background: var(--hw-bg);
1453
1581
  }
1454
1582
 
1583
+ /* ── Skeleton: Article detail ──────────────────
1584
+ Designed to be PIXEL-EQUIVALENT to the rendered article so content can land
1585
+ without reflow. Maps 1:1 to:
1586
+ <div class="hw-content-detail">
1587
+ <div class="hw-content-detail-header"> ← title (22px line) + meta row
1588
+ <div class="hw-content-detail-body">
1589
+ <div class="hw-markdown">
1590
+ <h2>...</h2> ← section header (~16px line)
1591
+ <ul><li>**Bold:** desc...</li></ul> ← bullet item, 2 visible lines
1592
+ <ul><li>...</li></ul>
1593
+ The skeleton uses the SAME outer classes for padding/spacing, then injects
1594
+ shimmer bars where text would render. */
1595
+
1596
+ .hw-skeleton-title {
1597
+ height: 22px;
1598
+ width: 65%;
1599
+ border-radius: 6px;
1600
+ }
1601
+
1602
+ .hw-skeleton-badge {
1603
+ width: 42px;
1604
+ height: 18px;
1605
+ border-radius: 9px;
1606
+ }
1607
+
1608
+ .hw-skeleton-date {
1609
+ width: 60px;
1610
+ height: 12px;
1611
+ border-radius: 6px;
1612
+ }
1613
+
1614
+ .hw-skeleton-h2 {
1615
+ height: 16px;
1616
+ border-radius: 6px;
1617
+ }
1618
+
1619
+ /* Bullet wrapper — emulates <ul> padding-left: 20px so the skeleton bullet
1620
+ text starts at the same x-coordinate as the real <li>'s text content. */
1621
+ .hw-skeleton-bullet {
1622
+ padding-left: 20px;
1623
+ display: flex;
1624
+ flex-direction: column;
1625
+ gap: 8px;
1626
+ }
1627
+
1628
+ /* Each "line" inside a bullet — line-height: 14 matches the visible text mass
1629
+ of body text (font-size 14 × line-height 1.6 = 22.4 visible bbox, but skeleton
1630
+ bar is the visible-character thickness only). */
1631
+ .hw-skeleton-bullet-line {
1632
+ height: 14px;
1633
+ border-radius: 7px;
1634
+ }
1635
+
1455
1636
  /* ════════════════════════════════════════════════
1456
1637
  EMAIL COLLECTION CARD (fixed above composer)
1457
1638
  ════════════════════════════════════════════════ */
@@ -1461,7 +1642,7 @@
1461
1642
  padding: 14px 16px 10px;
1462
1643
  border: 1px solid var(--hw-border, rgba(0,0,0,0.08));
1463
1644
  border-radius: 14px;
1464
- background: var(--hw-surface, #fff);
1645
+ background: var(--hw-bg, #fff);
1465
1646
  box-shadow: 0 1px 4px rgba(0,0,0,0.06), 0 4px 12px rgba(0,0,0,0.03);
1466
1647
  animation: hw-email-slide-in 0.25s ease-out;
1467
1648
  }
@@ -1483,11 +1664,11 @@
1483
1664
  width: 32px;
1484
1665
  height: 32px;
1485
1666
  border-radius: 8px;
1486
- background: var(--hw-brand, #0a0a0a);
1667
+ background: var(--hw-bg-hover, #f5f5f5);
1487
1668
  display: flex;
1488
1669
  align-items: center;
1489
1670
  justify-content: center;
1490
- color: #fff;
1671
+ color: var(--hw-text, #1a1a1a);
1491
1672
  }
1492
1673
 
1493
1674
  .hw-email-card-title {
@@ -1500,7 +1681,7 @@
1500
1681
 
1501
1682
  .hw-email-card-subtitle {
1502
1683
  font-size: 12px;
1503
- color: var(--hw-text-muted, #888);
1684
+ color: var(--hw-text-2, #888);
1504
1685
  line-height: 1.4;
1505
1686
  margin: 0;
1506
1687
  }
@@ -1510,18 +1691,22 @@
1510
1691
  padding: 9px 12px;
1511
1692
  border-radius: 10px;
1512
1693
  border: 1px solid var(--hw-border, rgba(0,0,0,0.1));
1513
- background: var(--hw-bg, #fafafa);
1694
+ background: var(--hw-bg-subtle, #fafafa);
1514
1695
  color: var(--hw-text, #1a1a1a);
1515
1696
  font-size: 13px;
1516
1697
  outline: none;
1517
1698
  margin-bottom: 8px;
1518
1699
  box-sizing: border-box;
1519
- transition: border-color 0.15s;
1700
+ transition: border-color 0.15s, box-shadow 0.15s;
1701
+ }
1702
+
1703
+ .hw-email-card-input::placeholder {
1704
+ color: var(--hw-text-3, #999);
1520
1705
  }
1521
1706
 
1522
1707
  .hw-email-card-input:focus {
1523
- border-color: var(--hw-brand, #0a0a0a);
1524
- box-shadow: 0 0 0 2px rgba(0,0,0,0.06);
1708
+ border-color: var(--hw-focus-border, rgba(0,0,0,0.2));
1709
+ box-shadow: 0 0 0 2px var(--hw-focus-ring, rgba(0,0,0,0.06));
1525
1710
  }
1526
1711
 
1527
1712
  .hw-email-card-input--error {
@@ -1534,7 +1719,7 @@
1534
1719
  border-radius: 10px;
1535
1720
  border: none;
1536
1721
  background: var(--hw-brand, #0a0a0a);
1537
- color: #fff;
1722
+ color: var(--hw-on-brand, #fff);
1538
1723
  font-size: 13px;
1539
1724
  font-weight: 500;
1540
1725
  cursor: pointer;
@@ -1561,7 +1746,7 @@
1561
1746
  gap: 6px;
1562
1747
  padding: 10px 16px;
1563
1748
  font-size: 13px;
1564
- color: var(--hw-text-muted, #888);
1749
+ color: var(--hw-text-2, #888);
1565
1750
  animation: hw-email-slide-in 0.2s ease-out;
1566
1751
  }
1567
1752
 
@@ -2055,8 +2240,8 @@
2055
2240
  width: 32px;
2056
2241
  height: 32px;
2057
2242
  border-radius: 50%;
2058
- background: #e0e0e0;
2059
- color: #555;
2243
+ background: var(--hw-bg-hover, #e0e0e0);
2244
+ color: var(--hw-text-2, #555);
2060
2245
  display: flex;
2061
2246
  align-items: center;
2062
2247
  justify-content: center;
@@ -2260,6 +2445,9 @@
2260
2445
  .hw-msg {
2261
2446
  max-width: 82%;
2262
2447
  }
2448
+ .hw-msg--ai {
2449
+ max-width: 100%;
2450
+ }
2263
2451
  }
2264
2452
 
2265
2453
  /* ════════════════════════════════════════════════
@@ -2578,31 +2766,92 @@
2578
2766
  color: var(--hw-text-1);
2579
2767
  }
2580
2768
 
2581
- /* ── Markdown Rendering ────────────────────────────────── */
2769
+ /* ── Markdown Rendering ──────────────────────────────────
2770
+ Heading vertical spacing is governed by the adjacency rules further
2771
+ down (.hw-markdown > * + h2, etc.). Keeping margin: 0 here prevents
2772
+ the heading's own bottom margin from compounding with the sibling's
2773
+ top margin (e.g. h2 8px + p 12px = 20px instead of 12px). */
2582
2774
  .hw-markdown h1 {
2583
2775
  font-size: 17px;
2584
2776
  font-weight: 700;
2585
- margin: 20px 0 8px;
2777
+ margin: 0;
2586
2778
  }
2587
2779
 
2588
2780
  .hw-markdown h2 {
2589
2781
  font-size: 15px;
2590
2782
  font-weight: 600;
2591
- margin: 16px 0 6px;
2783
+ margin: 0;
2592
2784
  }
2593
2785
 
2594
2786
  .hw-markdown h3 {
2595
2787
  font-size: 14px;
2596
2788
  font-weight: 600;
2597
- margin: 12px 0 4px;
2789
+ margin: 0;
2598
2790
  }
2599
2791
 
2600
2792
  .hw-markdown p {
2601
- margin: 0 0 12px;
2793
+ margin: 0;
2794
+ }
2795
+
2796
+ /* Rich-text editors (PlateJS, Slate, ProseMirror) emit any of:
2797
+ <p><br></p> ← visual line break paragraph
2798
+ <p></p> ← empty paragraph
2799
+ <div><br></div> ← editor block element (PlateJS default)
2800
+ <div></div> ← empty block
2801
+ Each contributes line-height + margin twice → 50-70px gap between items.
2802
+ Hide them all so spacing is governed by the adjacency rules below. */
2803
+ .hw-markdown p:empty,
2804
+ .hw-markdown div:empty,
2805
+ .hw-markdown p:has(> br:only-child),
2806
+ .hw-markdown div:has(> br:only-child) {
2807
+ display: none;
2808
+ }
2809
+
2810
+ /* Adjacency-based spacing — works for any block element type the CMS emits
2811
+ (<p>, <div>, custom). Combined with the JS post-render cleanup in
2812
+ simple-markdown.tsx (which strips whitespace-only blocks like <p>&nbsp;</p>
2813
+ that CSS :empty can't match), this gives consistent spacing regardless of
2814
+ editor format. */
2815
+ .hw-markdown > * + * {
2816
+ margin-top: 12px;
2817
+ }
2818
+
2819
+ .hw-markdown > * + h1,
2820
+ .hw-markdown > * + h2 {
2821
+ margin-top: 20px;
2822
+ }
2823
+
2824
+ .hw-markdown > * + h3 {
2825
+ margin-top: 16px;
2826
+ }
2827
+
2828
+ .hw-markdown > h1 + *,
2829
+ .hw-markdown > h2 + *,
2830
+ .hw-markdown > h3 + * {
2831
+ margin-top: 8px;
2832
+ }
2833
+
2834
+ /* First/last child margin reset so the body's outer padding is the only
2835
+ spacing that surrounds the article. */
2836
+ .hw-markdown > *:first-child {
2837
+ margin-top: 0;
2838
+ }
2839
+
2840
+ .hw-markdown > *:last-child {
2841
+ margin-bottom: 0;
2842
+ }
2843
+
2844
+ /* Better i18n CMS emits standalone <br> elements at the markdown root as
2845
+ visual separators between consecutive <ul> bullet groups. Each <br>
2846
+ contributed ~22px line-height + adjacency margins on both sides, creating
2847
+ the 40-50px gap between items. Hide them — the adjacency rule alone gives
2848
+ the 12px gap we want. */
2849
+ .hw-markdown > br {
2850
+ display: none;
2602
2851
  }
2603
2852
 
2604
2853
  .hw-markdown ul {
2605
- margin: 0 0 12px;
2854
+ margin: 0;
2606
2855
  padding-left: 20px;
2607
2856
  }
2608
2857
 
@@ -2635,7 +2884,8 @@
2635
2884
  display: flex;
2636
2885
  align-items: center;
2637
2886
  justify-content: space-between;
2638
- padding: 6px 12px;
2887
+ gap: 10px;
2888
+ padding: 7px 8px 7px 12px;
2639
2889
  font-size: 11px;
2640
2890
  color: var(--hw-text-2, #6b7280);
2641
2891
  background: rgba(0, 0, 0, 0.03);
@@ -2648,24 +2898,85 @@
2648
2898
  font-weight: 500;
2649
2899
  }
2650
2900
 
2651
- .hw-code-copy {
2901
+ .hw-code-actions {
2652
2902
  display: inline-flex;
2653
2903
  align-items: center;
2654
- gap: 4px;
2655
- padding: 2px 8px;
2656
- font-size: 11px;
2904
+ gap: 1px;
2905
+ }
2906
+
2907
+ .hw-code-action {
2908
+ position: relative;
2909
+ display: inline-flex;
2910
+ align-items: center;
2911
+ justify-content: center;
2912
+ width: 22px;
2913
+ height: 22px;
2914
+ padding: 0;
2657
2915
  font-family: inherit;
2658
2916
  color: var(--hw-text-2, #6b7280);
2659
2917
  background: transparent;
2660
2918
  border: 1px solid transparent;
2661
- border-radius: 5px;
2919
+ border-radius: 6px;
2662
2920
  cursor: pointer;
2663
- transition: background 120ms ease, color 120ms ease;
2921
+ opacity: 0.62;
2922
+ transition:
2923
+ background 120ms ease,
2924
+ color 120ms ease,
2925
+ opacity 120ms ease,
2926
+ scale 120ms ease;
2664
2927
  }
2665
2928
 
2666
- .hw-code-copy:hover {
2929
+ .hw-code-action:hover {
2667
2930
  color: var(--hw-text, #111);
2668
2931
  background: rgba(0, 0, 0, 0.06);
2932
+ opacity: 1;
2933
+ }
2934
+
2935
+ .hw-code-action:active {
2936
+ scale: 0.96;
2937
+ }
2938
+
2939
+ .hw-code-action svg {
2940
+ width: 13px;
2941
+ height: 13px;
2942
+ }
2943
+
2944
+ .hw-code-copy-icon,
2945
+ .hw-code-check-icon {
2946
+ position: absolute;
2947
+ inset: 50% auto auto 50%;
2948
+ transition:
2949
+ opacity 180ms cubic-bezier(0.2, 0, 0, 1),
2950
+ scale 180ms cubic-bezier(0.2, 0, 0, 1),
2951
+ filter 180ms cubic-bezier(0.2, 0, 0, 1);
2952
+ translate: -50% -50%;
2953
+ }
2954
+
2955
+ .hw-code-check-icon {
2956
+ filter: blur(4px);
2957
+ opacity: 0;
2958
+ scale: 0.25;
2959
+ }
2960
+
2961
+ .hw-code-copy--copied .hw-code-copy-icon {
2962
+ filter: blur(4px);
2963
+ opacity: 0;
2964
+ scale: 0.25;
2965
+ }
2966
+
2967
+ .hw-code-copy--copied .hw-code-check-icon {
2968
+ filter: blur(0);
2969
+ opacity: 1;
2970
+ scale: 1;
2971
+ }
2972
+
2973
+ .hw-code-copy-label {
2974
+ position: absolute;
2975
+ width: 1px;
2976
+ height: 1px;
2977
+ overflow: hidden;
2978
+ clip: rect(0, 0, 0, 0);
2979
+ white-space: nowrap;
2669
2980
  }
2670
2981
 
2671
2982
  .hw-code-copy--copied {
@@ -2683,6 +2994,30 @@
2683
2994
  border-radius: 0;
2684
2995
  overflow-x: auto;
2685
2996
  max-width: 100%;
2997
+ max-height: 320px;
2998
+ scrollbar-color: rgba(0, 0, 0, 0.22) transparent;
2999
+ scrollbar-width: thin;
3000
+ }
3001
+
3002
+ .hw-code pre::-webkit-scrollbar {
3003
+ width: 10px;
3004
+ height: 10px;
3005
+ }
3006
+
3007
+ .hw-code pre::-webkit-scrollbar-track {
3008
+ background: transparent;
3009
+ }
3010
+
3011
+ .hw-code pre::-webkit-scrollbar-thumb {
3012
+ background: rgba(0, 0, 0, 0.18);
3013
+ background-clip: content-box;
3014
+ border: 3px solid transparent;
3015
+ border-radius: 999px;
3016
+ }
3017
+
3018
+ .hw-code pre::-webkit-scrollbar-thumb:hover {
3019
+ background: rgba(0, 0, 0, 0.28);
3020
+ background-clip: content-box;
2686
3021
  }
2687
3022
 
2688
3023
  .hw-code pre code {
@@ -2707,9 +3042,21 @@
2707
3042
  background: rgba(255, 255, 255, 0.03);
2708
3043
  border-bottom-color: rgba(255, 255, 255, 0.06);
2709
3044
  }
2710
- .hw-code-copy:hover {
3045
+ .hw-code-action:hover,
3046
+ .hw-code-action:focus-visible {
2711
3047
  background: rgba(255, 255, 255, 0.08);
2712
3048
  }
3049
+ .hw-code pre {
3050
+ scrollbar-color: rgba(255, 255, 255, 0.26) transparent;
3051
+ }
3052
+ .hw-code pre::-webkit-scrollbar-thumb {
3053
+ background: rgba(255, 255, 255, 0.22);
3054
+ background-clip: content-box;
3055
+ }
3056
+ .hw-code pre::-webkit-scrollbar-thumb:hover {
3057
+ background: rgba(255, 255, 255, 0.32);
3058
+ background-clip: content-box;
3059
+ }
2713
3060
  }
2714
3061
 
2715
3062
  /* Legacy bare <pre> fallback (rendered by old CMS bodyHtml content that may
@@ -2755,6 +3102,20 @@
2755
3102
  white-space: pre;
2756
3103
  }
2757
3104
 
3105
+ .hw-msg-bubble .hw-code pre {
3106
+ margin: 0;
3107
+ padding: 10px 12px;
3108
+ background: transparent;
3109
+ border-radius: 0;
3110
+ }
3111
+
3112
+ .hw-msg-bubble .hw-code pre code {
3113
+ background: transparent;
3114
+ padding: 0;
3115
+ font-size: 12px;
3116
+ line-height: 1.55;
3117
+ }
3118
+
2758
3119
  .hw-msg--team .hw-msg-bubble pre,
2759
3120
  .hw-msg--visitor .hw-msg-bubble pre {
2760
3121
  background: rgba(255, 255, 255, 0.12);
@@ -2850,6 +3211,12 @@
2850
3211
  }
2851
3212
  .hw-msg-meta {
2852
3213
  opacity: 1;
3214
+ height: auto;
3215
+ min-height: 20px;
3216
+ overflow: visible;
3217
+ }
3218
+ .hw-msg-copy {
3219
+ opacity: 1;
2853
3220
  }
2854
3221
  }
2855
3222
 
@@ -2909,11 +3276,20 @@
2909
3276
  color: var(--hw-text-4);
2910
3277
  cursor: pointer;
2911
3278
  vertical-align: middle;
2912
- transition: color 0.15s, background 0.15s;
3279
+ opacity: 0;
3280
+ transition:
3281
+ color 0.15s,
3282
+ background 0.15s,
3283
+ opacity 0.15s;
2913
3284
  padding: 0;
2914
3285
  flex-shrink: 0;
2915
3286
  }
2916
3287
 
3288
+ .hw-msg:hover .hw-msg-copy,
3289
+ .hw-msg:focus-within .hw-msg-copy {
3290
+ opacity: 1;
3291
+ }
3292
+
2917
3293
  .hw-msg-copy:hover {
2918
3294
  background: var(--hw-bg-hover);
2919
3295
  color: var(--hw-text-2);
@@ -3293,9 +3669,27 @@
3293
3669
  --hw-visitor-bubble-text: #f5f5f5;
3294
3670
  --hw-focus-border: rgba(255, 255, 255, 0.28);
3295
3671
  --hw-focus-ring: rgba(255, 255, 255, 0.08);
3672
+ /* Brand inverts in dark — light tile on dark surface keeps team avatars
3673
+ and primary CTAs readable. Same pattern as iOS dark mode tints. */
3674
+ --hw-brand: #f5f5f5;
3675
+ --hw-on-brand: #1c1c1e;
3296
3676
  }
3297
3677
 
3298
3678
  @media (prefers-color-scheme: dark) {
3679
+ .hw-widget:not([data-theme="light"]) .hw-messages {
3680
+ scrollbar-color: rgba(255, 255, 255, 0.26) transparent;
3681
+ }
3682
+
3683
+ .hw-widget:not([data-theme="light"]) .hw-messages::-webkit-scrollbar-thumb {
3684
+ background: rgba(255, 255, 255, 0.2);
3685
+ background-clip: content-box;
3686
+ }
3687
+
3688
+ .hw-widget:not([data-theme="light"]) .hw-messages::-webkit-scrollbar-thumb:hover {
3689
+ background: rgba(255, 255, 255, 0.32);
3690
+ background-clip: content-box;
3691
+ }
3692
+
3299
3693
  .hw-widget:not([data-theme="light"]) {
3300
3694
  --hw-bg: #1c1c1e;
3301
3695
  --hw-bg-subtle: #161618;
@@ -3315,6 +3709,9 @@
3315
3709
  /* Focus ring in dark needs lighter border + subtle halo. */
3316
3710
  --hw-focus-border: rgba(255, 255, 255, 0.28);
3317
3711
  --hw-focus-ring: rgba(255, 255, 255, 0.08);
3712
+ /* See --hw-brand comment in [data-theme="dark"] block. */
3713
+ --hw-brand: #f5f5f5;
3714
+ --hw-on-brand: #1c1c1e;
3318
3715
  }
3319
3716
  }
3320
3717