@quilltap/theme-storybook 1.0.95 → 1.0.97

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.
@@ -1057,13 +1057,11 @@
1057
1057
 
1058
1058
  /**
1059
1059
  * NanoGPT provider badge (primary/accent semantic)
1060
- * Same border quirk as the ollama badge: --qt-badge-primary-border has no
1061
- * default definition.
1062
1060
  */
1063
1061
  .qt-badge-provider-nanogpt {
1064
1062
  background: var(--qt-badge-primary-bg);
1065
1063
  color: var(--qt-badge-primary-fg);
1066
- border: 1px solid var(--qt-badge-primary-border);
1064
+ border: 1px solid var(--qt-badge-primary-border, var(--color-primary));
1067
1065
  }
1068
1066
 
1069
1067
  /**
@@ -1416,1211 +1414,2701 @@
1416
1414
  }
1417
1415
 
1418
1416
  /* ==========================================================================
1419
- BRAHMA CONSOLE LAUNCHER - The always-on button beside the left rail
1420
- Sits in the topmost floating layer so it stays reachable over any modal.
1417
+ HELP CHAT - Message bubbles, composer, and UI elements
1418
+ Used by the contextual help chat system
1421
1419
  ========================================================================== */
1422
1420
 
1423
- .qt-brahma-launcher {
1424
- position: fixed;
1425
- left: calc(var(--qt-left-sidebar-collapsed-width) + var(--qt-brahma-launcher-offset));
1426
- bottom: var(--qt-brahma-launcher-offset);
1427
- z-index: var(--qt-floating-layer-z);
1428
- width: var(--qt-brahma-launcher-size);
1429
- height: var(--qt-brahma-launcher-size);
1430
- display: inline-flex;
1431
- align-items: center;
1432
- justify-content: center;
1433
- border-radius: 9999px;
1434
- background: var(--qt-brahma-launcher-bg);
1435
- color: var(--qt-brahma-launcher-fg);
1436
- border: 2px solid var(--qt-brahma-launcher-ring);
1437
- box-shadow: var(--qt-brahma-launcher-shadow);
1438
- transition: background-color 150ms ease, color 150ms ease, transform 150ms ease;
1439
- }
1440
-
1441
- .qt-brahma-launcher:hover {
1442
- background: var(--qt-brahma-launcher-hover-bg);
1443
- transform: scale(1.06);
1421
+ /**
1422
+ * Help chat message bubble — user messages
1423
+ */
1424
+ .qt-help-msg-user {
1425
+ border-radius: 1rem;
1426
+ padding-left: 0.75rem;
1427
+ padding-right: 0.75rem;
1428
+ padding-top: 0.5rem;
1429
+ padding-bottom: 0.375rem;
1430
+ font-size: 0.875rem;
1431
+ line-height: 1.25rem;
1432
+ background-color: var(--color-primary);
1433
+ color: var(--color-primary-foreground);
1434
+ max-width: 80%;
1444
1435
  }
1445
1436
 
1446
- .qt-brahma-launcher:focus-visible {
1447
- outline: 2px solid var(--qt-brahma-launcher-ring);
1448
- outline-offset: 3px;
1437
+ .qt-help-msg-user :last-child,
1438
+ .qt-help-msg-assistant :last-child {
1439
+ margin-bottom: 0 !important;
1440
+ padding-bottom: 0 !important;
1449
1441
  }
1450
1442
 
1451
- .qt-brahma-launcher-active,
1452
- .qt-brahma-launcher-active:hover {
1453
- background: var(--qt-brahma-launcher-active-bg);
1454
- color: var(--qt-brahma-launcher-active-fg);
1443
+ /**
1444
+ * User bubbles render markdown through MessageContent, whose `.qt-prose-auto`
1445
+ * pins `--tw-prose-body` to the global foreground in dark themes. Left alone,
1446
+ * that prose colour overrides the bubble's `text-primary-foreground`, leaving
1447
+ * light prose on the primary fill — unreadable in dark themes such as
1448
+ * Madman's Box. Pin the prose body (and plain text) back to the primary
1449
+ * foreground, mirroring the Salon's user-bubble treatment.
1450
+ */
1451
+ .qt-help-msg-user .qt-chat-message-content {
1452
+ --tw-prose-body: var(--color-primary-foreground);
1453
+ --tw-prose-invert-body: var(--color-primary-foreground);
1454
+ color: var(--color-primary-foreground);
1455
1455
  }
1456
1456
 
1457
- .qt-brahma-launcher-icon {
1458
- width: 60%;
1459
- height: 60%;
1457
+ /**
1458
+ * Help chat message bubble — assistant messages
1459
+ */
1460
+ .qt-help-msg-assistant {
1461
+ border-radius: 1rem;
1462
+ padding-left: 0.75rem;
1463
+ padding-right: 0.75rem;
1464
+ padding-top: 0.5rem;
1465
+ padding-bottom: 0.5rem;
1466
+ font-size: 0.875rem;
1467
+ line-height: 1.25rem;
1468
+ background-color: var(--color-muted);
1469
+ color: var(--color-foreground);
1470
+ max-width: 80%;
1460
1471
  }
1461
1472
 
1462
- /* ==========================================================================
1463
- SLIDE-OVER PANELS
1464
- ========================================================================== */
1465
-
1466
- .qt-slide-over-overlay {
1467
- position: fixed;
1468
- inset: 0;
1469
- z-index: 55;
1470
- background-color: var(--qt-dialog-backdrop);
1471
- opacity: 0;
1472
- transition: opacity 200ms ease;
1473
- pointer-events: none;
1473
+ /**
1474
+ * Help chat bubble tail — triangular pointer toward sender
1475
+ */
1476
+ .qt-help-tail {
1477
+ flex-shrink: 0;
1478
+ width: 8px;
1479
+ height: 12px;
1480
+ align-self: flex-start;
1481
+ margin-top: 12px;
1474
1482
  }
1475
1483
 
1476
- .qt-slide-over-overlay[data-open="true"] {
1477
- opacity: 1;
1478
- pointer-events: auto;
1484
+ .qt-help-tail-user {
1485
+ color: var(--theme-primary);
1479
1486
  }
1480
1487
 
1481
- .qt-slide-over-panel {
1482
- position: fixed;
1483
- right: 0;
1484
- top: 0;
1485
- z-index: 55;
1486
- height: 100%;
1487
- display: flex;
1488
- flex-direction: column;
1489
- background-color: var(--qt-dialog-bg);
1490
- border-left: 1px solid var(--qt-dialog-border);
1491
- box-shadow: var(--qt-dialog-shadow);
1492
- transform: translateX(100%);
1493
- transition: transform 200ms cubic-bezier(0.4, 0, 0.2, 1);
1488
+ .qt-help-tail-assistant {
1489
+ color: var(--theme-muted);
1494
1490
  }
1495
1491
 
1496
- .qt-slide-over-panel[data-open="true"] {
1497
- transform: translateX(0);
1492
+ /**
1493
+ * Help chat message character name label
1494
+ */
1495
+ .qt-help-msg-character-name {
1496
+ font-size: 0.75rem;
1497
+ line-height: 1rem;
1498
+ font-weight: 500;
1499
+ color: var(--color-muted-foreground);
1500
+ margin-bottom: 0.25rem;
1498
1501
  }
1499
1502
 
1500
- .qt-slide-over-header {
1503
+ /**
1504
+ * Help chat avatar — small circular avatar in message list
1505
+ */
1506
+ .qt-help-avatar {
1507
+ flex-shrink: 0;
1508
+ width: 2rem;
1509
+ height: 2rem;
1510
+ border-radius: 9999px;
1511
+ background-color: var(--color-muted);
1501
1512
  display: flex;
1502
1513
  align-items: center;
1503
- justify-content: space-between;
1504
- padding: 0.75rem 1rem;
1505
- flex-shrink: 0;
1506
- border-bottom: 1px solid var(--qt-dialog-border);
1507
- }
1508
-
1509
- .qt-inspector-entry {
1510
- transition: all 150ms ease;
1511
- border-radius: var(--qt-card-radius);
1512
- background: var(--qt-card-bg);
1513
- border: 1px solid color-mix(in srgb, var(--qt-card-border) calc(var(--qt-card-border-opacity, 1) * 100%), transparent);
1514
+ justify-content: center;
1515
+ overflow: hidden;
1516
+ margin-top: 2px;
1517
+ margin-right: 4px;
1514
1518
  }
1515
1519
 
1516
- .qt-inspector-entry:hover {
1517
- border-color: color-mix(in srgb, var(--color-primary) 30%, transparent);
1520
+ /**
1521
+ * Help chat composer — input area at bottom
1522
+ */
1523
+ .qt-help-composer {
1524
+ display: flex;
1525
+ align-items: flex-end;
1526
+ gap: 0.5rem;
1527
+ padding: 0.75rem;
1528
+ border-top: 1px solid var(--qt-dialog-border);
1529
+ background: var(--qt-dialog-bg);
1518
1530
  }
1519
1531
 
1520
- .qt-inspector-entry-highlight {
1521
- animation: qt-inspector-highlight 2s ease-out;
1532
+ .qt-help-composer-input {
1533
+ flex: 1 1 0%;
1534
+ resize: none;
1535
+ border-radius: var(--radius-lg);
1536
+ padding-left: 0.75rem;
1537
+ padding-right: 0.75rem;
1538
+ padding-top: 0.5rem;
1539
+ padding-bottom: 0.5rem;
1540
+ font-size: 0.875rem;
1541
+ line-height: 1.25rem;
1542
+ border: 1px solid var(--qt-input-border, var(--color-input));
1543
+ background: var(--qt-input-bg, var(--color-background));
1522
1544
  }
1523
1545
 
1524
- @keyframes qt-inspector-highlight {
1525
- 0% {
1526
- box-shadow: 0 0 0 2px color-mix(in srgb, var(--color-primary) 60%, transparent);
1527
- }
1528
- 100% {
1529
- box-shadow: 0 0 0 0px transparent;
1530
- }
1546
+ .qt-help-composer-input::placeholder {
1547
+ color: var(--color-muted-foreground);
1531
1548
  }
1532
1549
 
1533
- /* ==========================================================================
1534
- TAB COMPONENTS
1535
- ========================================================================== */
1536
-
1537
- .qt-tab-group {
1538
- display: flex;
1539
- gap: var(--qt-tab-group-gap);
1540
- border-bottom: 1px solid var(--color-border);
1550
+ .qt-help-composer-input:focus-visible {
1551
+ outline-style: none;
1552
+ box-shadow: 0 0 0 2px var(--color-ring);
1541
1553
  }
1542
1554
 
1543
- .qt-tab {
1544
- padding: var(--qt-tab-padding-y) var(--qt-tab-padding-x);
1545
- font-size: var(--qt-tab-font-size);
1546
- font-weight: var(--qt-tab-font-weight);
1547
- color: var(--qt-tab-fg);
1548
- background-color: var(--qt-tab-bg);
1549
- border: none;
1550
- border-radius: var(--qt-tab-radius);
1551
- cursor: pointer;
1552
- transition: all 150ms;
1555
+ .qt-help-composer-input:disabled {
1556
+ cursor: not-allowed;
1557
+ opacity: 0.5;
1553
1558
  }
1554
1559
 
1555
- .qt-tab:hover {
1556
- color: var(--color-foreground);
1560
+ .qt-help-composer-send {
1561
+ display: inline-flex;
1562
+ align-items: center;
1563
+ justify-content: center;
1564
+ border-radius: var(--radius-md);
1565
+ padding-left: 0.75rem;
1566
+ padding-right: 0.75rem;
1567
+ padding-top: 0.5rem;
1568
+ padding-bottom: 0.5rem;
1569
+ height: 38px;
1570
+ font-size: 0.875rem;
1571
+ line-height: 1.25rem;
1572
+ font-weight: 500;
1573
+ background-color: var(--color-primary);
1574
+ color: var(--color-primary-foreground);
1557
1575
  }
1558
1576
 
1559
- .qt-tab-active {
1560
- background-color: var(--qt-tab-active-bg);
1561
- color: var(--qt-tab-active-fg);
1577
+ .qt-help-composer-send:disabled {
1578
+ opacity: 0.5;
1579
+ pointer-events: none;
1562
1580
  }
1563
1581
 
1564
- .qt-tab-content {
1565
- padding: 1rem 0;
1582
+ .qt-help-composer-send:hover:not(:disabled) {
1583
+ opacity: 0.9;
1566
1584
  }
1567
1585
 
1568
- /* ==========================================================================
1569
- CHAT COMPONENTS
1570
- ========================================================================== */
1571
-
1572
- .qt-chat-message {
1573
- padding: var(--qt-chat-message-padding);
1574
- border-radius: var(--qt-chat-message-radius);
1575
- max-width: 80%;
1586
+ /**
1587
+ * Help chat character selection pill
1588
+ */
1589
+ .qt-help-char-pill {
1590
+ display: flex;
1591
+ align-items: center;
1592
+ gap: 0.375rem;
1593
+ padding-left: 0.5rem;
1594
+ padding-right: 0.5rem;
1595
+ padding-top: 0.25rem;
1596
+ padding-bottom: 0.25rem;
1597
+ border-radius: 9999px;
1598
+ font-size: 0.75rem;
1599
+ line-height: 1rem;
1600
+ transition-property: color, background-color, border-color, text-decoration-color, fill, stroke;
1601
+ transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
1602
+ transition-duration: 150ms;
1603
+ color: var(--color-muted-foreground);
1604
+ border: 1px solid var(--qt-dialog-border);
1576
1605
  }
1577
1606
 
1578
- .qt-chat-message-user {
1579
- background-color: var(--qt-chat-user-bg);
1580
- color: var(--qt-chat-user-fg);
1581
- margin-left: auto;
1607
+ .qt-help-char-pill:hover {
1608
+ border-color: var(--theme-primary);
1609
+ opacity: 0.7;
1582
1610
  }
1583
1611
 
1584
- .qt-chat-message-assistant {
1585
- background-color: var(--qt-chat-assistant-bg);
1586
- color: var(--qt-chat-assistant-fg);
1587
- border: 1px solid var(--color-border);
1612
+ .qt-help-char-pill[data-selected="true"] {
1613
+ border-color: var(--theme-primary);
1614
+ background: color-mix(in srgb, var(--theme-primary) 10%, transparent);
1615
+ color: var(--theme-primary);
1588
1616
  }
1589
1617
 
1590
1618
  /**
1591
- * Whisper message — private messages between characters, not heard by all.
1619
+ * Help chat past chat list item
1592
1620
  */
1593
- .qt-chat-message-whisper {
1594
- background: var(--qt-chat-whisper-bg);
1595
- color: var(--qt-chat-whisper-fg);
1596
- border: 2px dashed var(--qt-chat-whisper-border);
1597
- font-style: italic;
1621
+ .qt-help-past-chat {
1622
+ display: flex;
1623
+ align-items: center;
1624
+ gap: 0.5rem;
1625
+ padding-left: 0.5rem;
1626
+ padding-right: 0.5rem;
1627
+ padding-top: 0.375rem;
1628
+ padding-bottom: 0.375rem;
1629
+ border-radius: 0.25rem;
1630
+ cursor: pointer;
1598
1631
  }
1599
1632
 
1600
- .qt-chat-whisper-label {
1601
- font-size: 0.75rem;
1602
- color: var(--qt-chat-whisper-label-fg);
1603
- font-style: italic;
1604
- margin-bottom: 0.25rem;
1633
+ .qt-help-past-chat:hover {
1634
+ background: var(--color-accent);
1605
1635
  }
1606
1636
 
1607
- .qt-chat-message-whisper-overheard {
1608
- opacity: 0.6;
1637
+ /**
1638
+ * Help chat section label
1639
+ */
1640
+ .qt-help-section-label {
1641
+ font-size: 0.75rem;
1642
+ line-height: 1rem;
1643
+ font-weight: 500;
1644
+ color: var(--color-muted-foreground);
1645
+ margin-bottom: 0.5rem;
1609
1646
  }
1610
1647
 
1611
1648
  /**
1612
- * Pascal result — the outcome of a custom tool (pseudo-tool) roll, announced by
1613
- * Pascal the Croupier. The accent carries the outcome's semantic `state`.
1614
- * Built on the --qt-alert-* families, which every bundled theme defines.
1649
+ * Help chat error banner
1615
1650
  */
1616
- .qt-pascal-result {
1617
- border-left: 3px solid var(--qt-alert-info-border);
1651
+ .qt-help-error {
1618
1652
  padding-left: 0.75rem;
1653
+ padding-right: 0.75rem;
1654
+ padding-top: 0.5rem;
1655
+ padding-bottom: 0.5rem;
1656
+ font-size: 0.75rem;
1657
+ line-height: 1rem;
1658
+ background: color-mix(in srgb, var(--color-destructive) 10%, transparent);
1659
+ color: var(--color-destructive);
1660
+ border-bottom: 1px solid color-mix(in srgb, var(--color-destructive) 20%, transparent);
1619
1661
  }
1620
1662
 
1621
- .qt-pascal-result--success {
1622
- border-left-color: var(--qt-alert-success-border);
1623
- }
1624
-
1625
- .qt-pascal-result--partial {
1626
- border-left-color: var(--qt-alert-warning-border);
1627
- }
1628
-
1629
- .qt-pascal-result--failure {
1630
- border-left-color: var(--qt-alert-error-border);
1631
- }
1632
-
1633
- .qt-pascal-result--info {
1634
- border-left-color: var(--qt-alert-info-border);
1635
- }
1636
-
1637
- /* --------------------------------------------------------------------------
1638
- ANSWER-CONFIRMATION BADGE
1639
- A quiet per-message verdict marker (Vouched / Amended / Stood by /
1640
- Unvetted). The glyph carries the state; a tooltip holds the discrepancy
1641
- notes. Metadata, not an alarm.
1642
- -------------------------------------------------------------------------- */
1643
-
1644
- .qt-confirmation-badge {
1663
+ .qt-help-nav-button {
1645
1664
  display: inline-flex;
1646
1665
  align-items: center;
1647
- gap: 0.2rem;
1648
- padding: 0.05rem 0.4rem;
1649
- border-radius: 0.375rem;
1650
- border: 1px solid color-mix(in srgb, currentColor 25%, transparent);
1651
- background: transparent;
1652
- font: inherit;
1653
- line-height: 1.4;
1654
- cursor: help;
1655
- color: var(--qt-text-secondary-fg, var(--qt-text-secondary));
1656
- opacity: 0.8;
1657
- user-select: none;
1658
- white-space: nowrap;
1659
- transition: color 150ms, background-color 150ms, border-color 150ms, opacity 150ms;
1666
+ gap: 0.375rem;
1667
+ padding-left: 0.75rem;
1668
+ padding-right: 0.75rem;
1669
+ padding-top: 0.375rem;
1670
+ padding-bottom: 0.375rem;
1671
+ font-size: 0.75rem;
1672
+ line-height: 1rem;
1673
+ font-weight: 500;
1674
+ border-radius: var(--radius-md);
1675
+ transition-property: color, background-color, border-color, text-decoration-color, fill, stroke;
1676
+ transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
1677
+ transition-duration: 150ms;
1678
+ cursor: pointer;
1679
+ background: var(--qt-help-nav-bg, color-mix(in srgb, var(--color-primary) 10%, transparent));
1680
+ color: var(--qt-help-nav-fg, var(--color-primary));
1681
+ border: 1px solid var(--qt-help-nav-border, color-mix(in srgb, var(--color-primary) 20%, transparent));
1660
1682
  }
1661
1683
 
1662
- /* The badge sits among the message action icons and answers the pointer the
1663
- same way they do. */
1664
- .qt-confirmation-badge:hover,
1665
- .qt-confirmation-badge:focus-visible {
1666
- opacity: 1;
1667
- border-color: color-mix(in srgb, currentColor 45%, transparent);
1668
- background: color-mix(in srgb, var(--color-muted) 50%, transparent);
1684
+ .qt-help-nav-button:hover {
1685
+ background: var(--qt-help-nav-hover-bg, color-mix(in srgb, var(--color-primary) 20%, transparent));
1686
+ border-color: var(--qt-help-nav-hover-border, color-mix(in srgb, var(--color-primary) 40%, transparent));
1669
1687
  }
1670
1688
 
1671
- /* The tinted states (stood-by, amended) keep their own colour on hover; the
1672
- quiet ones brighten to the foreground the way the action icons do. */
1673
- .qt-confirmation-badge[data-confirmation-state="vouched"]:hover,
1674
- .qt-confirmation-badge[data-confirmation-state="vouched"]:focus-visible,
1675
- .qt-confirmation-badge[data-confirmation-state="unvetted"]:hover,
1676
- .qt-confirmation-badge[data-confirmation-state="unvetted"]:focus-visible {
1677
- color: var(--color-foreground);
1689
+ /* Suggested links container — appears below messages with search-derived links */
1690
+ .qt-help-suggested-links {
1691
+ padding-left: 2.5rem;
1692
+ padding-top: 0.25rem;
1678
1693
  }
1679
1694
 
1680
- .qt-confirmation-badge:focus-visible {
1681
- outline: 2px solid color-mix(in srgb, var(--color-foreground) 45%, transparent);
1682
- outline-offset: 2px;
1695
+ .qt-help-suggested-links-label {
1696
+ font-size: 10px;
1697
+ text-transform: uppercase;
1698
+ letter-spacing: 0.05em;
1699
+ font-weight: 500;
1700
+ margin-bottom: 0.375rem;
1701
+ color: var(--qt-help-suggested-label, var(--color-muted-foreground));
1683
1702
  }
1684
1703
 
1685
- .qt-chat-message-user .qt-confirmation-badge:hover,
1686
- .qt-chat-message-user .qt-confirmation-badge:focus-visible {
1687
- color: var(--qt-chat-user-fg);
1688
- background: color-mix(in srgb, var(--qt-chat-user-fg) 15%, transparent);
1704
+ .qt-help-suggested-link {
1705
+ display: inline-flex;
1706
+ align-items: center;
1707
+ gap: 0.25rem;
1708
+ padding-left: 0.5rem;
1709
+ padding-right: 0.5rem;
1710
+ padding-top: 0.25rem;
1711
+ padding-bottom: 0.25rem;
1712
+ font-size: 11px;
1713
+ border-radius: 0.25rem;
1714
+ transition-property: color, background-color, border-color, text-decoration-color, fill, stroke;
1715
+ transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
1716
+ transition-duration: 150ms;
1717
+ cursor: pointer;
1718
+ background: var(--qt-help-suggested-bg, color-mix(in srgb, var(--color-muted) 50%, transparent));
1719
+ color: var(--qt-help-suggested-fg, var(--color-muted-foreground));
1720
+ border: 1px solid var(--qt-help-suggested-border, var(--color-border));
1689
1721
  }
1690
1722
 
1691
- .qt-confirmation-badge-glyph {
1692
- font-weight: 600;
1723
+ .qt-help-suggested-link:hover {
1724
+ background: var(--qt-help-suggested-hover-bg, color-mix(in srgb, var(--color-primary) 10%, transparent));
1725
+ color: var(--qt-help-suggested-hover-fg, var(--color-primary));
1726
+ border-color: var(--qt-help-suggested-hover-border, color-mix(in srgb, var(--color-primary) 30%, transparent));
1693
1727
  }
1694
1728
 
1695
- .qt-confirmation-badge[data-confirmation-state="stood-by"] {
1696
- color: var(--qt-warning-box-fg, var(--qt-text-secondary-fg));
1697
- opacity: 1;
1729
+ /* Entity picker — overlay for resolving parameterised help URLs */
1730
+ .qt-help-entity-picker-backdrop {
1731
+ position: absolute;
1732
+ inset: 0;
1733
+ z-index: 10;
1734
+ display: flex;
1735
+ align-items: center;
1736
+ justify-content: center;
1737
+ background: hsl(0 0% 0% / 0.7);
1738
+ backdrop-filter: blur(4px);
1698
1739
  }
1699
1740
 
1700
- .qt-confirmation-badge[data-confirmation-state="amended"] {
1701
- opacity: 1;
1741
+ .qt-help-entity-picker {
1742
+ display: flex;
1743
+ flex-direction: column;
1744
+ border-radius: var(--radius-lg);
1745
+ box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
1746
+ overflow: hidden;
1747
+ width: min(320px, calc(100% - 2rem));
1748
+ max-height: min(400px, calc(100% - 2rem));
1749
+ background: var(--qt-help-picker-bg, var(--color-card));
1750
+ border: 1px solid var(--qt-help-picker-border, var(--color-border));
1702
1751
  }
1703
1752
 
1704
- /* ==========================================================================
1705
- CHAT — STAFF ANNOUNCEMENTS
1706
- Messages authored by a personified feature (the Librarian, the Host, Pascal
1707
- the Croupier, …) rather than by a character. They summarise to a one-line
1708
- bar, and a run of consecutive ones packs into a row of content-width chips.
1709
- ========================================================================== */
1710
-
1711
- /**
1712
- * Collapsed bar for Staff-authored messages.
1713
- * Single-line summary: dot · sender name · kind · timestamp · chevron.
1714
- * Click to expand into the regular message body.
1715
- */
1716
- .qt-chat-system-bar {
1753
+ .qt-help-entity-picker-header {
1717
1754
  display: flex;
1718
1755
  align-items: center;
1719
- gap: 0.625rem;
1720
- width: 100%;
1721
- padding: 0.25rem 0.625rem;
1722
- margin: 0.125rem 0;
1723
- background: var(--qt-chat-system-bar-bg);
1724
- color: var(--qt-chat-system-bar-fg);
1725
- border: 1px solid var(--qt-chat-system-bar-border);
1726
- border-radius: var(--radius-sm, 0.25rem);
1727
- font-size: 0.75rem;
1728
- line-height: 1.2;
1729
- text-align: left;
1730
- cursor: pointer;
1731
- transition: background-color 120ms ease;
1756
+ justify-content: space-between;
1757
+ padding-left: 0.75rem;
1758
+ padding-right: 0.75rem;
1759
+ padding-top: 0.5rem;
1760
+ padding-bottom: 0.5rem;
1761
+ font-size: 0.875rem;
1762
+ line-height: 1.25rem;
1763
+ font-weight: 500;
1764
+ border-bottom: 1px solid var(--qt-help-picker-border, var(--color-border));
1732
1765
  }
1733
1766
 
1734
- .qt-chat-system-bar:hover,
1735
- .qt-chat-system-bar:focus-visible {
1736
- background: var(--qt-chat-system-bar-hover-bg);
1767
+ .qt-help-entity-picker-filter {
1768
+ width: 100%;
1769
+ padding-left: 0.5rem;
1770
+ padding-right: 0.5rem;
1771
+ padding-top: 0.25rem;
1772
+ padding-bottom: 0.25rem;
1773
+ font-size: 0.75rem;
1774
+ line-height: 1rem;
1775
+ border-radius: 0.25rem;
1776
+ background: var(--qt-help-picker-filter-bg, var(--color-muted));
1777
+ border: 1px solid var(--qt-help-picker-border, var(--color-border));
1778
+ color: inherit;
1737
1779
  outline: none;
1738
1780
  }
1739
1781
 
1740
- .qt-chat-system-bar-sender {
1741
- color: var(--qt-chat-system-bar-sender-fg);
1742
- font-weight: 600;
1743
- white-space: nowrap;
1782
+ .qt-help-entity-picker-filter:focus {
1783
+ border-color: color-mix(in srgb, var(--color-primary) 50%, transparent);
1744
1784
  }
1745
1785
 
1746
- .qt-chat-system-bar-kind {
1747
- flex: 1 1 auto;
1748
- min-width: 0;
1749
- font-style: italic;
1750
- overflow: hidden;
1751
- text-overflow: ellipsis;
1752
- white-space: nowrap;
1786
+ .qt-help-entity-picker-list {
1787
+ flex: 1 1 0%;
1788
+ overflow-y: auto;
1789
+ padding-top: 0.25rem;
1790
+ padding-bottom: 0.25rem;
1753
1791
  }
1754
1792
 
1755
- /**
1756
- * Whisper audience on an announcement bar or chip ("to Alice, Bob"). Wears the
1757
- * same ink as the message body's whisper label so a private aside reads the
1758
- * same whether it is collapsed to a chip or opened in full.
1759
- */
1760
- .qt-chat-system-bar-whisper {
1761
- flex: 0 1 auto;
1762
- min-width: 0;
1763
- color: var(--qt-chat-whisper-label-fg);
1764
- font-style: italic;
1793
+ .qt-help-entity-picker-item {
1794
+ width: 100%;
1795
+ text-align: left;
1796
+ padding-left: 0.75rem;
1797
+ padding-right: 0.75rem;
1798
+ padding-top: 0.375rem;
1799
+ padding-bottom: 0.375rem;
1800
+ font-size: 0.875rem;
1801
+ line-height: 1.25rem;
1765
1802
  overflow: hidden;
1766
1803
  text-overflow: ellipsis;
1767
1804
  white-space: nowrap;
1805
+ transition-property: color, background-color, border-color, text-decoration-color, fill, stroke;
1806
+ transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
1807
+ transition-duration: 150ms;
1808
+ cursor: pointer;
1809
+ color: var(--qt-help-picker-fg, var(--color-foreground));
1768
1810
  }
1769
1811
 
1770
- .qt-chat-system-bar-time {
1771
- color: var(--qt-chat-system-bar-fg);
1772
- opacity: 0.75;
1773
- white-space: nowrap;
1812
+ .qt-help-entity-picker-item:hover {
1813
+ background: var(--qt-help-picker-hover-bg, color-mix(in srgb, var(--color-primary) 10%, transparent));
1814
+ color: var(--qt-help-picker-hover-fg, var(--color-primary));
1774
1815
  }
1775
1816
 
1776
- .qt-chat-system-bar-chevron {
1777
- flex-shrink: 0;
1778
- width: 0.875rem;
1779
- height: 0.875rem;
1780
- opacity: 0.7;
1781
- }
1817
+ /* ==========================================================================
1818
+ HELP GUIDE TAB - Browseable documentation view
1782
1819
 
1783
- /**
1784
- * Variant rendered at the top of an *expanded* Staff-authored message, giving
1785
- * the reader a prominent click target to re-collapse it.
1786
- */
1787
- .qt-chat-system-bar-expanded {
1788
- margin-bottom: 0.25rem;
1789
- }
1820
+ The Guide tab always renders in Art Deco style regardless of the active
1821
+ theme. Variables are hardcoded from the Art Deco token palette so the
1822
+ guide feels like a consistent, branded reading experience.
1823
+ ========================================================================== */
1790
1824
 
1791
- /**
1792
- * Packed announcement chips. A run of consecutive *collapsed* Staff messages
1793
- * renders as one flex-wrapping row of content-width chips instead of a
1794
- * full-width bar each.
1795
- */
1796
- .qt-chat-announcement-group {
1825
+ /* --- Art Deco variable scope (light mode) --- */
1826
+ .qt-help-guide-deco {
1827
+ --deco-bg: hsl(45 28% 78%);
1828
+ --deco-fg: hsl(222 40% 12%);
1829
+ --deco-fg-muted: hsl(222 25% 38%);
1830
+ --deco-primary: hsl(222 47% 18%);
1831
+ --deco-primary-fg: hsl(43 85% 55%);
1832
+ --deco-accent: hsl(43 85% 48%);
1833
+ --deco-border: hsl(43 30% 60%);
1834
+ --deco-border-subtle: hsl(43 30% 60% / 0.5);
1835
+ --deco-card: hsl(45 28% 75%);
1836
+ --deco-muted: hsl(222 16% 72%);
1837
+ --deco-input-bg: hsl(45 28% 82%);
1838
+ --deco-code-bg: hsl(45 20% 72%);
1839
+ --deco-gold: hsl(222 47% 18%);
1840
+ --deco-welcome-bg: hsl(222 47% 18% / 0.06);
1841
+ --deco-welcome-border: hsl(43 85% 48% / 0.3);
1842
+ --deco-table-header: hsl(45 25% 72%);
1843
+ --deco-hover-bg: hsl(43 30% 72% / 0.5);
1844
+ --deco-font-serif: "Cormorant Garamond", Georgia, Cambria, "Times New Roman", Times, serif;
1845
+ --deco-font-sans: Raleway, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
1846
+ }
1847
+
1848
+ /* --- Art Deco variable scope (dark mode) --- */
1849
+ .dark .qt-help-guide-deco,
1850
+ .qt-help-guide-deco.dark {
1851
+ --deco-bg: hsl(222 47% 7%);
1852
+ --deco-fg: hsl(45 15% 90%);
1853
+ --deco-fg-muted: hsl(222 12% 55%);
1854
+ --deco-primary: hsl(43 85% 55%);
1855
+ --deco-primary-fg: hsl(222 47% 7%);
1856
+ --deco-accent: hsl(43 90% 58%);
1857
+ --deco-border: hsl(43 35% 25%);
1858
+ --deco-border-subtle: hsl(43 35% 25% / 0.5);
1859
+ --deco-card: hsl(222 40% 12%);
1860
+ --deco-muted: hsl(222 25% 15%);
1861
+ --deco-input-bg: hsl(222 30% 14%);
1862
+ --deco-code-bg: hsl(222 25% 15%);
1863
+ --deco-gold: hsl(43 90% 58%);
1864
+ --deco-welcome-bg: hsl(43 85% 55% / 0.06);
1865
+ --deco-welcome-border: hsl(43 90% 58% / 0.2);
1866
+ --deco-table-header: hsl(222 30% 16%);
1867
+ --deco-hover-bg: hsl(222 25% 18% / 0.6);
1868
+ --deco-font-serif: "Cormorant Garamond", Georgia, Cambria, "Times New Roman", Times, serif;
1869
+ --deco-font-sans: Raleway, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
1870
+ }
1871
+
1872
+ /* --- Apply Art Deco palette to all guide components --- */
1873
+ .qt-help-guide-deco {
1874
+ background:
1875
+ linear-gradient(hsl(45 28% 75% / 0.88), hsl(45 28% 75% / 0.88)),
1876
+ url('/api/themes/assets/bundle:art-deco/textures/background-light.webp');
1877
+ background-size: cover;
1878
+ background-position: center center;
1879
+ color: var(--deco-fg);
1880
+ font-family: var(--deco-font-serif);
1881
+
1882
+ --qt-help-guide-search-bg: var(--deco-input-bg);
1883
+ --qt-help-guide-search-border: var(--deco-border);
1884
+ --qt-help-guide-search-fg: var(--deco-fg);
1885
+ --qt-help-guide-search-placeholder: var(--deco-fg-muted);
1886
+ --qt-help-guide-search-icon: var(--deco-fg-muted);
1887
+ --qt-help-guide-border: var(--deco-border-subtle);
1888
+ --qt-help-guide-category-fg: var(--deco-fg);
1889
+ --qt-help-guide-category-hover: var(--deco-gold);
1890
+ --qt-help-guide-badge-fg: var(--deco-fg-muted);
1891
+ --qt-help-guide-topic-fg: var(--deco-fg-muted);
1892
+ --qt-help-guide-topic-hover: var(--deco-fg);
1893
+ --qt-help-guide-topic-hover-bg: var(--deco-hover-bg);
1894
+ --qt-help-guide-topic-active-fg: var(--deco-gold);
1895
+ --qt-help-guide-back-fg: var(--deco-gold);
1896
+ --qt-help-guide-back-hover-bg: var(--deco-hover-bg);
1897
+ --qt-help-guide-reader-fg: var(--deco-fg);
1898
+ --qt-help-guide-heading-fg: var(--deco-fg);
1899
+ --qt-help-guide-code-bg: var(--deco-code-bg);
1900
+ --qt-help-guide-code-fg: var(--deco-fg);
1901
+ --qt-help-guide-link-fg: var(--deco-gold);
1902
+ --qt-help-guide-table-header-bg: var(--deco-table-header);
1903
+ --qt-help-welcome-bg: var(--deco-welcome-bg);
1904
+ --qt-help-welcome-border: var(--deco-welcome-border);
1905
+ --qt-help-welcome-title-fg: var(--deco-fg);
1906
+ --qt-help-welcome-text-fg: var(--deco-fg-muted);
1907
+ --qt-help-welcome-link-fg: var(--deco-gold);
1908
+ }
1909
+
1910
+ .dark .qt-help-guide-deco,
1911
+ .qt-help-guide-deco.dark {
1912
+ background:
1913
+ linear-gradient(hsl(222 40% 12% / 0.88), hsl(222 40% 12% / 0.88)),
1914
+ url('/api/themes/assets/bundle:art-deco/textures/background-dark.webp');
1915
+ background-size: cover;
1916
+ background-position: center center;
1917
+ }
1918
+
1919
+ .qt-help-guide-deco .qt-help-guide-category-label {
1920
+ font-family: var(--deco-font-sans);
1921
+ letter-spacing: 0.025em;
1922
+ }
1923
+
1924
+ .qt-help-guide-deco .qt-help-guide-reader h1,
1925
+ .qt-help-guide-deco .qt-help-guide-reader h2,
1926
+ .qt-help-guide-deco .qt-help-guide-reader h3 {
1927
+ font-family: var(--deco-font-sans);
1928
+ letter-spacing: 0.015em;
1929
+ }
1930
+
1931
+ .qt-help-guide-deco .qt-help-guide-back {
1932
+ font-family: var(--deco-font-sans);
1933
+ letter-spacing: 0.025em;
1934
+ }
1935
+
1936
+ .qt-help-guide-search {
1937
+ position: relative;
1797
1938
  display: flex;
1798
- flex-wrap: wrap;
1799
- gap: 0.375rem;
1800
- width: 95%;
1801
- max-width: var(--qt-chat-message-row-max-width);
1802
- margin: 1.5rem auto 0;
1803
- align-items: flex-start;
1939
+ align-items: center;
1804
1940
  }
1805
1941
 
1806
- /**
1807
- * A single collapsed announcement, sized to its content (never full width).
1808
- * Reuses the -sender / -kind / -time / -chevron element classes above; only the
1809
- * -kind sizing differs (see the override below).
1810
- */
1811
- .qt-chat-announcement-chip {
1812
- display: inline-flex;
1813
- align-items: center;
1814
- gap: 0.5rem;
1815
- flex: 0 1 auto;
1816
- min-width: 0;
1817
- max-width: 100%;
1818
- padding: 0.25rem 0.625rem;
1819
- background: var(--qt-chat-system-bar-bg);
1820
- color: var(--qt-chat-system-bar-fg);
1821
- border: 1px solid var(--qt-chat-system-bar-border);
1822
- border-radius: var(--radius-sm, 0.25rem);
1823
- font-size: 0.75rem;
1824
- line-height: 1.2;
1825
- text-align: left;
1826
- cursor: pointer;
1827
- transition: background-color 120ms ease;
1942
+ .qt-help-guide-search-icon {
1943
+ position: absolute;
1944
+ left: 0.625rem;
1945
+ width: 1rem;
1946
+ height: 1rem;
1947
+ pointer-events: none;
1948
+ color: var(--qt-help-guide-search-icon, var(--color-muted-foreground));
1828
1949
  }
1829
1950
 
1830
- .qt-chat-announcement-chip:hover,
1831
- .qt-chat-announcement-chip:focus-visible {
1832
- background: var(--qt-chat-system-bar-hover-bg);
1833
- outline: none;
1951
+ .qt-help-guide-search-input {
1952
+ width: 100%;
1953
+ padding-left: 2.25rem;
1954
+ padding-right: 2rem;
1955
+ padding-top: 0.375rem;
1956
+ padding-bottom: 0.375rem;
1957
+ font-size: 0.875rem;
1958
+ line-height: 1.25rem;
1959
+ border-radius: var(--radius-md);
1960
+ border-width: 1px;
1961
+ border-style: solid;
1962
+ background: var(--qt-help-guide-search-bg, var(--color-background));
1963
+ border-color: var(--qt-help-guide-search-border, var(--color-border));
1964
+ color: var(--qt-help-guide-search-fg, var(--color-foreground));
1834
1965
  }
1835
1966
 
1836
- /* Inside a chip the kind must not greedily fill the row; cap it so a long kind
1837
- doesn't dominate a packed row. */
1838
- .qt-chat-announcement-chip .qt-chat-system-bar-kind {
1839
- flex: 0 1 auto;
1840
- max-width: 22ch;
1967
+ .qt-help-guide-search-input::placeholder {
1968
+ color: var(--qt-help-guide-search-placeholder, var(--color-muted-foreground));
1841
1969
  }
1842
1970
 
1843
- /* Same cap for a long audience list — a whisper to five people must not push
1844
- the timestamp and chevron off the chip. */
1845
- .qt-chat-announcement-chip .qt-chat-system-bar-whisper {
1846
- max-width: 18ch;
1971
+ .qt-help-guide-search-input:focus {
1972
+ outline-style: none;
1973
+ box-shadow: 0 0 0 1px var(--color-background), 0 0 0 3px var(--color-ring);
1847
1974
  }
1848
1975
 
1849
- /* A whispered announcement carries the whisper's border colour, so a private
1850
- aside is distinguishable from a public one before it is ever expanded. */
1851
- .qt-chat-announcement-chip-whisper {
1852
- border-color: var(--qt-chat-whisper-label-fg);
1976
+ .qt-help-guide-search-clear {
1977
+ position: absolute;
1978
+ right: 0.5rem;
1979
+ padding: 0.125rem;
1980
+ border-radius: var(--radius-sm);
1981
+ transition-property: color, background-color, border-color, text-decoration-color, fill, stroke;
1982
+ transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
1983
+ transition-duration: 150ms;
1984
+ color: var(--qt-help-guide-search-icon, var(--color-muted-foreground));
1853
1985
  }
1854
1986
 
1855
- /**
1856
- * Importance dot before the sender name. Filled for high/medium, hollow for
1857
- * low, so the eye lands on what matters and skims past the low-noise chatter.
1858
- */
1859
- .qt-chat-announcement-dot {
1860
- flex-shrink: 0;
1861
- width: 0.5rem;
1862
- height: 0.5rem;
1863
- border-radius: 9999px;
1864
- border: 1px solid transparent;
1987
+ .qt-help-guide-search-clear:hover {
1988
+ color: var(--qt-help-guide-search-fg, var(--color-foreground));
1865
1989
  }
1866
1990
 
1867
- .qt-chat-announcement-dot-high {
1868
- background: var(--qt-chat-announcement-dot-high);
1991
+ /* Category accordion */
1992
+
1993
+ .qt-help-guide-category {
1994
+ border-bottom-width: 1px;
1995
+ border-bottom-style: solid;
1996
+ border-color: var(--qt-help-guide-border, color-mix(in srgb, var(--color-border) 50%, transparent));
1869
1997
  }
1870
1998
 
1871
- .qt-chat-announcement-dot-medium {
1872
- background: var(--qt-chat-announcement-dot-medium);
1999
+ .qt-help-guide-category:last-child {
2000
+ border-bottom-width: 0;
1873
2001
  }
1874
2002
 
1875
- .qt-chat-announcement-dot-low {
1876
- background: transparent;
1877
- border-color: var(--qt-chat-announcement-dot-low);
2003
+ .qt-help-guide-category-header {
2004
+ width: 100%;
2005
+ display: flex;
2006
+ align-items: center;
2007
+ gap: 0.5rem;
2008
+ padding-top: 0.5rem;
2009
+ padding-bottom: 0.5rem;
2010
+ padding-left: 0.25rem;
2011
+ padding-right: 0.25rem;
2012
+ text-align: left;
2013
+ font-size: 0.875rem;
2014
+ line-height: 1.25rem;
2015
+ transition-property: color, background-color, border-color, text-decoration-color, fill, stroke;
2016
+ transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
2017
+ transition-duration: 150ms;
2018
+ cursor: pointer;
2019
+ color: var(--qt-help-guide-category-fg, var(--color-foreground));
1878
2020
  }
1879
2021
 
1880
- /**
1881
- * Outcome dot for a Pascal roll announcement, which replaces the importance dot:
1882
- * a roll has a verdict of its own — success / partial / failure / info — and
1883
- * that verdict is what the reader is looking for. Filled with the solid
1884
- * --qt-alert-*-fg (the -border tints are alpha-thin and vanish at 8px); the
1885
- * bar's leading accent below uses the -border tints, as .qt-pascal-result does.
1886
- */
1887
- .qt-chat-announcement-dot-outcome-success {
1888
- background: var(--qt-alert-success-fg);
2022
+ .qt-help-guide-category-header:hover {
2023
+ color: var(--qt-help-guide-category-hover, var(--color-primary));
1889
2024
  }
1890
2025
 
1891
- .qt-chat-announcement-dot-outcome-partial {
1892
- background: var(--qt-alert-warning-fg);
2026
+ .qt-help-guide-category-chevron {
2027
+ width: 1rem;
2028
+ height: 1rem;
2029
+ flex-shrink: 0;
2030
+ transition-property: transform, translate, scale, rotate;
2031
+ transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
2032
+ transition-duration: 150ms;
1893
2033
  }
1894
2034
 
1895
- .qt-chat-announcement-dot-outcome-failure {
1896
- background: var(--qt-alert-error-fg);
2035
+ .qt-help-guide-category-chevron-open {
2036
+ transform: rotate(90deg);
1897
2037
  }
1898
2038
 
1899
- .qt-chat-announcement-dot-outcome-info {
1900
- background: var(--qt-alert-info-fg);
2039
+ .qt-help-guide-category-label {
2040
+ flex: 1 1 0%;
2041
+ font-weight: 500;
1901
2042
  }
1902
2043
 
1903
- /**
1904
- * The bar/chip of a Pascal roll wears the same .qt-pascal-result accent as the
1905
- * outcome bubble itself, so one outcome reads identically wherever it is shown.
1906
- *
1907
- * These compound selectors only restate that accent: .qt-pascal-result is
1908
- * declared above, and both wrappers set `border` and `padding` SHORTHANDS at
1909
- * equal specificity, so the plain family would lose on source order. Nothing
1910
- * new is styled here — change the accent itself at .qt-pascal-result.
1911
- */
1912
- .qt-chat-system-bar.qt-pascal-result,
1913
- .qt-chat-announcement-chip.qt-pascal-result {
1914
- border-left-width: 3px;
1915
- border-left-color: var(--qt-alert-info-border);
1916
- padding-left: 0.75rem;
2044
+ .qt-help-guide-category-badge {
2045
+ font-size: 0.75rem;
2046
+ line-height: 1rem;
2047
+ flex-shrink: 0;
2048
+ color: var(--qt-help-guide-badge-fg, var(--color-muted-foreground));
1917
2049
  }
1918
2050
 
1919
- .qt-chat-system-bar.qt-pascal-result--success,
1920
- .qt-chat-announcement-chip.qt-pascal-result--success {
1921
- border-left-color: var(--qt-alert-success-border);
2051
+ .qt-help-guide-category-topics {
2052
+ display: flex;
2053
+ flex-direction: column;
2054
+ padding-bottom: 0.25rem;
1922
2055
  }
1923
2056
 
1924
- .qt-chat-system-bar.qt-pascal-result--partial,
1925
- .qt-chat-announcement-chip.qt-pascal-result--partial {
1926
- border-left-color: var(--qt-alert-warning-border);
2057
+ /* Topic rows */
2058
+
2059
+ .qt-help-guide-topic {
2060
+ width: 100%;
2061
+ text-align: left;
2062
+ padding-top: 0.25rem;
2063
+ padding-bottom: 0.25rem;
2064
+ padding-left: 1.75rem;
2065
+ padding-right: 0.5rem;
2066
+ font-size: 0.875rem;
2067
+ line-height: 1.25rem;
2068
+ overflow: hidden;
2069
+ text-overflow: ellipsis;
2070
+ white-space: nowrap;
2071
+ transition-property: color, background-color, border-color, text-decoration-color, fill, stroke;
2072
+ transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
2073
+ transition-duration: 150ms;
2074
+ cursor: pointer;
2075
+ border-radius: var(--radius-sm);
2076
+ color: var(--qt-help-guide-topic-fg, var(--color-muted-foreground));
1927
2077
  }
1928
2078
 
1929
- .qt-chat-system-bar.qt-pascal-result--failure,
1930
- .qt-chat-announcement-chip.qt-pascal-result--failure {
1931
- border-left-color: var(--qt-alert-error-border);
2079
+ .qt-help-guide-topic:hover {
2080
+ color: var(--qt-help-guide-topic-hover, var(--color-foreground));
2081
+ background: var(--qt-help-guide-topic-hover-bg, color-mix(in srgb, var(--color-accent) 50%, transparent));
1932
2082
  }
1933
2083
 
1934
- .qt-chat-system-bar.qt-pascal-result--info,
1935
- .qt-chat-announcement-chip.qt-pascal-result--info {
1936
- border-left-color: var(--qt-alert-info-border);
2084
+ .qt-help-guide-topic-active {
2085
+ color: var(--qt-help-guide-topic-active-fg, var(--color-primary));
2086
+ font-weight: 500;
1937
2087
  }
1938
2088
 
1939
- /**
1940
- * Deus Ex Machina — established facts in the Salon.
1941
- *
1942
- * Mirrors app/styles/qt-components/_chat.css. Built on existing tokens only (the --qt-alert-info-* family and --color-ring,
1943
- * the focus-ring colour), so every bundled theme renders it without per-theme
1944
- * work and the armed frame holds the focus ring's own contrast.
1945
- *
1946
- * - .qt-chat-composer-established-fact: the composer's editor wrapper while
1947
- * `/deus` is armed — a frame and a faint tint, so the operator can see the
1948
- * next line will be posted as fact.
1949
- * - .qt-chat-message-established-fact: the small ribbon on an operator line
1950
- * posted as fact.
1951
- * - .qt-chat-established-fact: the accent on a machine fact's bar/chip.
1952
- * - .qt-chat-established-fact-row / -band: a machine fact renders as a
1953
- * full-width band (no avatar) rather than a speech bubble.
1954
- */
1955
- .qt-chat-composer-established-fact .qt-chat-composer-input {
1956
- border-color: var(--color-ring);
1957
- box-shadow: inset 0 0 0 1px var(--color-ring);
1958
- background-image: linear-gradient(var(--qt-alert-info-bg), var(--qt-alert-info-bg));
2089
+ /* Reader view */
2090
+
2091
+ .qt-help-guide-back {
2092
+ display: flex;
2093
+ align-items: center;
2094
+ gap: 0.375rem;
2095
+ padding-left: 0.75rem;
2096
+ padding-right: 0.75rem;
2097
+ padding-top: 0.5rem;
2098
+ padding-bottom: 0.5rem;
2099
+ font-size: 0.875rem;
2100
+ line-height: 1.25rem;
2101
+ font-weight: 500;
2102
+ border-bottom-width: 1px;
2103
+ border-bottom-style: solid;
2104
+ flex-shrink: 0;
2105
+ transition-property: color, background-color, border-color, text-decoration-color, fill, stroke;
2106
+ transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
2107
+ transition-duration: 150ms;
2108
+ cursor: pointer;
2109
+ color: var(--qt-help-guide-back-fg, var(--color-primary));
2110
+ border-color: var(--qt-help-guide-border, color-mix(in srgb, var(--color-border) 50%, transparent));
1959
2111
  }
1960
2112
 
1961
- .qt-chat-message-established-fact {
1962
- font-size: 0.75rem;
2113
+ .qt-help-guide-back:hover {
2114
+ background: var(--qt-help-guide-back-hover-bg, color-mix(in srgb, var(--color-accent) 30%, transparent));
2115
+ }
2116
+
2117
+ .qt-help-guide-reader {
2118
+ flex: 1 1 0%;
2119
+ overflow-y: auto;
2120
+ padding-left: 1rem;
2121
+ padding-right: 1rem;
2122
+ padding-top: 0.75rem;
2123
+ padding-bottom: 0.75rem;
2124
+ font-size: 0.8125rem;
2125
+ line-height: 1.625;
2126
+ color: var(--qt-help-guide-reader-fg, var(--color-foreground));
2127
+ overflow-x: hidden;
2128
+ min-width: 0;
2129
+ }
2130
+
2131
+ .qt-help-guide-reader h1 {
2132
+ font-size: 1.125rem;
2133
+ line-height: 1.75rem;
2134
+ font-weight: 700;
2135
+ margin-top: 0;
2136
+ margin-bottom: 0.75rem;
2137
+ }
2138
+
2139
+ .qt-help-guide-reader h2 {
2140
+ font-size: 1rem;
2141
+ line-height: 1.5rem;
1963
2142
  font-weight: 600;
1964
- letter-spacing: 0.02em;
1965
- color: var(--qt-alert-info-fg);
1966
- margin-bottom: 0.25rem;
2143
+ margin-top: 1.25rem;
2144
+ margin-bottom: 0.5rem;
2145
+ color: var(--qt-help-guide-heading-fg, var(--color-foreground));
1967
2146
  }
1968
2147
 
1969
- .qt-chat-system-bar.qt-chat-established-fact,
1970
- .qt-chat-announcement-chip.qt-chat-established-fact {
1971
- border-left-width: 3px;
1972
- border-left-color: var(--color-ring);
1973
- padding-left: 0.75rem;
2148
+ .qt-help-guide-reader h3 {
2149
+ font-size: 0.875rem;
2150
+ line-height: 1.25rem;
2151
+ font-weight: 600;
2152
+ margin-top: 1rem;
2153
+ margin-bottom: 0.375rem;
1974
2154
  }
1975
2155
 
1976
- .qt-chat-established-fact-row {
1977
- width: 100%;
1978
- max-width: none;
2156
+ .qt-help-guide-reader p {
2157
+ margin-bottom: 0.5rem;
1979
2158
  }
1980
2159
 
1981
- .qt-chat-established-fact-band {
2160
+ .qt-help-guide-reader ul,
2161
+ .qt-help-guide-reader ol {
2162
+ margin-bottom: 0.5rem;
2163
+ padding-left: 1.25rem;
2164
+ }
2165
+
2166
+ .qt-help-guide-reader li {
2167
+ margin-bottom: 0.125rem;
2168
+ }
2169
+
2170
+ .qt-help-guide-reader strong {
2171
+ font-weight: 600;
2172
+ }
2173
+
2174
+ .qt-help-guide-reader table {
1982
2175
  width: 100%;
1983
- background: var(--qt-alert-info-bg);
1984
- border: 1px solid var(--qt-alert-info-border);
1985
- border-left: 3px solid var(--color-ring);
1986
- box-shadow: none;
2176
+ margin-bottom: 0.75rem;
2177
+ font-size: 0.75rem;
2178
+ line-height: 1rem;
2179
+ border-collapse: collapse;
2180
+ table-layout: fixed;
2181
+ word-break: break-word;
1987
2182
  }
1988
2183
 
1989
- /**
1990
- * Silent message — inner thoughts and actions from character in silent mode.
1991
- * Distinguished from whispers by a dotted border (vs dashed) and sage/teal tones.
1992
- */
1993
- .qt-chat-message-silent {
1994
- background: var(--qt-chat-silent-bg);
1995
- color: var(--qt-chat-silent-fg);
1996
- border: 2px dotted var(--qt-chat-silent-border);
1997
- font-style: italic;
2184
+ .qt-help-guide-reader th,
2185
+ .qt-help-guide-reader td {
2186
+ padding-left: 0.5rem;
2187
+ padding-right: 0.5rem;
2188
+ padding-top: 0.25rem;
2189
+ padding-bottom: 0.25rem;
2190
+ border-width: 1px;
2191
+ border-style: solid;
2192
+ text-align: left;
2193
+ border-color: var(--qt-help-guide-border, color-mix(in srgb, var(--color-border) 50%, transparent));
1998
2194
  }
1999
2195
 
2000
- .qt-chat-silent-label {
2196
+ .qt-help-guide-reader th {
2197
+ font-weight: 600;
2198
+ background: var(--qt-help-guide-table-header-bg, color-mix(in srgb, var(--color-muted) 50%, transparent));
2199
+ }
2200
+
2201
+ .qt-help-guide-reader hr {
2202
+ margin-top: 1rem;
2203
+ margin-bottom: 1rem;
2204
+ border-color: var(--qt-help-guide-border, color-mix(in srgb, var(--color-border) 50%, transparent));
2205
+ }
2206
+
2207
+ .qt-help-guide-inline-code {
2208
+ padding-left: 0.25rem;
2209
+ padding-right: 0.25rem;
2210
+ padding-top: 0.125rem;
2211
+ padding-bottom: 0.125rem;
2212
+ border-radius: 0.25rem;
2001
2213
  font-size: 0.75rem;
2002
- color: var(--qt-chat-silent-label-fg);
2003
- font-style: italic;
2214
+ line-height: 1rem;
2215
+ background: var(--qt-help-guide-code-bg, var(--color-muted));
2216
+ color: var(--qt-help-guide-code-fg, var(--color-foreground));
2217
+ }
2218
+
2219
+ .qt-help-guide-code-block {
2220
+ border-radius: var(--radius-md);
2221
+ padding: 0.75rem;
2222
+ margin-bottom: 0.5rem;
2223
+ font-size: 0.75rem;
2224
+ line-height: 1rem;
2225
+ background: var(--qt-help-guide-code-bg, var(--color-muted));
2226
+ white-space: pre-wrap !important;
2227
+ word-break: break-all;
2228
+ overflow-wrap: anywhere;
2229
+ max-width: 100%;
2230
+ overflow: hidden;
2231
+ color: var(--qt-help-guide-code-fg, var(--color-foreground));
2232
+ }
2233
+
2234
+ /* Navigation callout button (replaces "Open this page in Quilltap" blockquote) */
2235
+
2236
+ .qt-help-guide-nav-callout {
2237
+ margin-top: 0.75rem;
2238
+ margin-bottom: 0.75rem;
2239
+ }
2240
+
2241
+ /* Doc links and page links within reader */
2242
+
2243
+ .qt-help-guide-doc-link {
2244
+ cursor: pointer;
2245
+ text-decoration-line: underline;
2246
+ color: var(--qt-help-guide-link-fg, var(--color-primary));
2247
+ }
2248
+
2249
+ .qt-help-guide-doc-link:hover {
2250
+ opacity: 0.8;
2251
+ }
2252
+
2253
+ .qt-help-guide-page-link {
2254
+ cursor: pointer;
2255
+ text-decoration-line: underline;
2256
+ color: var(--qt-help-guide-link-fg, var(--color-primary));
2257
+ }
2258
+
2259
+ .qt-help-guide-page-link:hover {
2260
+ opacity: 0.8;
2261
+ }
2262
+
2263
+ /* Welcome card */
2264
+
2265
+ .qt-help-welcome-card {
2266
+ border-radius: var(--radius-lg);
2267
+ border-width: 1px;
2268
+ border-style: solid;
2269
+ padding: 0.75rem;
2270
+ margin-bottom: 0.75rem;
2271
+ background: var(--qt-help-welcome-bg, color-mix(in srgb, var(--color-primary) 5%, transparent));
2272
+ border-color: var(--qt-help-welcome-border, color-mix(in srgb, var(--color-primary) 20%, transparent));
2273
+ }
2274
+
2275
+ .qt-help-welcome-title {
2276
+ font-size: 0.875rem;
2277
+ line-height: 1.25rem;
2278
+ font-weight: 600;
2004
2279
  margin-bottom: 0.25rem;
2280
+ color: var(--qt-help-welcome-title-fg, var(--color-foreground));
2005
2281
  }
2006
2282
 
2007
- /**
2008
- * Regeneration — a line being re-rolled in place.
2009
- *
2010
- * Two states, one bubble. Before the first token the old line is still there
2011
- * but visibly out of service (dimmed, desaturated, unselectable) under a plate
2012
- * that says what is happening. From the first token the plate and the old line
2013
- * are both gone and the new prose streams in their place.
2014
- */
2015
- .qt-chat-message-regenerating {
2016
- border-color: color-mix(in srgb, var(--qt-response-status-streaming-fg) 45%, transparent);
2283
+ .qt-help-welcome-text {
2284
+ font-size: 0.75rem;
2285
+ line-height: 1rem;
2286
+ margin-bottom: 0.5rem;
2287
+ color: var(--qt-help-welcome-text-fg, var(--color-muted-foreground));
2288
+ }
2289
+
2290
+ .qt-help-welcome-links {
2291
+ display: flex;
2292
+ flex-direction: column;
2293
+ gap: 0.125rem;
2294
+ margin-bottom: 0.5rem;
2295
+ }
2296
+
2297
+ .qt-help-welcome-link {
2298
+ display: flex;
2299
+ align-items: center;
2300
+ gap: 0.375rem;
2301
+ font-size: 0.75rem;
2302
+ line-height: 1rem;
2303
+ padding-top: 0.125rem;
2304
+ padding-bottom: 0.125rem;
2305
+ transition-property: color, background-color, border-color, text-decoration-color, fill, stroke;
2306
+ transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
2307
+ transition-duration: 150ms;
2308
+ cursor: pointer;
2309
+ text-align: left;
2310
+ color: var(--qt-help-welcome-link-fg, var(--color-primary));
2311
+ }
2312
+
2313
+ .qt-help-welcome-link:hover {
2314
+ opacity: 0.8;
2315
+ }
2316
+
2317
+ .qt-help-welcome-footer {
2318
+ font-size: 0.75rem;
2319
+ line-height: 1rem;
2320
+ color: var(--qt-help-welcome-text-fg, var(--color-muted-foreground));
2321
+ }
2322
+
2323
+ /* ==========================================================================
2324
+ BRAHMA CONSOLE LAUNCHER - The always-on button beside the left rail
2325
+ Sits in the topmost floating layer so it stays reachable over any modal.
2326
+ ========================================================================== */
2327
+
2328
+ .qt-brahma-launcher {
2329
+ position: fixed;
2330
+ left: calc(var(--qt-left-sidebar-collapsed-width) + var(--qt-brahma-launcher-offset));
2331
+ bottom: var(--qt-brahma-launcher-offset);
2332
+ z-index: var(--qt-floating-layer-z);
2333
+ width: var(--qt-brahma-launcher-size);
2334
+ height: var(--qt-brahma-launcher-size);
2335
+ display: inline-flex;
2336
+ align-items: center;
2337
+ justify-content: center;
2338
+ border-radius: 9999px;
2339
+ background: var(--qt-brahma-launcher-bg);
2340
+ color: var(--qt-brahma-launcher-fg);
2341
+ border: 2px solid var(--qt-brahma-launcher-ring);
2342
+ box-shadow: var(--qt-brahma-launcher-shadow);
2343
+ transition: background-color 150ms ease, color 150ms ease, transform 150ms ease;
2344
+ }
2345
+
2346
+ .qt-brahma-launcher:hover {
2347
+ background: var(--qt-brahma-launcher-hover-bg);
2348
+ transform: scale(1.06);
2349
+ }
2350
+
2351
+ .qt-brahma-launcher:focus-visible {
2352
+ outline: 2px solid var(--qt-brahma-launcher-ring);
2353
+ outline-offset: 3px;
2354
+ }
2355
+
2356
+ .qt-brahma-launcher-active,
2357
+ .qt-brahma-launcher-active:hover {
2358
+ background: var(--qt-brahma-launcher-active-bg);
2359
+ color: var(--qt-brahma-launcher-active-fg);
2360
+ }
2361
+
2362
+ .qt-brahma-launcher-icon {
2363
+ width: 60%;
2364
+ height: 60%;
2365
+ }
2366
+
2367
+ /* ==========================================================================
2368
+ SLIDE-OVER PANELS
2369
+ ========================================================================== */
2370
+
2371
+ .qt-slide-over-overlay {
2372
+ position: fixed;
2373
+ inset: 0;
2374
+ z-index: 55;
2375
+ background-color: var(--qt-dialog-backdrop);
2376
+ opacity: 0;
2377
+ transition: opacity 200ms ease;
2378
+ pointer-events: none;
2379
+ }
2380
+
2381
+ .qt-slide-over-overlay[data-open="true"] {
2382
+ opacity: 1;
2383
+ pointer-events: auto;
2384
+ }
2385
+
2386
+ .qt-slide-over-panel {
2387
+ position: fixed;
2388
+ right: 0;
2389
+ top: 0;
2390
+ z-index: 55;
2391
+ height: 100%;
2392
+ display: flex;
2393
+ flex-direction: column;
2394
+ background-color: var(--qt-dialog-bg);
2395
+ border-left: 1px solid var(--qt-dialog-border);
2396
+ box-shadow: var(--qt-dialog-shadow);
2397
+ transform: translateX(100%);
2398
+ transition: transform 200ms cubic-bezier(0.4, 0, 0.2, 1);
2399
+ }
2400
+
2401
+ .qt-slide-over-panel[data-open="true"] {
2402
+ transform: translateX(0);
2403
+ }
2404
+
2405
+ .qt-slide-over-header {
2406
+ display: flex;
2407
+ align-items: center;
2408
+ justify-content: space-between;
2409
+ padding: 0.75rem 1rem;
2410
+ flex-shrink: 0;
2411
+ border-bottom: 1px solid var(--qt-dialog-border);
2412
+ }
2413
+
2414
+ .qt-inspector-entry {
2415
+ transition: all 150ms ease;
2416
+ border-radius: var(--qt-card-radius);
2417
+ background: var(--qt-card-bg);
2418
+ border: 1px solid color-mix(in srgb, var(--qt-card-border) calc(var(--qt-card-border-opacity, 1) * 100%), transparent);
2419
+ }
2420
+
2421
+ .qt-inspector-entry:hover {
2422
+ border-color: color-mix(in srgb, var(--color-primary) 30%, transparent);
2423
+ }
2424
+
2425
+ .qt-inspector-entry-highlight {
2426
+ animation: qt-inspector-highlight 2s ease-out;
2427
+ }
2428
+
2429
+ @keyframes qt-inspector-highlight {
2430
+ 0% {
2431
+ box-shadow: 0 0 0 2px color-mix(in srgb, var(--color-primary) 60%, transparent);
2432
+ }
2433
+ 100% {
2434
+ box-shadow: 0 0 0 0px transparent;
2435
+ }
2436
+ }
2437
+
2438
+ /* ==========================================================================
2439
+ TAB COMPONENTS
2440
+ ========================================================================== */
2441
+
2442
+ .qt-tab-group {
2443
+ display: flex;
2444
+ gap: var(--qt-tab-group-gap);
2445
+ border-bottom: 1px solid var(--color-border);
2446
+ }
2447
+
2448
+ .qt-tab {
2449
+ padding: var(--qt-tab-padding-y) var(--qt-tab-padding-x);
2450
+ font-size: var(--qt-tab-font-size);
2451
+ font-weight: var(--qt-tab-font-weight);
2452
+ color: var(--qt-tab-fg);
2453
+ background-color: var(--qt-tab-bg);
2454
+ border: none;
2455
+ border-radius: var(--qt-tab-radius);
2456
+ cursor: pointer;
2457
+ transition: all 150ms;
2458
+ }
2459
+
2460
+ .qt-tab:hover {
2461
+ color: var(--color-foreground);
2462
+ }
2463
+
2464
+ .qt-tab-active {
2465
+ background-color: var(--qt-tab-active-bg);
2466
+ color: var(--qt-tab-active-fg);
2467
+ }
2468
+
2469
+ .qt-tab-content {
2470
+ padding: 1rem 0;
2471
+ }
2472
+
2473
+ /* ==========================================================================
2474
+ CHAT COMPONENTS
2475
+ ========================================================================== */
2476
+
2477
+ .qt-chat-message {
2478
+ padding: var(--qt-chat-message-padding);
2479
+ border-radius: var(--qt-chat-message-radius);
2480
+ max-width: 80%;
2481
+ }
2482
+
2483
+ .qt-chat-message-user {
2484
+ background-color: var(--qt-chat-user-bg);
2485
+ color: var(--qt-chat-user-fg);
2486
+ margin-left: auto;
2487
+ }
2488
+
2489
+ .qt-chat-message-assistant {
2490
+ background-color: var(--qt-chat-assistant-bg);
2491
+ color: var(--qt-chat-assistant-fg);
2492
+ border: 1px solid var(--color-border);
2493
+ }
2494
+
2495
+ /**
2496
+ * Whisper message — private messages between characters, not heard by all.
2497
+ */
2498
+ .qt-chat-message-whisper {
2499
+ background: var(--qt-chat-whisper-bg);
2500
+ color: var(--qt-chat-whisper-fg);
2501
+ border: 2px dashed var(--qt-chat-whisper-border);
2502
+ font-style: italic;
2503
+ }
2504
+
2505
+ .qt-chat-whisper-label {
2506
+ font-size: 0.75rem;
2507
+ color: var(--qt-chat-whisper-label-fg);
2508
+ font-style: italic;
2509
+ margin-bottom: 0.25rem;
2510
+ }
2511
+
2512
+ .qt-chat-message-whisper-overheard {
2513
+ opacity: 0.6;
2514
+ }
2515
+
2516
+ /**
2517
+ * Pascal result — the outcome of a custom tool (pseudo-tool) roll, announced by
2518
+ * Pascal the Croupier. The accent carries the outcome's semantic `state`.
2519
+ * Built on the --qt-alert-* families, which every bundled theme defines.
2520
+ */
2521
+ .qt-pascal-result {
2522
+ border-left: 3px solid var(--qt-alert-info-border);
2523
+ padding-left: 0.75rem;
2524
+ }
2525
+
2526
+ .qt-pascal-result--success {
2527
+ border-left-color: var(--qt-alert-success-border);
2528
+ }
2529
+
2530
+ .qt-pascal-result--partial {
2531
+ border-left-color: var(--qt-alert-warning-border);
2532
+ }
2533
+
2534
+ .qt-pascal-result--failure {
2535
+ border-left-color: var(--qt-alert-error-border);
2536
+ }
2537
+
2538
+ .qt-pascal-result--info {
2539
+ border-left-color: var(--qt-alert-info-border);
2540
+ }
2541
+
2542
+ /* --------------------------------------------------------------------------
2543
+ ANSWER-CONFIRMATION BADGE
2544
+ A quiet per-message verdict marker (Vouched / Amended / Stood by /
2545
+ Unvetted). The glyph carries the state; a tooltip holds the discrepancy
2546
+ notes. Metadata, not an alarm.
2547
+ -------------------------------------------------------------------------- */
2548
+
2549
+ .qt-confirmation-badge {
2550
+ display: inline-flex;
2551
+ align-items: center;
2552
+ gap: 0.2rem;
2553
+ padding: 0.05rem 0.4rem;
2554
+ border-radius: 0.375rem;
2555
+ border: 1px solid color-mix(in srgb, currentColor 25%, transparent);
2556
+ background: transparent;
2557
+ font: inherit;
2558
+ line-height: 1.4;
2559
+ cursor: help;
2560
+ color: var(--qt-text-secondary-fg, var(--color-muted-foreground));
2561
+ opacity: 0.8;
2562
+ user-select: none;
2563
+ white-space: nowrap;
2564
+ transition: color 150ms, background-color 150ms, border-color 150ms, opacity 150ms;
2565
+ }
2566
+
2567
+ /* The badge sits among the message action icons and answers the pointer the
2568
+ same way they do. */
2569
+ .qt-confirmation-badge:hover,
2570
+ .qt-confirmation-badge:focus-visible {
2571
+ opacity: 1;
2572
+ border-color: color-mix(in srgb, currentColor 45%, transparent);
2573
+ background: color-mix(in srgb, var(--color-muted) 50%, transparent);
2574
+ }
2575
+
2576
+ /* The tinted states (stood-by, amended) keep their own colour on hover; the
2577
+ quiet ones brighten to the foreground the way the action icons do. */
2578
+ .qt-confirmation-badge[data-confirmation-state="vouched"]:hover,
2579
+ .qt-confirmation-badge[data-confirmation-state="vouched"]:focus-visible,
2580
+ .qt-confirmation-badge[data-confirmation-state="unvetted"]:hover,
2581
+ .qt-confirmation-badge[data-confirmation-state="unvetted"]:focus-visible {
2582
+ color: var(--color-foreground);
2583
+ }
2584
+
2585
+ .qt-confirmation-badge:focus-visible {
2586
+ outline: 2px solid color-mix(in srgb, var(--color-foreground) 45%, transparent);
2587
+ outline-offset: 2px;
2588
+ }
2589
+
2590
+ .qt-chat-message-user .qt-confirmation-badge:hover,
2591
+ .qt-chat-message-user .qt-confirmation-badge:focus-visible {
2592
+ color: var(--qt-chat-user-fg);
2593
+ background: color-mix(in srgb, var(--qt-chat-user-fg) 15%, transparent);
2594
+ }
2595
+
2596
+ .qt-confirmation-badge-glyph {
2597
+ font-weight: 600;
2598
+ }
2599
+
2600
+ .qt-confirmation-badge[data-confirmation-state="stood-by"] {
2601
+ color: var(--qt-warning-box-fg, var(--qt-text-secondary-fg));
2602
+ opacity: 1;
2603
+ }
2604
+
2605
+ .qt-confirmation-badge[data-confirmation-state="amended"] {
2606
+ opacity: 1;
2607
+ }
2608
+
2609
+ /* ==========================================================================
2610
+ CHAT — STAFF ANNOUNCEMENTS
2611
+ Messages authored by a personified feature (the Librarian, the Host, Pascal
2612
+ the Croupier, …) rather than by a character. They summarise to a one-line
2613
+ bar, and a run of consecutive ones packs into a row of content-width chips.
2614
+ ========================================================================== */
2615
+
2616
+ /**
2617
+ * Collapsed bar for Staff-authored messages.
2618
+ * Single-line summary: dot · sender name · kind · timestamp · chevron.
2619
+ * Click to expand into the regular message body.
2620
+ */
2621
+ .qt-chat-system-bar {
2622
+ display: flex;
2623
+ align-items: center;
2624
+ gap: 0.625rem;
2625
+ width: 100%;
2626
+ padding: 0.25rem 0.625rem;
2627
+ margin: 0.125rem 0;
2628
+ background: var(--qt-chat-system-bar-bg);
2629
+ color: var(--qt-chat-system-bar-fg);
2630
+ border: 1px solid var(--qt-chat-system-bar-border);
2631
+ border-radius: var(--radius-sm, 0.25rem);
2632
+ font-size: 0.75rem;
2633
+ line-height: 1.2;
2634
+ text-align: left;
2635
+ cursor: pointer;
2636
+ transition: background-color 120ms ease;
2637
+ }
2638
+
2639
+ .qt-chat-system-bar:hover,
2640
+ .qt-chat-system-bar:focus-visible {
2641
+ background: var(--qt-chat-system-bar-hover-bg);
2642
+ outline: none;
2643
+ }
2644
+
2645
+ .qt-chat-system-bar-sender {
2646
+ color: var(--qt-chat-system-bar-sender-fg);
2647
+ font-weight: 600;
2648
+ white-space: nowrap;
2649
+ }
2650
+
2651
+ .qt-chat-system-bar-kind {
2652
+ flex: 1 1 auto;
2653
+ min-width: 0;
2654
+ font-style: italic;
2655
+ overflow: hidden;
2656
+ text-overflow: ellipsis;
2657
+ white-space: nowrap;
2658
+ }
2659
+
2660
+ /**
2661
+ * Whisper audience on an announcement bar or chip ("to Alice, Bob"). Wears the
2662
+ * same ink as the message body's whisper label so a private aside reads the
2663
+ * same whether it is collapsed to a chip or opened in full.
2664
+ */
2665
+ .qt-chat-system-bar-whisper {
2666
+ flex: 0 1 auto;
2667
+ min-width: 0;
2668
+ color: var(--qt-chat-whisper-label-fg);
2669
+ font-style: italic;
2670
+ overflow: hidden;
2671
+ text-overflow: ellipsis;
2672
+ white-space: nowrap;
2673
+ }
2674
+
2675
+ .qt-chat-system-bar-time {
2676
+ color: var(--qt-chat-system-bar-fg);
2677
+ opacity: 0.75;
2678
+ white-space: nowrap;
2679
+ }
2680
+
2681
+ .qt-chat-system-bar-chevron {
2682
+ flex-shrink: 0;
2683
+ width: 0.875rem;
2684
+ height: 0.875rem;
2685
+ opacity: 0.7;
2686
+ }
2687
+
2688
+ /**
2689
+ * Variant rendered at the top of an *expanded* Staff-authored message, giving
2690
+ * the reader a prominent click target to re-collapse it.
2691
+ */
2692
+ .qt-chat-system-bar-expanded {
2693
+ margin-bottom: 0.25rem;
2694
+ }
2695
+
2696
+ /**
2697
+ * Packed announcement chips. A run of consecutive *collapsed* Staff messages
2698
+ * renders as one flex-wrapping row of content-width chips instead of a
2699
+ * full-width bar each.
2700
+ */
2701
+ .qt-chat-announcement-group {
2702
+ display: flex;
2703
+ flex-wrap: wrap;
2704
+ gap: 0.375rem;
2705
+ width: 95%;
2706
+ max-width: var(--qt-chat-message-row-max-width);
2707
+ margin: 1.5rem auto 0;
2708
+ align-items: flex-start;
2709
+ }
2710
+
2711
+ /**
2712
+ * A single collapsed announcement, sized to its content (never full width).
2713
+ * Reuses the -sender / -kind / -time / -chevron element classes above; only the
2714
+ * -kind sizing differs (see the override below).
2715
+ */
2716
+ .qt-chat-announcement-chip {
2717
+ display: inline-flex;
2718
+ align-items: center;
2719
+ gap: 0.5rem;
2720
+ flex: 0 1 auto;
2721
+ min-width: 0;
2722
+ max-width: 100%;
2723
+ padding: 0.25rem 0.625rem;
2724
+ background: var(--qt-chat-system-bar-bg);
2725
+ color: var(--qt-chat-system-bar-fg);
2726
+ border: 1px solid var(--qt-chat-system-bar-border);
2727
+ border-radius: var(--radius-sm, 0.25rem);
2728
+ font-size: 0.75rem;
2729
+ line-height: 1.2;
2730
+ text-align: left;
2731
+ cursor: pointer;
2732
+ transition: background-color 120ms ease;
2733
+ }
2734
+
2735
+ .qt-chat-announcement-chip:hover,
2736
+ .qt-chat-announcement-chip:focus-visible {
2737
+ background: var(--qt-chat-system-bar-hover-bg);
2738
+ outline: none;
2739
+ }
2740
+
2741
+ /* Inside a chip the kind must not greedily fill the row; cap it so a long kind
2742
+ doesn't dominate a packed row. */
2743
+ .qt-chat-announcement-chip .qt-chat-system-bar-kind {
2744
+ flex: 0 1 auto;
2745
+ max-width: 22ch;
2746
+ }
2747
+
2748
+ /* Same cap for a long audience list — a whisper to five people must not push
2749
+ the timestamp and chevron off the chip. */
2750
+ .qt-chat-announcement-chip .qt-chat-system-bar-whisper {
2751
+ max-width: 18ch;
2752
+ }
2753
+
2754
+ /* A whispered announcement carries the whisper's border colour, so a private
2755
+ aside is distinguishable from a public one before it is ever expanded. */
2756
+ .qt-chat-announcement-chip-whisper {
2757
+ border-color: var(--qt-chat-whisper-label-fg);
2758
+ }
2759
+
2760
+ /**
2761
+ * Importance dot before the sender name. Filled for high/medium, hollow for
2762
+ * low, so the eye lands on what matters and skims past the low-noise chatter.
2763
+ */
2764
+ .qt-chat-announcement-dot {
2765
+ flex-shrink: 0;
2766
+ width: 0.5rem;
2767
+ height: 0.5rem;
2768
+ border-radius: 9999px;
2769
+ border: 1px solid transparent;
2770
+ }
2771
+
2772
+ .qt-chat-announcement-dot-high {
2773
+ background: var(--qt-chat-announcement-dot-high);
2774
+ }
2775
+
2776
+ .qt-chat-announcement-dot-medium {
2777
+ background: var(--qt-chat-announcement-dot-medium);
2778
+ }
2779
+
2780
+ .qt-chat-announcement-dot-low {
2781
+ background: transparent;
2782
+ border-color: var(--qt-chat-announcement-dot-low);
2783
+ }
2784
+
2785
+ /**
2786
+ * Outcome dot for a Pascal roll announcement, which replaces the importance dot:
2787
+ * a roll has a verdict of its own — success / partial / failure / info — and
2788
+ * that verdict is what the reader is looking for. Filled with the solid
2789
+ * --qt-alert-*-fg (the -border tints are alpha-thin and vanish at 8px); the
2790
+ * bar's leading accent below uses the -border tints, as .qt-pascal-result does.
2791
+ */
2792
+ .qt-chat-announcement-dot-outcome-success {
2793
+ background: var(--qt-alert-success-fg);
2794
+ }
2795
+
2796
+ .qt-chat-announcement-dot-outcome-partial {
2797
+ background: var(--qt-alert-warning-fg);
2798
+ }
2799
+
2800
+ .qt-chat-announcement-dot-outcome-failure {
2801
+ background: var(--qt-alert-error-fg);
2802
+ }
2803
+
2804
+ .qt-chat-announcement-dot-outcome-info {
2805
+ background: var(--qt-alert-info-fg);
2806
+ }
2807
+
2808
+ /**
2809
+ * The bar/chip of a Pascal roll wears the same .qt-pascal-result accent as the
2810
+ * outcome bubble itself, so one outcome reads identically wherever it is shown.
2811
+ *
2812
+ * These compound selectors only restate that accent: .qt-pascal-result is
2813
+ * declared above, and both wrappers set `border` and `padding` SHORTHANDS at
2814
+ * equal specificity, so the plain family would lose on source order. Nothing
2815
+ * new is styled here — change the accent itself at .qt-pascal-result.
2816
+ */
2817
+ .qt-chat-system-bar.qt-pascal-result,
2818
+ .qt-chat-announcement-chip.qt-pascal-result {
2819
+ border-left-width: 3px;
2820
+ border-left-color: var(--qt-alert-info-border);
2821
+ padding-left: 0.75rem;
2822
+ }
2823
+
2824
+ .qt-chat-system-bar.qt-pascal-result--success,
2825
+ .qt-chat-announcement-chip.qt-pascal-result--success {
2826
+ border-left-color: var(--qt-alert-success-border);
2827
+ }
2828
+
2829
+ .qt-chat-system-bar.qt-pascal-result--partial,
2830
+ .qt-chat-announcement-chip.qt-pascal-result--partial {
2831
+ border-left-color: var(--qt-alert-warning-border);
2832
+ }
2833
+
2834
+ .qt-chat-system-bar.qt-pascal-result--failure,
2835
+ .qt-chat-announcement-chip.qt-pascal-result--failure {
2836
+ border-left-color: var(--qt-alert-error-border);
2837
+ }
2838
+
2839
+ .qt-chat-system-bar.qt-pascal-result--info,
2840
+ .qt-chat-announcement-chip.qt-pascal-result--info {
2841
+ border-left-color: var(--qt-alert-info-border);
2842
+ }
2843
+
2844
+ /**
2845
+ * Deus Ex Machina — established facts in the Salon.
2846
+ *
2847
+ * Mirrors app/styles/qt-components/_chat.css. Built on existing tokens only (the --qt-alert-info-* family and --color-ring,
2848
+ * the focus-ring colour), so every bundled theme renders it without per-theme
2849
+ * work and the armed frame holds the focus ring's own contrast.
2850
+ *
2851
+ * - .qt-chat-composer-established-fact: the composer's editor wrapper while
2852
+ * `/deus` is armed — a frame and a faint tint, so the operator can see the
2853
+ * next line will be posted as fact.
2854
+ * - .qt-chat-message-established-fact: the small ribbon on an operator line
2855
+ * posted as fact.
2856
+ * - .qt-chat-established-fact: the accent on a machine fact's bar/chip.
2857
+ * - .qt-chat-established-fact-row / -band: a machine fact renders as a
2858
+ * full-width band (no avatar) rather than a speech bubble.
2859
+ */
2860
+ .qt-chat-composer-established-fact .qt-chat-composer-input {
2861
+ border-color: var(--color-ring);
2862
+ box-shadow: inset 0 0 0 1px var(--color-ring);
2863
+ background-image: linear-gradient(var(--qt-alert-info-bg), var(--qt-alert-info-bg));
2864
+ }
2865
+
2866
+ /* The ribbon sits on whatever the theme paints the speaker's bubble, so it
2867
+ takes the bubble's own text colour (every theme pairs those) and stands
2868
+ apart by weight and small caps rather than by a hue of its own. */
2869
+ .qt-chat-message-established-fact {
2870
+ font-size: 0.75rem;
2871
+ font-weight: 600;
2872
+ font-variant-caps: all-small-caps;
2873
+ letter-spacing: 0.04em;
2874
+ color: inherit;
2875
+ margin-bottom: 0.25rem;
2876
+ }
2877
+
2878
+ .qt-chat-system-bar.qt-chat-established-fact,
2879
+ .qt-chat-announcement-chip.qt-chat-established-fact {
2880
+ border-left-width: 3px;
2881
+ border-left-color: var(--color-ring);
2882
+ padding-left: 0.75rem;
2883
+ }
2884
+
2885
+ .qt-chat-established-fact-row {
2886
+ width: 100%;
2887
+ max-width: none;
2888
+ }
2889
+
2890
+ .qt-chat-established-fact-band {
2891
+ width: 100%;
2892
+ background: var(--qt-alert-info-bg);
2893
+ border: 1px solid var(--qt-alert-info-border);
2894
+ border-left: 3px solid var(--color-ring);
2895
+ box-shadow: none;
2896
+ }
2897
+
2898
+ /* The toggle that arms Deus Ex Machina, seated in the corner of the composer's
2899
+ "speaking as" portrait. A small frosted tile at rest; armed, it wears the
2900
+ composer frame's own ring and tint so the two read as one state. */
2901
+ .qt-chat-established-fact-toggle {
2902
+ display: inline-flex;
2903
+ align-items: center;
2904
+ justify-content: center;
2905
+ width: 1.625rem;
2906
+ height: 1.625rem;
2907
+ padding: 0;
2908
+ border: 1px solid var(--color-border);
2909
+ border-radius: var(--radius-sm);
2910
+ background-color: color-mix(in srgb, var(--color-background) 82%, transparent);
2911
+ color: var(--color-foreground);
2912
+ cursor: pointer;
2913
+ opacity: 0.85;
2914
+ transition: opacity 150ms ease, border-color 150ms ease, box-shadow 150ms ease;
2915
+ }
2916
+
2917
+ .qt-chat-established-fact-toggle:hover,
2918
+ .qt-chat-established-fact-toggle:focus-visible {
2919
+ opacity: 1;
2920
+ }
2921
+
2922
+ .qt-chat-established-fact-toggle:focus-visible {
2923
+ outline: 2px solid var(--color-ring);
2924
+ outline-offset: 1px;
2925
+ }
2926
+
2927
+ .qt-chat-established-fact-toggle[aria-pressed="true"] {
2928
+ opacity: 1;
2929
+ border-color: var(--color-ring);
2930
+ box-shadow: inset 0 0 0 1px var(--color-ring);
2931
+ background-image: linear-gradient(var(--qt-alert-info-bg), var(--qt-alert-info-bg));
2932
+ }
2933
+
2934
+ .qt-chat-established-fact-toggle:disabled {
2935
+ cursor: not-allowed;
2936
+ opacity: 0.5;
2937
+ }
2938
+
2939
+ /**
2940
+ * Silent message — inner thoughts and actions from character in silent mode.
2941
+ * Distinguished from whispers by a dotted border (vs dashed) and sage/teal tones.
2942
+ */
2943
+ .qt-chat-message-silent {
2944
+ background: var(--qt-chat-silent-bg);
2945
+ color: var(--qt-chat-silent-fg);
2946
+ border: 2px dotted var(--qt-chat-silent-border);
2947
+ font-style: italic;
2948
+ }
2949
+
2950
+ .qt-chat-silent-label {
2951
+ font-size: 0.75rem;
2952
+ color: var(--qt-chat-silent-label-fg);
2953
+ font-style: italic;
2954
+ margin-bottom: 0.25rem;
2955
+ }
2956
+
2957
+ /**
2958
+ * Regeneration — a line being re-rolled in place.
2959
+ *
2960
+ * Two states, one bubble. Before the first token the old line is still there
2961
+ * but visibly out of service (dimmed, desaturated, unselectable) under a plate
2962
+ * that says what is happening. From the first token the plate and the old line
2963
+ * are both gone and the new prose streams in their place.
2964
+ */
2965
+ .qt-chat-message-regenerating {
2966
+ border-color: color-mix(in srgb, var(--qt-response-status-streaming-fg) 45%, transparent);
2967
+ }
2968
+
2969
+ .qt-chat-regenerating {
2970
+ position: relative;
2971
+ }
2972
+
2973
+ .qt-chat-regenerating-original {
2974
+ opacity: 0.3;
2975
+ filter: grayscale(0.8);
2976
+ pointer-events: none;
2977
+ user-select: none;
2978
+ }
2979
+
2980
+ .qt-chat-regenerating-plate {
2981
+ position: absolute;
2982
+ inset: 0;
2983
+ display: flex;
2984
+ align-items: center;
2985
+ justify-content: center;
2986
+ gap: 0.5rem;
2987
+ color: var(--qt-response-status-streaming-fg);
2988
+ }
2989
+
2990
+ /* The words are in the bubble's own ink: the streaming green is a status
2991
+ accent, and on a mid-tone bubble it fell below 3:1. The green stays on the
2992
+ border and the quill. */
2993
+ .qt-chat-regenerating-plate-text {
2994
+ color: var(--qt-chat-regenerating-plate-fg, var(--qt-chat-assistant-fg, var(--color-foreground)));
2995
+ font-size: 0.875rem;
2996
+ line-height: 1.25rem;
2997
+ font-weight: 500;
2998
+ padding: 0.375rem 0.75rem;
2999
+ border-radius: 0.375rem;
3000
+ background: color-mix(in srgb, var(--qt-chat-assistant-bg) 88%, transparent);
3001
+ border: 1px solid color-mix(in srgb, var(--qt-response-status-streaming-fg) 35%, transparent);
3002
+ letter-spacing: 0.02em;
3003
+ }
3004
+
3005
+ /**
3006
+ * Message action bar — the per-message toolbar (copy, source, edit, delete,
3007
+ * regenerate, swipe arrows) along the bottom of a bubble.
3008
+ */
3009
+ .qt-chat-message-action-bar {
3010
+ display: flex;
3011
+ align-items: center;
3012
+ gap: 0.75rem;
3013
+ margin-top: 0.5rem;
3014
+ padding-top: 0.5rem;
3015
+ border-top: 1px solid color-mix(in srgb, var(--color-border) 50%, transparent);
3016
+ }
3017
+
3018
+ .qt-chat-message-action-bar-icons {
3019
+ display: flex;
3020
+ align-items: center;
3021
+ gap: 0.25rem;
3022
+ }
3023
+
3024
+ /** The bar of a line that is mid-replacement: nothing on it is safe to press. */
3025
+ .qt-chat-message-action-bar-disabled {
3026
+ pointer-events: none;
3027
+ opacity: 0.4;
3028
+ }
3029
+
3030
+ .qt-chat-message-action-icon {
3031
+ padding: 0.375rem;
3032
+ border-radius: 0.25rem;
3033
+ transition-property: color, background-color, border-color, text-decoration-color, fill, stroke;
3034
+ transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
3035
+ transition-duration: 150ms;
3036
+ color: var(--color-muted-foreground);
3037
+ cursor: pointer;
3038
+ }
3039
+
3040
+ .qt-chat-message-action-icon:hover {
3041
+ color: var(--color-foreground);
3042
+ background: color-mix(in srgb, var(--color-muted) 50%, transparent);
3043
+ }
3044
+
3045
+ .qt-chat-message-action-icon-danger:hover {
3046
+ color: var(--qt-status-danger-fg);
3047
+ background: color-mix(in srgb, var(--qt-status-danger-bg) 50%, transparent);
3048
+ }
3049
+
3050
+ .qt-chat-message-action-icon svg,
3051
+ .qt-chat-message-action-icon .qt-icon {
3052
+ width: 1rem;
3053
+ height: 1rem;
3054
+ }
3055
+
3056
+ /** User message action icons — light colours on the user bubble's ground. */
3057
+ .qt-chat-message-user .qt-chat-message-action-bar {
3058
+ border-top-color: color-mix(in srgb, var(--qt-chat-user-fg) 30%, transparent);
3059
+ }
3060
+
3061
+ .qt-chat-message-user .qt-chat-message-action-icon {
3062
+ color: color-mix(in srgb, var(--qt-chat-user-fg) 70%, transparent);
3063
+ }
3064
+
3065
+ .qt-chat-message-user .qt-chat-message-action-icon:hover {
3066
+ color: var(--qt-chat-user-fg);
3067
+ background: color-mix(in srgb, var(--qt-chat-user-fg) 15%, transparent);
3068
+ }
3069
+
3070
+ .qt-chat-message-user .qt-chat-message-action-icon-danger:hover {
3071
+ color: hsl(0 100% 85%);
3072
+ background: color-mix(in srgb, hsl(0 70% 50%) 25%, transparent);
3073
+ }
3074
+
3075
+ .qt-chat-message-action-timestamp {
3076
+ font-size: 0.75rem;
3077
+ line-height: 1rem;
3078
+ color: var(--color-muted-foreground);
3079
+ margin-left: auto;
3080
+ }
3081
+
3082
+ .qt-chat-message-user .qt-chat-message-action-timestamp {
3083
+ color: color-mix(in srgb, var(--qt-chat-user-fg) 70%, transparent);
3084
+ }
3085
+
3086
+ /**
3087
+ * Response status strip — the line above the composer that narrates a turn as
3088
+ * it happens ("Gathering memories and context...", "Ada is responding...",
3089
+ * "Regenerating Ada's reply..."). Coloured per stage.
3090
+ */
3091
+ .qt-chat-response-status {
3092
+ display: flex;
3093
+ align-items: center;
3094
+ gap: 0.5rem;
3095
+ padding: 0.375rem 0.75rem;
3096
+ font-size: 0.875rem;
3097
+ line-height: 1.25rem;
3098
+ margin-bottom: 0.5rem;
3099
+ border-radius: 0.375rem;
3100
+ background: var(--qt-response-status-bg);
3101
+ color: var(--qt-response-status-fg);
3102
+ border: 1px solid var(--qt-response-status-border);
3103
+ animation: qt-status-fade-in 150ms ease-out;
3104
+ }
3105
+
3106
+ .qt-chat-response-status-icon {
3107
+ flex-shrink: 0;
3108
+ width: 1rem;
3109
+ height: 1rem;
3110
+ }
3111
+
3112
+ .qt-chat-response-status-text {
3113
+ font-weight: 500;
3114
+ }
3115
+
3116
+ .qt-chat-response-status[data-stage="compressing"] {
3117
+ color: var(--qt-response-status-compressing-fg);
3118
+ border-color: color-mix(in srgb, var(--qt-response-status-compressing-fg) 30%, transparent);
3119
+ }
3120
+
3121
+ .qt-chat-response-status[data-stage="gathering"] {
3122
+ color: var(--qt-response-status-gathering-fg);
3123
+ border-color: color-mix(in srgb, var(--qt-response-status-gathering-fg) 30%, transparent);
3124
+ }
3125
+
3126
+ .qt-chat-response-status[data-stage="building"] {
3127
+ color: var(--qt-response-status-building-fg);
3128
+ border-color: color-mix(in srgb, var(--qt-response-status-building-fg) 30%, transparent);
3129
+ }
3130
+
3131
+ .qt-chat-response-status[data-stage="sending"] {
3132
+ color: var(--qt-response-status-sending-fg);
3133
+ border-color: color-mix(in srgb, var(--qt-response-status-sending-fg) 30%, transparent);
3134
+ }
3135
+
3136
+ .qt-chat-response-status[data-stage="streaming"] {
3137
+ color: var(--qt-response-status-streaming-fg);
3138
+ border-color: color-mix(in srgb, var(--qt-response-status-streaming-fg) 30%, transparent);
3139
+ }
3140
+
3141
+ .qt-chat-response-status[data-stage="regenerating"],
3142
+ .qt-chat-response-status[data-stage="saving"] {
3143
+ color: var(--qt-response-status-streaming-fg);
3144
+ border-color: color-mix(in srgb, var(--qt-response-status-streaming-fg) 30%, transparent);
3145
+ }
3146
+
3147
+ .qt-chat-response-status[data-stage="tool_executing"] {
3148
+ color: var(--qt-response-status-tool-fg);
3149
+ border-color: color-mix(in srgb, var(--qt-response-status-tool-fg) 30%, transparent);
3150
+ }
3151
+
3152
+ @keyframes qt-status-fade-in {
3153
+ from { opacity: 0; transform: translateY(-4px); }
3154
+ to { opacity: 1; transform: translateY(0); }
3155
+ }
3156
+
3157
+ @media (prefers-reduced-motion: reduce) {
3158
+ .qt-chat-response-status { animation: none; }
3159
+ .qt-chat-response-status-icon .animate-pulse { animation: none; }
3160
+ }
3161
+
3162
+ /**
3163
+ * Wardrobe action notice — inline summary of outfit changes.
3164
+ * Double border with warm amber/gold tones, distinct from whisper (dashed) and silent (dotted).
3165
+ */
3166
+ .qt-chat-wardrobe-notice {
3167
+ background: var(--qt-chat-wardrobe-bg);
3168
+ color: var(--qt-chat-wardrobe-fg);
3169
+ border: 3px double var(--qt-chat-wardrobe-border);
3170
+ border-radius: var(--radius-md, 0.375rem);
3171
+ padding: 0.5rem 0.75rem;
3172
+ margin-bottom: 0.5rem;
3173
+ font-size: 0.8125rem;
3174
+ line-height: 1.4;
3175
+ }
3176
+
3177
+ .qt-chat-wardrobe-label {
3178
+ font-size: 0.6875rem;
3179
+ color: var(--qt-chat-wardrobe-label-fg);
3180
+ font-weight: 600;
3181
+ text-transform: uppercase;
3182
+ letter-spacing: 0.05em;
3183
+ margin-bottom: 0.25rem;
3184
+ }
3185
+
3186
+ .qt-chat-wardrobe-summary {
3187
+ color: var(--qt-chat-wardrobe-fg);
3188
+ }
3189
+
3190
+ /**
3191
+ * Status badges for silent/absent participants
3192
+ */
3193
+ .qt-badge-silent {
3194
+ background: var(--qt-chat-silent-bg);
3195
+ color: var(--qt-chat-silent-label-fg);
3196
+ border: 1px solid var(--qt-chat-silent-border);
3197
+ border-radius: 9999px;
3198
+ padding: 0.125rem 0.5rem;
3199
+ font-weight: 600;
3200
+ font-size: 0.75rem;
3201
+ }
3202
+
3203
+ .qt-badge-absent {
3204
+ background: color-mix(in srgb, var(--color-muted) 40%, transparent);
3205
+ color: var(--color-muted-foreground);
3206
+ border: 1px solid var(--color-muted);
3207
+ border-radius: 9999px;
3208
+ padding: 0.125rem 0.5rem;
3209
+ font-weight: 600;
3210
+ font-size: 0.75rem;
3211
+ opacity: 0.8;
3212
+ }
3213
+
3214
+ /**
3215
+ * Status overlay on participant avatar — small icon badge in the
3216
+ * bottom-right corner, visible when sidebar is collapsed.
3217
+ */
3218
+ .qt-participant-status-overlay {
3219
+ position: absolute;
3220
+ bottom: -0.125rem;
3221
+ right: -0.125rem;
3222
+ width: 1.125rem;
3223
+ height: 1.125rem;
3224
+ border-radius: 9999px;
3225
+ display: flex;
3226
+ align-items: center;
3227
+ justify-content: center;
3228
+ border: 1.5px solid var(--color-background);
3229
+ z-index: 2;
3230
+ }
3231
+
3232
+ .qt-participant-status-overlay-silent {
3233
+ background: var(--qt-chat-silent-border);
3234
+ color: white;
3235
+ }
3236
+
3237
+ .qt-participant-status-overlay-absent {
3238
+ background: var(--color-muted);
3239
+ color: var(--color-muted-foreground);
3240
+ }
3241
+
3242
+ .qt-participant-card-silent {
3243
+ border-color: var(--qt-chat-silent-border);
3244
+ }
3245
+
3246
+ .qt-chat-composer {
3247
+ display: flex;
3248
+ align-items: flex-end;
3249
+ gap: 0.5rem;
3250
+ padding: 1rem;
3251
+ background-color: var(--color-background);
3252
+ border: 1px solid var(--color-border);
3253
+ border-radius: var(--radius-lg);
3254
+ }
3255
+
3256
+ .qt-chat-composer-input {
3257
+ flex: 1;
3258
+ min-height: 2.5rem;
3259
+ padding: 0.5rem 0.75rem;
3260
+ background-color: transparent;
3261
+ border: none;
3262
+ resize: none;
3263
+ font-family: inherit;
3264
+ font-size: 0.875rem;
3265
+ line-height: 1.5;
3266
+ color: var(--color-foreground);
3267
+ }
3268
+
3269
+ .qt-chat-composer-input:focus,
3270
+ .qt-chat-composer-input:focus-within {
3271
+ outline: none;
3272
+ }
3273
+
3274
+ /* Composer action buttons: Send, the soft interrupt (raise a hand) and the
3275
+ hard Stop. Mirrors app/styles/qt-components/_chat.css. */
3276
+ .qt-chat-composer-actions {
3277
+ display: flex;
3278
+ flex-direction: column;
3279
+ align-items: center;
3280
+ gap: 0.375rem;
3281
+ flex-shrink: 0;
3282
+ }
3283
+
3284
+ .qt-chat-composer-actions .qt-chat-composer-send {
3285
+ height: 2.5rem;
3286
+ width: 2.5rem;
3287
+ }
3288
+
3289
+ .qt-chat-composer-send {
3290
+ display: inline-flex;
3291
+ align-items: center;
3292
+ justify-content: center;
3293
+ height: 3rem;
3294
+ width: 3rem;
3295
+ border-radius: 9999px;
3296
+ transition: all 200ms;
3297
+ cursor: pointer;
3298
+ background: var(--qt-button-primary-bg);
3299
+ color: var(--qt-button-primary-fg);
3300
+ box-shadow: var(--qt-button-primary-shadow);
3301
+ }
3302
+
3303
+ .qt-chat-composer-send:focus-visible {
3304
+ outline: none;
3305
+ box-shadow: 0 0 0 2px var(--color-background), 0 0 0 4px var(--color-ring);
3306
+ }
3307
+
3308
+ .qt-chat-composer-send:disabled {
3309
+ opacity: 0.5;
3310
+ cursor: not-allowed;
3311
+ }
3312
+
3313
+ .qt-chat-composer-send:hover:not(:disabled) {
3314
+ background: var(--qt-button-primary-hover-bg);
3315
+ }
3316
+
3317
+ .qt-chat-continue-button {
3318
+ background: var(--qt-status-info-bg);
3319
+ color: var(--qt-status-info-fg);
3320
+ border: 1px solid var(--qt-status-info-border);
3321
+ }
3322
+
3323
+ .qt-chat-stop-button {
3324
+ background: var(--qt-status-danger-bg);
3325
+ color: var(--qt-status-danger-fg);
3326
+ border: 1px solid var(--qt-status-danger-border);
3327
+ }
3328
+
3329
+ .qt-chat-stop-button:hover:not(:disabled) {
3330
+ background: color-mix(in srgb, var(--qt-status-danger-bg) 70%, black);
3331
+ }
3332
+
3333
+ .qt-chat-interrupt-button {
3334
+ background: var(--qt-status-warning-bg);
3335
+ color: var(--qt-status-warning-fg);
3336
+ border: 1px solid var(--qt-status-warning-border);
3337
+ }
3338
+
3339
+ .qt-chat-interrupt-button:hover:not(:disabled) {
3340
+ background: color-mix(in srgb, var(--qt-status-warning-bg) 70%, black);
3341
+ }
3342
+
3343
+ .qt-chat-interrupt-button-raised {
3344
+ box-shadow: 0 0 0 3px color-mix(in srgb, var(--qt-status-warning-border) 45%, transparent);
3345
+ animation: qt-hand-raised-pulse 1.6s ease-in-out infinite;
3346
+ }
3347
+
3348
+ @keyframes qt-hand-raised-pulse {
3349
+ 0%, 100% { box-shadow: 0 0 0 3px color-mix(in srgb, var(--qt-status-warning-border) 45%, transparent); }
3350
+ 50% { box-shadow: 0 0 0 6px color-mix(in srgb, var(--qt-status-warning-border) 15%, transparent); }
3351
+ }
3352
+
3353
+ @media (prefers-reduced-motion: reduce) {
3354
+ .qt-chat-interrupt-button-raised { animation: none; }
3355
+ }
3356
+
3357
+ /* Composer punctuation warnings — painted by PunctuationLintPlugin through the
3358
+ CSS Custom Highlight API, so no element carries a class. Only background and
3359
+ text-decoration are styleable on a ::highlight. */
3360
+ ::highlight(qt-punctuation-warning) {
3361
+ background-color: var(--qt-punctuation-warning-bg);
3362
+ text-decoration: underline wavy var(--qt-punctuation-warning-underline);
3363
+ text-decoration-thickness: 2px;
3364
+ }
3365
+
3366
+ /* Prose mode (a template like Novel: unmarked narration, quoted dialogue).
3367
+ The no-dialogue tint covers every narrated run while the draft has no
3368
+ dialogue at all; the preview marks narration and ((asides)) the way the
3369
+ rendered message will set them. ::highlight cannot set font-style, so
3370
+ narration is told apart by colour rather than italics. */
3371
+ ::highlight(qt-punctuation-no-dialogue) {
3372
+ background-color: var(--qt-punctuation-no-dialogue-bg);
3373
+ text-decoration: underline dotted var(--qt-punctuation-no-dialogue-underline);
3374
+ text-decoration-thickness: 2px;
3375
+ }
3376
+
3377
+ ::highlight(qt-composer-narration) {
3378
+ color: var(--qt-composer-narration-fg);
3379
+ background-color: var(--qt-composer-narration-bg);
3380
+ }
3381
+
3382
+ ::highlight(qt-composer-ooc) {
3383
+ color: var(--qt-composer-ooc-fg);
3384
+ background-color: var(--qt-composer-ooc-bg);
2017
3385
  }
2018
3386
 
2019
- .qt-chat-regenerating {
3387
+ /* Lexical editor rich text node styles */
3388
+ .qt-lexical-contenteditable {
3389
+ overflow-y: auto;
2020
3390
  position: relative;
2021
3391
  }
2022
3392
 
2023
- .qt-chat-regenerating-original {
2024
- opacity: 0.3;
2025
- filter: grayscale(0.8);
2026
- pointer-events: none;
2027
- user-select: none;
3393
+ .qt-lexical-contenteditable [contenteditable] {
3394
+ outline: none;
3395
+ min-height: 1.5em;
2028
3396
  }
2029
3397
 
2030
- .qt-chat-regenerating-plate {
3398
+ .qt-lexical-placeholder {
3399
+ color: var(--color-muted-foreground);
3400
+ font-size: 0.875rem;
3401
+ pointer-events: none;
2031
3402
  position: absolute;
2032
- inset: 0;
2033
- display: flex;
2034
- align-items: center;
2035
- justify-content: center;
2036
- gap: 0.5rem;
2037
- color: var(--qt-response-status-streaming-fg);
3403
+ top: 0;
3404
+ left: 0;
3405
+ padding: var(--qt-input-padding-y, 0.5rem) var(--qt-input-padding-x, 0.75rem);
3406
+ overflow: hidden;
3407
+ text-overflow: ellipsis;
3408
+ white-space: nowrap;
2038
3409
  }
2039
3410
 
2040
- /* The words are in the bubble's own ink: the streaming green is a status
2041
- accent, and on a mid-tone bubble it fell below 3:1. The green stays on the
2042
- border and the quill. */
2043
- .qt-chat-regenerating-plate-text {
2044
- color: var(--qt-chat-regenerating-plate-fg, var(--qt-chat-assistant-fg, var(--color-foreground)));
2045
- font-size: 0.875rem;
2046
- line-height: 1.25rem;
2047
- font-weight: 500;
2048
- padding: 0.375rem 0.75rem;
2049
- border-radius: 0.375rem;
2050
- background: color-mix(in srgb, var(--qt-chat-assistant-bg) 88%, transparent);
2051
- border: 1px solid color-mix(in srgb, var(--qt-response-status-streaming-fg) 35%, transparent);
2052
- letter-spacing: 0.02em;
3411
+ .qt-lexical-root {
3412
+ outline: none;
3413
+ min-height: 1.5em;
2053
3414
  }
2054
3415
 
2055
- /**
2056
- * Message action bar — the per-message toolbar (copy, source, edit, delete,
2057
- * regenerate, swipe arrows) along the bottom of a bubble.
2058
- */
2059
- .qt-chat-message-action-bar {
2060
- display: flex;
2061
- align-items: center;
2062
- gap: 0.75rem;
2063
- margin-top: 0.5rem;
2064
- padding-top: 0.5rem;
2065
- border-top: 1px solid color-mix(in srgb, var(--color-border) 50%, transparent);
3416
+ .qt-lexical-paragraph {
3417
+ margin: 0;
2066
3418
  }
2067
3419
 
2068
- .qt-chat-message-action-bar-icons {
2069
- display: flex;
2070
- align-items: center;
2071
- gap: 0.25rem;
3420
+ .qt-lexical-bold {
3421
+ font-weight: 700;
2072
3422
  }
2073
3423
 
2074
- /** The bar of a line that is mid-replacement: nothing on it is safe to press. */
2075
- .qt-chat-message-action-bar-disabled {
2076
- pointer-events: none;
2077
- opacity: 0.4;
3424
+ .qt-lexical-italic {
3425
+ font-style: italic;
2078
3426
  }
2079
3427
 
2080
- .qt-chat-message-action-icon {
2081
- padding: 0.375rem;
2082
- border-radius: 0.25rem;
2083
- transition-property: color, background-color, border-color, text-decoration-color, fill, stroke;
2084
- transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
2085
- transition-duration: 150ms;
2086
- color: var(--color-muted-foreground);
2087
- cursor: pointer;
3428
+ .qt-lexical-underline {
3429
+ text-decoration: underline;
2088
3430
  }
2089
3431
 
2090
- .qt-chat-message-action-icon:hover {
2091
- color: var(--color-foreground);
2092
- background: color-mix(in srgb, var(--color-muted) 50%, transparent);
3432
+ .qt-lexical-strikethrough {
3433
+ text-decoration: line-through;
2093
3434
  }
2094
3435
 
2095
- .qt-chat-message-action-icon-danger:hover {
2096
- color: var(--qt-status-danger-fg);
2097
- background: color-mix(in srgb, var(--qt-status-danger-bg) 50%, transparent);
3436
+ .qt-lexical-code {
3437
+ font-family: monospace;
3438
+ font-size: 0.75rem;
3439
+ background: rgba(0, 0, 0, 0.1);
3440
+ padding: 0.1em 0.3em;
3441
+ border-radius: 0.2em;
2098
3442
  }
2099
3443
 
2100
- .qt-chat-message-action-icon svg,
2101
- .qt-chat-message-action-icon .qt-icon {
2102
- width: 1rem;
2103
- height: 1rem;
3444
+ .qt-lexical-h1 {
3445
+ font-size: 1.25rem;
3446
+ font-weight: bold;
3447
+ margin: 0.5em 0 0.25em;
2104
3448
  }
2105
3449
 
2106
- /** User message action icons — light colours on the user bubble's ground. */
2107
- .qt-chat-message-user .qt-chat-message-action-bar {
2108
- border-top-color: color-mix(in srgb, var(--qt-chat-user-fg) 30%, transparent);
3450
+ .qt-lexical-h2 {
3451
+ font-size: 1.125rem;
3452
+ font-weight: bold;
3453
+ margin: 0.4em 0 0.2em;
2109
3454
  }
2110
3455
 
2111
- .qt-chat-message-user .qt-chat-message-action-icon {
2112
- color: color-mix(in srgb, var(--qt-chat-user-fg) 70%, transparent);
3456
+ .qt-lexical-h3 {
3457
+ font-size: 1rem;
3458
+ font-weight: 600;
3459
+ margin: 0.3em 0 0.15em;
2113
3460
  }
2114
3461
 
2115
- .qt-chat-message-user .qt-chat-message-action-icon:hover {
2116
- color: var(--qt-chat-user-fg);
2117
- background: color-mix(in srgb, var(--qt-chat-user-fg) 15%, transparent);
3462
+ .qt-lexical-h4 {
3463
+ font-size: 0.875rem;
3464
+ font-weight: 600;
3465
+ margin: 0.25em 0 0.1em;
2118
3466
  }
2119
3467
 
2120
- .qt-chat-message-user .qt-chat-message-action-icon-danger:hover {
2121
- color: hsl(0 100% 85%);
2122
- background: color-mix(in srgb, hsl(0 70% 50%) 25%, transparent);
3468
+ .qt-lexical-h5 {
3469
+ font-size: 0.75rem;
3470
+ font-weight: 600;
3471
+ margin: 0.2em 0 0.1em;
2123
3472
  }
2124
3473
 
2125
- .qt-chat-message-action-timestamp {
3474
+ .qt-lexical-h6 {
2126
3475
  font-size: 0.75rem;
2127
- line-height: 1rem;
2128
- color: var(--color-muted-foreground);
2129
- margin-left: auto;
3476
+ font-weight: 500;
3477
+ margin: 0.2em 0 0.1em;
2130
3478
  }
2131
3479
 
2132
- .qt-chat-message-user .qt-chat-message-action-timestamp {
2133
- color: color-mix(in srgb, var(--qt-chat-user-fg) 70%, transparent);
3480
+ .qt-lexical-ul {
3481
+ list-style-type: disc;
3482
+ padding-left: 1.5rem;
3483
+ margin: 0.25em 0;
2134
3484
  }
2135
3485
 
2136
- /**
2137
- * Response status strip — the line above the composer that narrates a turn as
2138
- * it happens ("Gathering memories and context...", "Ada is responding...",
2139
- * "Regenerating Ada's reply..."). Coloured per stage.
2140
- */
2141
- .qt-chat-response-status {
2142
- display: flex;
2143
- align-items: center;
2144
- gap: 0.5rem;
2145
- padding: 0.375rem 0.75rem;
2146
- font-size: 0.875rem;
2147
- line-height: 1.25rem;
2148
- margin-bottom: 0.5rem;
2149
- border-radius: 0.375rem;
2150
- background: var(--qt-response-status-bg);
2151
- color: var(--qt-response-status-fg);
2152
- border: 1px solid var(--qt-response-status-border);
2153
- animation: qt-status-fade-in 150ms ease-out;
3486
+ .qt-lexical-ol {
3487
+ list-style-type: decimal;
3488
+ padding-left: 1.5rem;
3489
+ margin: 0.25em 0;
2154
3490
  }
2155
3491
 
2156
- .qt-chat-response-status-icon {
2157
- flex-shrink: 0;
2158
- width: 1rem;
2159
- height: 1rem;
3492
+ .qt-lexical-li {
3493
+ margin: 0.1em 0;
2160
3494
  }
2161
3495
 
2162
- .qt-chat-response-status-text {
2163
- font-weight: 500;
3496
+ /*
3497
+ * Wrapper item for a sub-list. Lexical represents nesting as a list item whose
3498
+ * only child is another list, so this <li> is structure rather than content —
3499
+ * left to itself it draws the parent list's bullet right beside the sub-list's
3500
+ * own first bullet.
3501
+ */
3502
+ .qt-lexical-li-nested {
3503
+ list-style-type: none;
3504
+ margin: 0;
2164
3505
  }
2165
3506
 
2166
- .qt-chat-response-status[data-stage="compressing"] {
2167
- color: var(--qt-response-status-compressing-fg);
2168
- border-color: color-mix(in srgb, var(--qt-response-status-compressing-fg) 30%, transparent);
3507
+ .qt-lexical-li-nested::before,
3508
+ .qt-lexical-li-nested::after {
3509
+ display: none;
2169
3510
  }
2170
3511
 
2171
- .qt-chat-response-status[data-stage="gathering"] {
2172
- color: var(--qt-response-status-gathering-fg);
2173
- border-color: color-mix(in srgb, var(--qt-response-status-gathering-fg) 30%, transparent);
3512
+ /* Checklist items */
3513
+ .qt-lexical-checklist {
3514
+ list-style: none;
3515
+ padding-left: 0;
2174
3516
  }
2175
3517
 
2176
- .qt-chat-response-status[data-stage="building"] {
2177
- color: var(--qt-response-status-building-fg);
2178
- border-color: color-mix(in srgb, var(--qt-response-status-building-fg) 30%, transparent);
3518
+ .qt-lexical-li-checked,
3519
+ .qt-lexical-li-unchecked {
3520
+ position: relative;
3521
+ padding-left: 1.5rem;
3522
+ list-style: none;
3523
+ margin: 0.15em 0;
2179
3524
  }
2180
3525
 
2181
- .qt-chat-response-status[data-stage="sending"] {
2182
- color: var(--qt-response-status-sending-fg);
2183
- border-color: color-mix(in srgb, var(--qt-response-status-sending-fg) 30%, transparent);
3526
+ .qt-lexical-li-checked::before,
3527
+ .qt-lexical-li-unchecked::before {
3528
+ content: '';
3529
+ position: absolute;
3530
+ left: 0;
3531
+ top: 0.25rem;
3532
+ width: 1rem;
3533
+ height: 1rem;
3534
+ border-radius: 0.25rem;
3535
+ border: 1px solid var(--qt-border-color, var(--color-border));
3536
+ cursor: pointer;
2184
3537
  }
2185
3538
 
2186
- .qt-chat-response-status[data-stage="streaming"] {
2187
- color: var(--qt-response-status-streaming-fg);
2188
- border-color: color-mix(in srgb, var(--qt-response-status-streaming-fg) 30%, transparent);
3539
+ .qt-lexical-li-checked::before {
3540
+ background: var(--color-primary);
3541
+ border-color: var(--color-primary);
3542
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='white'%3E%3Cpath d='M12.207 4.793a1 1 0 010 1.414l-5 5a1 1 0 01-1.414 0l-2-2a1 1 0 011.414-1.414L6.5 9.086l4.293-4.293a1 1 0 011.414 0z'/%3E%3C/svg%3E");
3543
+ background-size: 12px 12px;
3544
+ background-position: center;
3545
+ background-repeat: no-repeat;
2189
3546
  }
2190
3547
 
2191
- .qt-chat-response-status[data-stage="regenerating"],
2192
- .qt-chat-response-status[data-stage="saving"] {
2193
- color: var(--qt-response-status-streaming-fg);
2194
- border-color: color-mix(in srgb, var(--qt-response-status-streaming-fg) 30%, transparent);
3548
+ .qt-lexical-li-checked {
3549
+ opacity: 0.6;
3550
+ text-decoration: line-through;
2195
3551
  }
2196
3552
 
2197
- .qt-chat-response-status[data-stage="tool_executing"] {
2198
- color: var(--qt-response-status-tool-fg);
2199
- border-color: color-mix(in srgb, var(--qt-response-status-tool-fg) 30%, transparent);
3553
+ .qt-lexical-blockquote {
3554
+ border-left: 4px solid rgba(0, 0, 0, 0.2);
3555
+ padding-left: 0.75rem;
3556
+ font-style: italic;
3557
+ margin: 0.25em 0;
2200
3558
  }
2201
3559
 
2202
- @keyframes qt-status-fade-in {
2203
- from { opacity: 0; transform: translateY(-4px); }
2204
- to { opacity: 1; transform: translateY(0); }
3560
+ .qt-lexical-link {
3561
+ text-decoration: underline;
3562
+ color: var(--color-primary);
3563
+ }
3564
+
3565
+ .qt-lexical-code-block {
3566
+ font-family: monospace;
3567
+ font-size: 0.75rem;
3568
+ background: rgba(0, 0, 0, 0.15);
3569
+ padding: 0.5em 0.75em;
3570
+ border-radius: 0.3em;
3571
+ margin: 0.25em 0;
3572
+ overflow-x: auto;
3573
+ tab-size: 2;
2205
3574
  }
2206
3575
 
2207
- @media (prefers-reduced-motion: reduce) {
2208
- .qt-chat-response-status { animation: none; }
2209
- .qt-chat-response-status-icon .animate-pulse { animation: none; }
2210
- }
3576
+ /* ==========================================================================
3577
+ CHAT MESSAGE LINKS
3578
+ ========================================================================== */
2211
3579
 
2212
3580
  /**
2213
- * Wardrobe action notice — inline summary of outfit changes.
2214
- * Double border with warm amber/gold tones, distinct from whisper (dashed) and silent (dotted).
3581
+ * Links inside rendered chat messages must be visibly clickable. The default
3582
+ * .qt-link decoration is `none`, which leaves markdown links indistinguishable
3583
+ * from surrounding prose. Force a colored, underlined treatment in this scope.
2215
3584
  */
2216
- .qt-chat-wardrobe-notice {
2217
- background: var(--qt-chat-wardrobe-bg);
2218
- color: var(--qt-chat-wardrobe-fg);
2219
- border: 3px double var(--qt-chat-wardrobe-border);
2220
- border-radius: var(--radius-md, 0.375rem);
2221
- padding: 0.5rem 0.75rem;
2222
- margin-bottom: 0.5rem;
2223
- font-size: 0.8125rem;
2224
- line-height: 1.4;
3585
+ .qt-chat-message-content a,
3586
+ .qt-chat-message-content a.qt-link {
3587
+ color: var(--qt-link-color, var(--color-primary));
3588
+ text-decoration: underline;
3589
+ text-underline-offset: 2px;
2225
3590
  }
2226
-
2227
- .qt-chat-wardrobe-label {
2228
- font-size: 0.6875rem;
2229
- color: var(--qt-chat-wardrobe-label-fg);
2230
- font-weight: 600;
2231
- text-transform: uppercase;
2232
- letter-spacing: 0.05em;
2233
- margin-bottom: 0.25rem;
3591
+ .qt-chat-message-content a:hover,
3592
+ .qt-chat-message-content a.qt-link:hover {
3593
+ color: var(--qt-link-hover-color, var(--color-primary));
3594
+ text-decoration: underline;
2234
3595
  }
2235
3596
 
2236
- .qt-chat-wardrobe-summary {
2237
- color: var(--qt-chat-wardrobe-fg);
2238
- }
3597
+ /* ==========================================================================
3598
+ DOCUMENT MODE - Split-panel layout (Scriptorium Phase 3.5)
3599
+ ========================================================================== */
2239
3600
 
2240
3601
  /**
2241
- * Status badges for silent/absent participants
3602
+ * Split layout container for Document Mode
3603
+ * Wraps the chat pane + divider + document pane inside .qt-chat-main
2242
3604
  */
2243
- .qt-badge-silent {
2244
- background: var(--qt-chat-silent-bg);
2245
- color: var(--qt-chat-silent-label-fg);
2246
- border: 1px solid var(--qt-chat-silent-border);
2247
- border-radius: 9999px;
2248
- padding: 0.125rem 0.5rem;
2249
- font-weight: 600;
2250
- font-size: 0.75rem;
3605
+ .qt-doc-split-layout {
3606
+ display: flex;
3607
+ flex-direction: row;
3608
+ height: 100%;
3609
+ overflow: hidden;
2251
3610
  }
2252
3611
 
2253
- .qt-badge-absent {
2254
- background: color-mix(in srgb, var(--color-muted) 40%, transparent);
2255
- color: var(--color-muted-foreground);
2256
- border: 1px solid var(--color-muted);
2257
- border-radius: 9999px;
2258
- padding: 0.125rem 0.5rem;
2259
- font-weight: 600;
2260
- font-size: 0.75rem;
2261
- opacity: 0.8;
3612
+ /**
3613
+ * Chat pane in split mode
3614
+ * Min-width prevents the chat from becoming unusable
3615
+ */
3616
+ .qt-doc-chat-pane {
3617
+ display: flex;
3618
+ flex-direction: column;
3619
+ height: 100%;
3620
+ overflow: hidden;
3621
+ min-width: 320px;
2262
3622
  }
2263
3623
 
2264
3624
  /**
2265
- * Status overlay on participant avatar — small icon badge in the
2266
- * bottom-right corner, visible when sidebar is collapsed.
3625
+ * Draggable divider between chat and document panes
3626
+ * 6px wide handle with a visible grip indicator
2267
3627
  */
2268
- .qt-participant-status-overlay {
2269
- position: absolute;
2270
- bottom: -0.125rem;
2271
- right: -0.125rem;
2272
- width: 1.125rem;
2273
- height: 1.125rem;
2274
- border-radius: 9999px;
3628
+ .qt-doc-divider {
3629
+ flex-shrink: 0;
3630
+ height: 100%;
2275
3631
  display: flex;
2276
3632
  align-items: center;
2277
3633
  justify-content: center;
2278
- border: 1.5px solid var(--color-background);
2279
- z-index: 2;
2280
- }
2281
-
2282
- .qt-participant-status-overlay-silent {
2283
- background: var(--qt-chat-silent-border);
2284
- color: white;
3634
+ width: 6px;
3635
+ cursor: col-resize;
3636
+ background: var(--color-border);
3637
+ transition: background 0.15s ease;
3638
+ user-select: none;
3639
+ touch-action: none;
2285
3640
  }
2286
3641
 
2287
- .qt-participant-status-overlay-absent {
2288
- background: var(--color-muted);
2289
- color: var(--color-muted-foreground);
3642
+ .qt-doc-divider:hover,
3643
+ .qt-doc-divider.qt-doc-divider-active {
3644
+ background: var(--color-primary);
2290
3645
  }
2291
3646
 
2292
- .qt-participant-card-silent {
2293
- border-color: var(--qt-chat-silent-border);
3647
+ /** Grip dots indicator on the divider */
3648
+ .qt-doc-divider-grip {
3649
+ display: flex;
3650
+ flex-direction: column;
3651
+ gap: 0.25rem;
2294
3652
  }
2295
3653
 
2296
- .qt-chat-composer {
2297
- display: flex;
2298
- align-items: flex-end;
2299
- gap: 0.5rem;
2300
- padding: 1rem;
2301
- background-color: var(--color-background);
2302
- border: 1px solid var(--color-border);
2303
- border-radius: var(--radius-lg);
3654
+ .qt-doc-divider-grip span {
3655
+ display: block;
3656
+ width: 3px;
3657
+ height: 3px;
3658
+ border-radius: 50%;
3659
+ background: var(--color-muted-foreground);
2304
3660
  }
2305
3661
 
2306
- .qt-chat-composer-input {
2307
- flex: 1;
2308
- min-height: 2.5rem;
2309
- padding: 0.5rem 0.75rem;
2310
- background-color: transparent;
2311
- border: none;
2312
- resize: none;
2313
- font-family: inherit;
2314
- font-size: 0.875rem;
2315
- line-height: 1.5;
2316
- color: var(--color-foreground);
3662
+ .qt-doc-divider:hover .qt-doc-divider-grip span,
3663
+ .qt-doc-divider.qt-doc-divider-active .qt-doc-divider-grip span {
3664
+ background: var(--qt-primary-fg, var(--color-primary-foreground));
2317
3665
  }
2318
3666
 
2319
- .qt-chat-composer-input:focus,
2320
- .qt-chat-composer-input:focus-within {
2321
- outline: none;
3667
+ /**
3668
+ * Document pane container
3669
+ * Sits to the right of the divider in split mode
3670
+ */
3671
+ .qt-doc-pane {
3672
+ display: flex;
3673
+ flex-direction: column;
3674
+ height: 100%;
3675
+ overflow: hidden;
3676
+ min-width: 360px;
3677
+ background: color-mix(in srgb, var(--qt-content-bg) 92%, transparent);
3678
+ border-left: 1px solid var(--color-border);
2322
3679
  }
2323
3680
 
2324
- /* Composer action buttons: Send, the soft interrupt (raise a hand) and the
2325
- hard Stop. Mirrors app/styles/qt-components/_chat.css. */
2326
- .qt-chat-composer-actions {
3681
+ /**
3682
+ * Vertical (top/bottom) split inside the right pane — used when both
3683
+ * Document Mode and Terminal Mode are active. Document on top, terminal
3684
+ * on bottom, with a draggable horizontal divider between them.
3685
+ */
3686
+ .qt-doc-vertical-split-layout {
2327
3687
  display: flex;
2328
3688
  flex-direction: column;
2329
- align-items: center;
2330
- gap: 0.375rem;
2331
- flex-shrink: 0;
3689
+ height: 100%;
3690
+ width: 100%;
3691
+ overflow: hidden;
2332
3692
  }
2333
3693
 
2334
- .qt-chat-composer-actions .qt-chat-composer-send {
2335
- height: 2.5rem;
2336
- width: 2.5rem;
3694
+ .qt-doc-vertical-pane {
3695
+ display: flex;
3696
+ flex-direction: column;
3697
+ width: 100%;
3698
+ overflow: hidden;
3699
+ min-height: 200px;
2337
3700
  }
2338
3701
 
2339
- .qt-chat-composer-send {
2340
- display: inline-flex;
3702
+ .qt-doc-vertical-divider {
3703
+ flex-shrink: 0;
3704
+ width: 100%;
3705
+ display: flex;
2341
3706
  align-items: center;
2342
3707
  justify-content: center;
2343
- height: 3rem;
2344
- width: 3rem;
2345
- border-radius: 9999px;
2346
- transition: all 200ms;
2347
- cursor: pointer;
2348
- background: var(--qt-button-primary-bg);
2349
- color: var(--qt-button-primary-fg);
2350
- box-shadow: var(--qt-button-primary-shadow);
2351
- }
2352
-
2353
- .qt-chat-composer-send:focus-visible {
2354
- outline: none;
2355
- box-shadow: 0 0 0 2px var(--color-background), 0 0 0 4px var(--color-ring);
2356
- }
2357
-
2358
- .qt-chat-composer-send:disabled {
2359
- opacity: 0.5;
2360
- cursor: not-allowed;
2361
- }
2362
-
2363
- .qt-chat-composer-send:hover:not(:disabled) {
2364
- background: var(--qt-button-primary-hover-bg);
3708
+ height: 6px;
3709
+ cursor: row-resize;
3710
+ background: var(--color-border);
3711
+ transition: background 0.15s ease;
3712
+ user-select: none;
3713
+ touch-action: none;
2365
3714
  }
2366
3715
 
2367
- .qt-chat-continue-button {
2368
- background: var(--qt-status-info-bg);
2369
- color: var(--qt-status-info-fg);
2370
- border: 1px solid var(--qt-status-info-border);
3716
+ .qt-doc-vertical-divider:hover,
3717
+ .qt-doc-vertical-divider.qt-doc-vertical-divider-active {
3718
+ background: var(--color-primary);
2371
3719
  }
2372
3720
 
2373
- .qt-chat-stop-button {
2374
- background: var(--qt-status-danger-bg);
2375
- color: var(--qt-status-danger-fg);
2376
- border: 1px solid var(--qt-status-danger-border);
3721
+ .qt-doc-vertical-divider-grip {
3722
+ display: flex;
3723
+ flex-direction: row;
3724
+ gap: 0.25rem;
2377
3725
  }
2378
3726
 
2379
- .qt-chat-stop-button:hover:not(:disabled) {
2380
- background: color-mix(in srgb, var(--qt-status-danger-bg) 70%, black);
3727
+ .qt-doc-vertical-divider-grip span {
3728
+ display: block;
3729
+ width: 3px;
3730
+ height: 3px;
3731
+ border-radius: 50%;
3732
+ background: var(--color-muted-foreground);
2381
3733
  }
2382
3734
 
2383
- .qt-chat-interrupt-button {
2384
- background: var(--qt-status-warning-bg);
2385
- color: var(--qt-status-warning-fg);
2386
- border: 1px solid var(--qt-status-warning-border);
3735
+ .qt-doc-vertical-divider:hover .qt-doc-vertical-divider-grip span,
3736
+ .qt-doc-vertical-divider.qt-doc-vertical-divider-active .qt-doc-vertical-divider-grip span {
3737
+ background: var(--qt-primary-fg, var(--color-primary-foreground));
2387
3738
  }
2388
3739
 
2389
- .qt-chat-interrupt-button:hover:not(:disabled) {
2390
- background: color-mix(in srgb, var(--qt-status-warning-bg) 70%, black);
3740
+ /**
3741
+ * Focus mode — document pane fills the entire main area
3742
+ * Chat pane is hidden
3743
+ */
3744
+ .qt-doc-focus-mode .qt-doc-editor-area {
3745
+ max-width: 640px;
3746
+ margin-left: auto;
3747
+ margin-right: auto;
2391
3748
  }
2392
3749
 
2393
- .qt-chat-interrupt-button-raised {
2394
- box-shadow: 0 0 0 3px color-mix(in srgb, var(--qt-status-warning-border) 45%, transparent);
2395
- animation: qt-hand-raised-pulse 1.6s ease-in-out infinite;
3750
+ /**
3751
+ * Document header bar
3752
+ * Contains title, badges, and mode toggle buttons
3753
+ */
3754
+ .qt-doc-header {
3755
+ display: flex;
3756
+ align-items: center;
3757
+ gap: 0.5rem;
3758
+ padding-left: 1rem;
3759
+ padding-right: 1rem;
3760
+ padding-top: 0.5rem;
3761
+ padding-bottom: 0.5rem;
3762
+ flex-shrink: 0;
3763
+ border-bottom: 1px solid var(--color-border);
3764
+ background: color-mix(in srgb, var(--qt-content-bg) 95%, transparent);
2396
3765
  }
2397
3766
 
2398
- @keyframes qt-hand-raised-pulse {
2399
- 0%, 100% { box-shadow: 0 0 0 3px color-mix(in srgb, var(--qt-status-warning-border) 45%, transparent); }
2400
- 50% { box-shadow: 0 0 0 6px color-mix(in srgb, var(--qt-status-warning-border) 15%, transparent); }
3767
+ /** Green "Document" badge in the header */
3768
+ .qt-doc-badge {
3769
+ display: inline-flex;
3770
+ align-items: center;
3771
+ padding-left: 0.5rem;
3772
+ padding-right: 0.5rem;
3773
+ padding-top: 0.125rem;
3774
+ padding-bottom: 0.125rem;
3775
+ border-radius: 9999px;
3776
+ font-size: 0.75rem;
3777
+ line-height: 1rem;
3778
+ font-weight: 500;
3779
+ background: var(--qt-success-bg, color-mix(in srgb, #22c55e 15%, var(--qt-content-bg)));
3780
+ color: var(--qt-success-fg, #22c55e);
2401
3781
  }
2402
3782
 
2403
- @media (prefers-reduced-motion: reduce) {
2404
- .qt-chat-interrupt-button-raised { animation: none; }
3783
+ /** Editable document title in the header */
3784
+ .qt-doc-title {
3785
+ flex: 1 1 0%;
3786
+ font-size: 0.875rem;
3787
+ line-height: 1.25rem;
3788
+ font-weight: 500;
3789
+ overflow: hidden;
3790
+ text-overflow: ellipsis;
3791
+ white-space: nowrap;
3792
+ color: var(--color-foreground);
2405
3793
  }
2406
3794
 
2407
- /* Composer punctuation warnings — painted by PunctuationLintPlugin through the
2408
- CSS Custom Highlight API, so no element carries a class. Only background and
2409
- text-decoration are styleable on a ::highlight. */
2410
- ::highlight(qt-punctuation-warning) {
2411
- background-color: var(--qt-punctuation-warning-bg);
2412
- text-decoration: underline wavy var(--qt-punctuation-warning-underline);
2413
- text-decoration-thickness: 2px;
3795
+ .qt-doc-title-input {
3796
+ font-size: 0.875rem;
3797
+ line-height: 1.25rem;
3798
+ font-weight: 500;
3799
+ width: 100%;
3800
+ background-color: transparent;
3801
+ border-width: 0 0 1px;
3802
+ border-style: dashed;
3803
+ border-color: var(--color-border);
3804
+ color: var(--color-foreground);
3805
+ outline: none;
2414
3806
  }
2415
3807
 
2416
- /* Prose mode (a template like Novel: unmarked narration, quoted dialogue).
2417
- The no-dialogue tint covers every narrated run while the draft has no
2418
- dialogue at all; the preview marks narration and ((asides)) the way the
2419
- rendered message will set them. ::highlight cannot set font-style, so
2420
- narration is told apart by colour rather than italics. */
2421
- ::highlight(qt-punctuation-no-dialogue) {
2422
- background-color: var(--qt-punctuation-no-dialogue-bg);
2423
- text-decoration: underline dotted var(--qt-punctuation-no-dialogue-underline);
2424
- text-decoration-thickness: 2px;
3808
+ .qt-doc-title-input:focus {
3809
+ border-color: var(--color-primary);
2425
3810
  }
2426
3811
 
2427
- ::highlight(qt-composer-narration) {
2428
- color: var(--qt-composer-narration-fg);
2429
- background-color: var(--qt-composer-narration-bg);
3812
+ /** Header action buttons (maximize, show chat, exit) */
3813
+ .qt-doc-header-button {
3814
+ padding: 0.375rem;
3815
+ border-radius: 0.25rem;
3816
+ transition-property: color, background-color, border-color, text-decoration-color, fill, stroke;
3817
+ transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
3818
+ transition-duration: 150ms;
3819
+ color: var(--color-muted-foreground);
2430
3820
  }
2431
3821
 
2432
- ::highlight(qt-composer-ooc) {
2433
- color: var(--qt-composer-ooc-fg);
2434
- background-color: var(--qt-composer-ooc-bg);
3822
+ .qt-doc-header-button:hover {
3823
+ color: var(--color-foreground);
3824
+ background: var(--qt-hover-bg, color-mix(in srgb, var(--color-foreground) 10%, transparent));
2435
3825
  }
2436
3826
 
2437
- /* Lexical editor rich text node styles */
2438
- .qt-lexical-contenteditable {
2439
- overflow-y: auto;
2440
- position: relative;
3827
+ /** Compact qtap:// URL line shown under the document header */
3828
+ .qt-doc-uri-row {
3829
+ display: flex;
3830
+ align-items: center;
3831
+ gap: 0.5rem;
3832
+ padding-left: 1rem;
3833
+ padding-right: 1rem;
3834
+ padding-top: 0.25rem;
3835
+ padding-bottom: 0.25rem;
3836
+ flex-shrink: 0;
3837
+ border-bottom: 1px solid var(--color-border);
3838
+ background: color-mix(in srgb, var(--qt-content-bg) 95%, transparent);
2441
3839
  }
2442
3840
 
2443
- .qt-lexical-contenteditable [contenteditable] {
2444
- outline: none;
2445
- min-height: 1.5em;
3841
+ .qt-doc-uri-label {
3842
+ font-size: 10px;
3843
+ font-weight: 600;
3844
+ text-transform: uppercase;
3845
+ letter-spacing: 0.025em;
3846
+ color: var(--color-muted-foreground);
2446
3847
  }
2447
3848
 
2448
- .qt-lexical-placeholder {
2449
- color: var(--color-muted-foreground);
2450
- font-size: 0.875rem;
2451
- pointer-events: none;
2452
- position: absolute;
2453
- top: 0;
2454
- left: 0;
2455
- padding: var(--qt-input-padding-y, 0.5rem) var(--qt-input-padding-x, 0.75rem);
3849
+ .qt-doc-uri-value {
3850
+ min-width: 0;
3851
+ flex: 1 1 0%;
2456
3852
  overflow: hidden;
2457
3853
  text-overflow: ellipsis;
2458
3854
  white-space: nowrap;
3855
+ font-size: 0.75rem;
3856
+ line-height: 1rem;
3857
+ font-family: var(--font-mono);
3858
+ color: var(--color-muted-foreground);
2459
3859
  }
2460
3860
 
2461
- .qt-lexical-root {
2462
- outline: none;
2463
- min-height: 1.5em;
3861
+ .qt-doc-uri-copy-button {
3862
+ padding: 0.25rem;
3863
+ border-radius: 0.25rem;
3864
+ transition-property: color, background-color, border-color, text-decoration-color, fill, stroke;
3865
+ transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
3866
+ transition-duration: 150ms;
3867
+ color: var(--color-muted-foreground);
2464
3868
  }
2465
3869
 
2466
- .qt-lexical-paragraph {
2467
- margin: 0;
3870
+ .qt-doc-uri-copy-button:hover {
3871
+ color: var(--color-foreground);
3872
+ background: var(--qt-hover-bg, color-mix(in srgb, var(--color-foreground) 10%, transparent));
2468
3873
  }
2469
3874
 
2470
- .qt-lexical-bold {
2471
- font-weight: 700;
3875
+ /**
3876
+ * Document editor toolbar
3877
+ * Formatting buttons for the document pane, always visible
3878
+ */
3879
+ .qt-doc-toolbar {
3880
+ display: flex;
3881
+ align-items: center;
3882
+ gap: 0.25rem;
3883
+ padding-left: 1rem;
3884
+ padding-right: 1rem;
3885
+ padding-top: 0.375rem;
3886
+ padding-bottom: 0.375rem;
3887
+ flex-shrink: 0;
3888
+ border-bottom: 1px solid var(--color-border);
3889
+ background: color-mix(in srgb, var(--qt-content-bg) 95%, transparent);
2472
3890
  }
2473
3891
 
2474
- .qt-lexical-italic {
2475
- font-style: italic;
3892
+ /**
3893
+ * Document editor area
3894
+ * Fills available vertical space, independently scrollable
3895
+ */
3896
+ .qt-doc-editor-area {
3897
+ flex: 1 1 0%;
3898
+ overflow-y: auto;
3899
+ position: relative;
3900
+ padding: 1rem 1.5rem;
3901
+ background: var(--color-background);
2476
3902
  }
2477
3903
 
2478
- .qt-lexical-underline {
2479
- text-decoration: underline;
3904
+ /**
3905
+ * Status bar at the bottom of the document pane
3906
+ */
3907
+ .qt-doc-status-bar {
3908
+ display: flex;
3909
+ align-items: center;
3910
+ gap: 1rem;
3911
+ padding-left: 1rem;
3912
+ padding-right: 1rem;
3913
+ padding-top: 0.25rem;
3914
+ padding-bottom: 0.25rem;
3915
+ flex-shrink: 0;
3916
+ font-size: 0.75rem;
3917
+ line-height: 1rem;
3918
+ border-top: 1px solid var(--color-border);
3919
+ color: var(--color-muted-foreground);
3920
+ background: color-mix(in srgb, var(--qt-content-bg) 95%, transparent);
2480
3921
  }
2481
3922
 
2482
- .qt-lexical-strikethrough {
2483
- text-decoration: line-through;
3923
+ .qt-doc-status-item {
3924
+ display: inline-flex;
3925
+ align-items: center;
3926
+ gap: 0.25rem;
2484
3927
  }
2485
3928
 
2486
- .qt-lexical-code {
2487
- font-family: monospace;
2488
- font-size: 0.75rem;
2489
- background: rgba(0, 0, 0, 0.1);
2490
- padding: 0.1em 0.3em;
2491
- border-radius: 0.2em;
3929
+ /** Saving indicator dot animation */
3930
+ .qt-doc-status-saving {
3931
+ display: inline-block;
3932
+ width: 0.375rem;
3933
+ height: 0.375rem;
3934
+ border-radius: 9999px;
3935
+ background: var(--qt-warning-fg, #f59e0b);
3936
+ animation: qt-doc-pulse 1s ease-in-out infinite;
2492
3937
  }
2493
3938
 
2494
- .qt-lexical-h1 {
2495
- font-size: 1.25rem;
2496
- font-weight: bold;
2497
- margin: 0.5em 0 0.25em;
3939
+ @keyframes qt-doc-pulse {
3940
+ 0%, 100% { opacity: 0.4; }
3941
+ 50% { opacity: 1; }
2498
3942
  }
2499
3943
 
2500
- .qt-lexical-h2 {
2501
- font-size: 1.125rem;
2502
- font-weight: bold;
2503
- margin: 0.4em 0 0.2em;
3944
+ /** Saved indicator dot */
3945
+ .qt-doc-status-saved {
3946
+ display: inline-block;
3947
+ width: 0.375rem;
3948
+ height: 0.375rem;
3949
+ border-radius: 9999px;
3950
+ background: var(--qt-success-fg, #22c55e);
2504
3951
  }
2505
3952
 
2506
- .qt-lexical-h3 {
2507
- font-size: 1rem;
2508
- font-weight: 600;
2509
- margin: 0.3em 0 0.15em;
3953
+ /**
3954
+ * "Open document" button in composer toolbar
3955
+ * Hidden at viewport widths below 1026px (not enough space for split pane)
3956
+ * When used inside qt-chat-toolbar, inherits toolbar button styling
3957
+ */
3958
+ @media (max-width: 1025px) {
3959
+ .qt-doc-open-button {
3960
+ display: none !important;
3961
+ }
2510
3962
  }
2511
3963
 
2512
- .qt-lexical-h4 {
2513
- font-size: 0.875rem;
2514
- font-weight: 600;
2515
- margin: 0.25em 0 0.1em;
3964
+ /* Document Gutter */
3965
+ .qt-doc-editor-with-gutter {
3966
+ display: flex;
3967
+ flex-direction: row;
3968
+ flex: 1;
3969
+ min-height: 0;
3970
+ overflow-y: auto;
2516
3971
  }
2517
3972
 
2518
- .qt-lexical-h5 {
2519
- font-size: 0.75rem;
2520
- font-weight: 600;
2521
- margin: 0.2em 0 0.1em;
3973
+ .qt-doc-gutter {
3974
+ position: relative;
3975
+ flex-shrink: 0;
3976
+ width: 20px;
3977
+ border-right: 1px solid var(--qt-border-color, rgba(128, 128, 128, 0.2));
2522
3978
  }
2523
3979
 
2524
- .qt-lexical-h6 {
2525
- font-size: 0.75rem;
2526
- font-weight: 500;
2527
- margin: 0.2em 0 0.1em;
3980
+ .qt-doc-gutter-change {
3981
+ position: absolute;
3982
+ left: 6px;
3983
+ width: 3px;
3984
+ border-radius: 1.5px;
3985
+ background-color: var(--qt-gutter-change-color, #3b82f6);
3986
+ opacity: 0.6;
2528
3987
  }
2529
3988
 
2530
- .qt-lexical-ul {
2531
- list-style-type: disc;
2532
- padding-left: 1.5rem;
2533
- margin: 0.25em 0;
3989
+ .qt-doc-gutter-eye {
3990
+ position: absolute;
3991
+ left: 2px;
3992
+ width: 16px;
3993
+ height: 16px;
3994
+ color: var(--qt-gutter-eye-color, #f59e0b);
3995
+ opacity: 0.85;
3996
+ pointer-events: none;
2534
3997
  }
2535
3998
 
2536
- .qt-lexical-ol {
2537
- list-style-type: decimal;
2538
- padding-left: 1.5rem;
2539
- margin: 0.25em 0;
2540
- }
3999
+ /* ==========================================================================
4000
+ CHAT SIDEBAR RESIZER
4001
+ ========================================================================== */
2541
4002
 
2542
- .qt-lexical-li {
2543
- margin: 0.1em 0;
4003
+ /**
4004
+ * Drag handle on the inner (left) edge of the expanded sidebar.
4005
+ * Transparent until hovered/active so it doesn't read as a second border.
4006
+ * Visuals mirror .qt-doc-divider / .qt-doc-divider-grip.
4007
+ */
4008
+ .qt-chat-sidebar-resizer {
4009
+ position: absolute;
4010
+ top: 0;
4011
+ bottom: 0;
4012
+ left: 0;
4013
+ width: 10px;
4014
+ transform: translateX(-50%);
4015
+ z-index: 20;
4016
+ cursor: col-resize;
4017
+ user-select: none;
4018
+ touch-action: none;
4019
+ display: flex;
4020
+ align-items: center;
4021
+ justify-content: center;
2544
4022
  }
2545
4023
 
2546
- /*
2547
- * Wrapper item for a sub-list. Lexical represents nesting as a list item whose
2548
- * only child is another list, so this <li> is structure rather than content —
2549
- * left to itself it draws the parent list's bullet right beside the sub-list's
2550
- * own first bullet.
2551
- */
2552
- .qt-lexical-li-nested {
2553
- list-style-type: none;
2554
- margin: 0;
4024
+ .qt-chat-sidebar-resizer::before {
4025
+ content: '';
4026
+ position: absolute;
4027
+ top: 0;
4028
+ bottom: 0;
4029
+ left: 50%;
4030
+ width: 2px;
4031
+ transform: translateX(-50%);
4032
+ background: transparent;
4033
+ transition: background 0.15s ease;
2555
4034
  }
2556
4035
 
2557
- .qt-lexical-li-nested::before,
2558
- .qt-lexical-li-nested::after {
2559
- display: none;
4036
+ .qt-chat-sidebar-resizer:hover::before,
4037
+ .qt-chat-sidebar-resizer:focus-visible::before,
4038
+ .qt-chat-sidebar-resizer-active::before {
4039
+ background: var(--color-primary);
2560
4040
  }
2561
4041
 
2562
- /* Checklist items */
2563
- .qt-lexical-checklist {
2564
- list-style: none;
2565
- padding-left: 0;
4042
+ .qt-chat-sidebar-resizer:focus-visible {
4043
+ outline: none;
2566
4044
  }
2567
4045
 
2568
- .qt-lexical-li-checked,
2569
- .qt-lexical-li-unchecked {
4046
+ .qt-chat-sidebar-resizer-grip {
4047
+ display: flex;
4048
+ flex-direction: column;
4049
+ gap: 0.25rem;
2570
4050
  position: relative;
2571
- padding-left: 1.5rem;
2572
- list-style: none;
2573
- margin: 0.15em 0;
4051
+ z-index: 1;
4052
+ opacity: 0;
4053
+ transition: opacity 0.15s ease;
2574
4054
  }
2575
4055
 
2576
- .qt-lexical-li-checked::before,
2577
- .qt-lexical-li-unchecked::before {
2578
- content: '';
2579
- position: absolute;
2580
- left: 0;
2581
- top: 0.25rem;
2582
- width: 1rem;
2583
- height: 1rem;
2584
- border-radius: 0.25rem;
2585
- border: 1px solid var(--qt-border-color, rgba(0, 0, 0, 0.3));
2586
- cursor: pointer;
4056
+ .qt-chat-sidebar-resizer:hover .qt-chat-sidebar-resizer-grip,
4057
+ .qt-chat-sidebar-resizer:focus-visible .qt-chat-sidebar-resizer-grip,
4058
+ .qt-chat-sidebar-resizer-active .qt-chat-sidebar-resizer-grip {
4059
+ opacity: 1;
2587
4060
  }
2588
4061
 
2589
- .qt-lexical-li-checked::before {
2590
- background: hsl(var(--primary, 220 90% 56%));
2591
- border-color: hsl(var(--primary, 220 90% 56%));
2592
- background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='white'%3E%3Cpath d='M12.207 4.793a1 1 0 010 1.414l-5 5a1 1 0 01-1.414 0l-2-2a1 1 0 011.414-1.414L6.5 9.086l4.293-4.293a1 1 0 011.414 0z'/%3E%3C/svg%3E");
2593
- background-size: 12px 12px;
2594
- background-position: center;
2595
- background-repeat: no-repeat;
4062
+ .qt-chat-sidebar-resizer-grip span {
4063
+ display: block;
4064
+ width: 3px;
4065
+ height: 3px;
4066
+ border-radius: 50%;
4067
+ background: var(--color-muted-foreground);
2596
4068
  }
2597
4069
 
2598
- .qt-lexical-li-checked {
2599
- opacity: 0.6;
2600
- text-decoration: line-through;
4070
+ /* ==========================================================================
4071
+ MEMORY SOURCE HIGHLIGHT
4072
+ Applied when scrolling to a message from memory provenance link
4073
+ ========================================================================== */
4074
+
4075
+ /**
4076
+ * Highlight animation for message when navigated from memory source link
4077
+ */
4078
+ .qt-memory-source-highlight {
4079
+ animation: memory-highlight-pulse 1s ease-in-out 2;
4080
+ position: relative;
2601
4081
  }
2602
4082
 
2603
- .qt-lexical-blockquote {
2604
- border-left: 4px solid rgba(0, 0, 0, 0.2);
2605
- padding-left: 0.75rem;
2606
- font-style: italic;
2607
- margin: 0.25em 0;
4083
+ .qt-memory-source-highlight::after {
4084
+ content: '';
4085
+ position: absolute;
4086
+ inset: -4px;
4087
+ border: 2px solid var(--color-primary);
4088
+ border-radius: var(--qt-chat-message-radius);
4089
+ pointer-events: none;
4090
+ animation: memory-highlight-border 3s ease-out forwards;
2608
4091
  }
2609
4092
 
2610
- .qt-lexical-link {
2611
- text-decoration: underline;
2612
- color: hsl(var(--primary, 220 90% 56%));
4093
+ @keyframes memory-highlight-pulse {
4094
+ 0%, 100% {
4095
+ background-color: transparent;
4096
+ }
4097
+ 50% {
4098
+ background-color: color-mix(in srgb, var(--color-primary) 10%, transparent);
4099
+ }
2613
4100
  }
2614
4101
 
2615
- .qt-lexical-code-block {
2616
- font-family: monospace;
2617
- font-size: 0.75rem;
2618
- background: rgba(0, 0, 0, 0.15);
2619
- padding: 0.5em 0.75em;
2620
- border-radius: 0.3em;
2621
- margin: 0.25em 0;
2622
- overflow-x: auto;
2623
- tab-size: 2;
4102
+ @keyframes memory-highlight-border {
4103
+ 0% {
4104
+ opacity: 1;
4105
+ }
4106
+ 80% {
4107
+ opacity: 1;
4108
+ }
4109
+ 100% {
4110
+ opacity: 0;
4111
+ }
2624
4112
  }
2625
4113
 
2626
4114
  /* ==========================================================================
@@ -2670,7 +4158,7 @@
2670
4158
  }
2671
4159
 
2672
4160
  .qt-formatting-button:hover:not(:disabled) {
2673
- background: var(--qt-content-bg-hover);
4161
+ background: var(--qt-content-bg-hover, var(--color-muted));
2674
4162
  border-color: var(--color-foreground);
2675
4163
  }
2676
4164
 
@@ -2960,7 +4448,7 @@
2960
4448
  flex: none;
2961
4449
  font-size: 0.75rem;
2962
4450
  line-height: 1rem;
2963
- color: var(--qt-text-secondary-fg, var(--qt-text-secondary));
4451
+ color: var(--qt-text-secondary-fg, var(--color-muted-foreground));
2964
4452
  }
2965
4453
 
2966
4454
  .qt-typeahead-empty {
@@ -2968,7 +4456,7 @@
2968
4456
  text-align: center;
2969
4457
  font-size: 0.875rem;
2970
4458
  line-height: 1.25rem;
2971
- color: var(--qt-text-secondary-fg, var(--qt-text-secondary));
4459
+ color: var(--qt-text-secondary-fg, var(--color-muted-foreground));
2972
4460
  }
2973
4461
 
2974
4462
  /* ==========================================================================
@@ -3007,7 +4495,7 @@
3007
4495
  line-height: 1rem;
3008
4496
  font-weight: 600;
3009
4497
  background: var(--qt-popover-bg);
3010
- color: var(--qt-text-secondary-fg, var(--qt-text-secondary));
4498
+ color: var(--qt-text-secondary-fg, var(--color-muted-foreground));
3011
4499
  }
3012
4500
 
3013
4501
  .qt-emoji-picker-row {
@@ -3030,7 +4518,7 @@
3030
4518
  }
3031
4519
 
3032
4520
  .qt-emoji-picker-cell:hover {
3033
- background: var(--qt-content-bg-hover);
4521
+ background: var(--qt-content-bg-hover, var(--color-muted));
3034
4522
  }
3035
4523
 
3036
4524
  .qt-emoji-picker-cell:focus-visible {
@@ -3045,7 +4533,7 @@
3045
4533
  text-align: center;
3046
4534
  font-size: 0.875rem;
3047
4535
  line-height: 1.25rem;
3048
- color: var(--qt-text-secondary-fg, var(--qt-text-secondary));
4536
+ color: var(--qt-text-secondary-fg, var(--color-muted-foreground));
3049
4537
  }
3050
4538
 
3051
4539
  /* Lexical table styling */