.panel { display: flex; flex-direction: column; height: 100%; min-height: 0; } .messages { flex: 1 1 auto; min-height: 0; /* Smaller, denser chat text (cascades into user bubble + assistant markdown + tool cards; the explicit-size Mantine labels keep their own size). */ font-size: var(--mantine-font-size-xs); } .messageRow { margin-bottom: var(--mantine-spacing-md); } .userBubble { background: var(--mantine-color-gray-light); border-radius: var(--mantine-radius-md); padding: 8px 12px; white-space: pre-wrap; overflow-wrap: break-word; word-break: break-word; } /* Rendered markdown for assistant messages. Keep block margins compact. */ .markdown { overflow-wrap: break-word; word-break: break-word; } .markdown p { margin-block-start: 0; margin-block-end: 0.5em; } .markdown pre { background: var(--mantine-color-gray-light); border-radius: var(--mantine-radius-sm); padding: 8px; overflow-x: auto; } .markdown code { font-size: 0.85em; } .markdown ul, .markdown ol { margin-block-start: 0; margin-block-end: 0.5em; padding-inline-start: 1.4em; } /* Animated three-dot "typing" indicator shown while the agent is thinking but has not yet produced any visible text/tool parts. */ .typingDots { display: inline-flex; align-items: center; gap: 4px; } .typingDots span { width: 5px; height: 5px; border-radius: 50%; background: var(--mantine-color-dimmed, var(--mantine-color-gray-5)); opacity: 0.4; animation: aiTypingBounce 1.2s infinite ease-in-out; } .typingDots span:nth-child(2) { animation-delay: 0.2s; } .typingDots span:nth-child(3) { animation-delay: 0.4s; } @keyframes aiTypingBounce { 0%, 80%, 100% { transform: translateY(0); opacity: 0.4; } 40% { /* Bounce height is driven by --bounce so reduced-motion can dampen it (below) without disabling the animation outright. */ transform: translateY(var(--bounce, -6px)); opacity: 1; } } /* Respect reduced-motion preferences: keep a smaller bounce instead of a full stop, so the "thinking" indicator still reads as active rather than frozen. */ @media (prefers-reduced-motion: reduce) { .typingDots span { --bounce: -3px; } } .toolCard { border: 1px solid light-dark(var(--mantine-color-gray-3), var(--mantine-color-dark-4)); border-radius: var(--mantine-radius-sm); padding: 6px 10px; margin-bottom: 6px; background: light-dark(var(--mantine-color-gray-0), var(--mantine-color-dark-6)); } /* Collapsible "Thinking" (reasoning) block: a subtle left rule, dimmer than the answer so it reads as secondary thinking context above the real answer. */ .reasoningBlock { border-left: 2px solid light-dark(var(--mantine-color-gray-3), var(--mantine-color-dark-4)); padding-left: 8px; } .reasoningText { margin-top: 4px; font-size: var(--mantine-font-size-xs); color: light-dark(var(--mantine-color-gray-7), var(--mantine-color-dark-1)); white-space: pre-wrap; } .reasoningText p { margin: 0 0 4px; } .inputWrapper { flex: 0 0 auto; padding-top: var(--mantine-spacing-xs); } .conversationItem { cursor: pointer; border-radius: var(--mantine-radius-sm); } .conversationItem:hover { background: var(--mantine-color-gray-light); } .conversationItemActive { background: var(--mantine-color-gray-light); } /* Pending messages queued by the user while a turn is still streaming. They are sent automatically, FIFO, once the current turn finishes. */ .queuedList { padding-bottom: var(--mantine-spacing-xs); } .queuedItem { background: var(--mantine-color-gray-light); border-radius: var(--mantine-radius-sm); padding: 4px 8px; } .queuedIcon { flex: none; color: var(--mantine-color-dimmed); } .queuedText { flex: 1; min-width: 0; color: var(--mantine-color-dimmed); white-space: pre-wrap; overflow-wrap: break-word; word-break: break-word; }