Files
fusion/packages/dashboard/app/components/QuickChatFAB.css
Fusion 91f187f9ff feat(FN-3603): improve mobile chat with jump-to-latest and bubble width fix
This merge implements FN-3603, adding jump-to-latest controls for the chat view and improving mobile bubble width layout, with corresponding CSS updates in ChatView and QuickChatFAB components. It also includes documentation for the new mobile chat controls, a fix for workspace lint regex escaping,

Fusion-Task-Id: FN-3603
2026-05-06 13:38:23 -07:00

1226 lines
32 KiB
CSS

/* ── Quick Chat FAB ──────────────────────────────────────────────── */
/* Position set via inline style from useDraggable */
.quick-chat-fab {
--quick-chat-fab-size: calc(var(--space-xl) * 2);
position: fixed;
width: var(--quick-chat-fab-size);
height: var(--quick-chat-fab-size);
border-radius: 50%;
border: 1px solid color-mix(in srgb, var(--todo) 45%, var(--border));
background: var(--todo);
color: var(--cta-text);
display: inline-flex;
align-items: center;
justify-content: center;
box-shadow: var(--quick-chat-fab-shadow);
cursor: grab;
touch-action: none;
z-index: 1000;
transition: transform var(--transition-fast), box-shadow var(--transition-fast), filter var(--transition-fast);
}
.quick-chat-fab:hover {
transform: translateY(var(--quick-chat-fab-lift));
box-shadow: var(--quick-chat-fab-shadow-hover);
filter: brightness(1.04);
}
.quick-chat-fab:focus-visible {
outline: none;
box-shadow: var(--focus-ring-strong);
}
/* Disable hover effects during drag for responsiveness */
.quick-chat-fab[data-dragging="true"] {
cursor: grabbing;
transform: scale(1.1);
transition: none;
}
.quick-chat-fab--hidden {
opacity: 0;
pointer-events: none;
visibility: hidden;
}
/* Always-mounted invisible input. Focused inside the FAB click gesture
to claim the iOS soft keyboard before the real composer input renders.
Must be focusable (no `display: none`, no `visibility: hidden`) and big
enough that iOS treats focus as a real intent — so we tuck it offscreen
instead of hiding it. `font-size: 16px` defeats the iOS focus-zoom. */
.quick-chat-stealth-input {
position: fixed;
bottom: 0;
left: 0;
width: 1px;
height: 1px;
padding: 0;
margin: 0;
border: 0;
opacity: 0;
pointer-events: none;
font-size: 16px;
z-index: -1;
}
/* Position set via inline style from useDraggable */
.quick-chat-panel {
--quick-chat-min-width: 280px;
--quick-chat-min-height: 260px;
position: fixed;
width: 320px;
height: 400px;
min-width: var(--quick-chat-min-width);
min-height: var(--quick-chat-min-height);
display: flex;
flex-direction: column;
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius-lg);
box-shadow: var(--shadow-lg);
overflow: hidden;
z-index: 1001;
}
.quick-chat-resize-handle {
position: absolute;
z-index: 2;
background: transparent;
/* Faint accent line appears on hover to indicate resizability */
transition: background var(--transition-fast);
}
/* Edge handles — inset matches corner handle size so they don't overlap. */
.quick-chat-resize-handle[data-resize-direction="n"] {
cursor: n-resize;
top: 0;
left: var(--space-lg);
right: var(--space-lg);
height: calc(var(--space-xs) + (var(--space-xs) / 2));
}
.quick-chat-resize-handle[data-resize-direction="s"] {
cursor: s-resize;
bottom: 0;
left: var(--space-lg);
right: var(--space-lg);
height: calc(var(--space-xs) + (var(--space-xs) / 2));
}
.quick-chat-resize-handle[data-resize-direction="e"] {
cursor: e-resize;
top: var(--space-lg);
right: 0;
bottom: var(--space-lg);
width: calc(var(--space-xs) + (var(--space-xs) / 2));
}
.quick-chat-resize-handle[data-resize-direction="w"] {
cursor: w-resize;
top: var(--space-lg);
left: 0;
bottom: var(--space-lg);
width: calc(var(--space-xs) + (var(--space-xs) / 2));
}
/* Corner handles — sized to clear the panel's 12px border-radius so the
diagonal hit target reaches outside the curve. */
.quick-chat-resize-handle[data-resize-direction="nw"] {
cursor: nw-resize;
top: 0;
left: 0;
width: var(--space-lg);
height: var(--space-lg);
}
.quick-chat-resize-handle[data-resize-direction="ne"] {
cursor: ne-resize;
top: 0;
right: 0;
width: var(--space-lg);
height: var(--space-lg);
}
.quick-chat-resize-handle[data-resize-direction="sw"] {
cursor: sw-resize;
bottom: 0;
left: 0;
width: var(--space-lg);
height: var(--space-lg);
}
.quick-chat-resize-handle[data-resize-direction="se"] {
cursor: se-resize;
bottom: 0;
right: 0;
width: var(--space-lg);
height: var(--space-lg);
}
/* Subtle hover accent on edge handles */
.quick-chat-resize-handle[data-resize-direction="n"]:hover,
.quick-chat-resize-handle[data-resize-direction="s"]:hover {
background: linear-gradient(
to bottom,
transparent 30%,
color-mix(in srgb, var(--border) 60%, transparent) 50%,
transparent 70%
);
}
.quick-chat-resize-handle[data-resize-direction="e"]:hover,
.quick-chat-resize-handle[data-resize-direction="w"]:hover {
background: linear-gradient(
to right,
transparent 30%,
color-mix(in srgb, var(--border) 60%, transparent) 50%,
transparent 70%
);
}
/* Subtle hover accent on corner handles — small radial dot that hints at
the diagonal grip without competing with the panel's rounded border. */
.quick-chat-resize-handle[data-resize-direction="nw"]:hover,
.quick-chat-resize-handle[data-resize-direction="ne"]:hover,
.quick-chat-resize-handle[data-resize-direction="sw"]:hover,
.quick-chat-resize-handle[data-resize-direction="se"]:hover {
background: radial-gradient(
circle at center,
color-mix(in srgb, var(--border) 70%, transparent) 0%,
color-mix(in srgb, var(--border) 30%, transparent) 50%,
transparent 75%
);
}
.quick-chat-panel-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: calc(var(--space-sm) + (var(--space-xs) / 2)) var(--space-md);
border-bottom: 1px solid var(--border);
background: color-mix(in srgb, var(--surface) 88%, var(--card));
}
.quick-chat-panel-header h3 {
margin: 0;
font-size: var(--space-md);
font-weight: 600;
color: var(--text);
}
.quick-chat-panel-title-wrap {
display: flex;
align-items: center;
gap: var(--space-sm);
min-width: 0;
}
.quick-chat-model-tag {
display: inline-flex;
align-items: center;
max-width: 18ch;
padding: var(--space-xs) var(--space-sm);
border-radius: var(--radius-pill);
border: 1px solid color-mix(in srgb, var(--todo) 35%, var(--border));
background: color-mix(in srgb, var(--todo) 14%, transparent);
color: var(--text);
font-size: calc(var(--space-sm) + var(--space-xs));
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
@media (min-width: 769px) {
.quick-chat-model-tag {
max-width: 14ch;
font-size: calc(var(--space-sm) + var(--space-xs) * 0.5);
line-height: 1.2;
white-space: normal;
overflow-wrap: anywhere;
text-overflow: clip;
}
}
/* Icon-only fallback when the model name is too long for the header. */
.quick-chat-model-tag--icon {
max-width: none;
padding: 0;
border: none;
border-radius: 0;
background: transparent;
justify-content: center;
}
.quick-chat-panel-header-actions {
--quick-chat-header-control-size: calc(var(--space-lg) + var(--space-sm) + var(--space-xs));
display: inline-flex;
align-items: center;
gap: var(--space-xs);
}
.quick-chat-panel-header-actions .btn-icon {
width: var(--quick-chat-header-control-size);
min-width: var(--quick-chat-header-control-size);
height: var(--quick-chat-header-control-size);
min-height: var(--quick-chat-header-control-size);
display: inline-flex;
align-items: center;
justify-content: center;
border: 1px solid var(--border);
border-radius: var(--radius-md);
background: var(--card);
color: var(--text);
}
.quick-chat-header-mode-toggle {
display: inline-flex;
align-items: center;
gap: calc(var(--space-xs) / 2);
}
.quick-chat-mode-btn {
min-width: var(--quick-chat-header-control-size, calc(var(--space-lg) + var(--space-sm) + var(--space-xs)));
height: var(--quick-chat-header-control-size, calc(var(--space-lg) + var(--space-sm) + var(--space-xs)));
min-height: var(--quick-chat-header-control-size, calc(var(--space-lg) + var(--space-sm) + var(--space-xs)));
padding: 0 var(--space-sm);
display: inline-flex;
align-items: center;
justify-content: center;
border: 1px solid var(--border);
border-radius: var(--radius-pill);
background: transparent;
color: var(--text-muted);
font-size: 12px;
font-weight: 600;
line-height: 1;
cursor: pointer;
transition: var(--transition-fast);
white-space: nowrap;
}
.quick-chat-panel-header-actions .btn-icon.quick-chat-new-chat-btn {
background: var(--cta-bg);
border-color: var(--cta-border);
color: var(--cta-text);
}
.quick-chat-panel-header-actions .btn-icon.quick-chat-new-chat-btn:hover {
background: var(--cta-bg-hover);
border-color: var(--cta-border-hover);
color: var(--cta-text);
}
.quick-chat-panel-header-actions .btn-icon.quick-chat-new-chat-btn:disabled,
.quick-chat-panel-header-actions .btn-icon.quick-chat-new-chat-btn:disabled:hover {
background: var(--cta-bg);
border-color: var(--cta-border);
color: var(--cta-text);
opacity: 0.6;
cursor: not-allowed;
}
.quick-chat-mode-btn:hover {
background: color-mix(in srgb, var(--todo) 10%, transparent);
color: var(--text);
border-color: color-mix(in srgb, var(--todo) 40%, var(--border));
}
.quick-chat-mode-btn--active {
background: color-mix(in srgb, var(--todo) 18%, transparent);
color: var(--text);
border-color: color-mix(in srgb, var(--todo) 50%, var(--border));
font-weight: 500;
}
.quick-chat-mode-btn:focus-visible {
outline: none;
box-shadow: var(--focus-ring-strong);
}
.quick-chat-panel-agent-select {
padding: calc(var(--space-sm) + (var(--space-xs) / 2)) var(--space-md);
border-bottom: 1px solid var(--border);
}
.quick-chat-new-session-chooser {
display: flex;
flex-direction: column;
gap: var(--space-sm);
margin: var(--space-sm) var(--space-md) 0;
padding: var(--space-sm);
border: 1px solid color-mix(in srgb, var(--todo) 25%, var(--border));
border-radius: var(--radius-md);
background: color-mix(in srgb, var(--surface) 80%, var(--card));
}
.quick-chat-inline-mode-toggle {
--quick-chat-header-control-size: calc(var(--space-lg) + var(--space-sm) + var(--space-xs));
display: inline-flex;
align-items: center;
gap: var(--space-xs);
}
.quick-chat-new-session-actions {
display: flex;
justify-content: flex-end;
align-items: center;
gap: var(--space-sm);
}
.quick-chat-panel-agent-select select {
width: 100%;
background: var(--bg);
color: var(--text);
border: 1px solid var(--border);
border-radius: var(--radius-sm);
padding: calc(var(--space-sm) - (var(--space-xs) / 4)) calc(var(--space-md) - (var(--space-xs) / 4));
}
.quick-chat-panel-messages {
flex: 1;
min-height: 0;
display: flex;
flex-direction: column;
gap: var(--space-sm);
overflow-y: auto;
padding: calc(var(--space-sm) + (var(--space-xs) / 2)) var(--space-md);
background: color-mix(in srgb, var(--bg) 35%, transparent);
}
.quick-chat-panel-empty {
margin: auto;
text-align: center;
color: var(--text-muted);
font-size: calc(var(--space-sm) + var(--space-xs) * 1.25);
}
.quick-chat-panel-message {
max-width: 86%;
padding: var(--space-sm) calc(var(--space-sm) + (var(--space-xs) / 2));
border-radius: var(--radius-md);
border: 1px solid var(--border);
color: var(--text);
font-size: calc(var(--space-sm) + var(--space-xs) * 1.25);
line-height: 1.45;
word-break: break-word;
}
.quick-chat-jump-to-latest {
position: absolute;
left: 50%;
bottom: calc(var(--space-xl) * 3);
transform: translateX(-50%);
z-index: 2;
}
.quick-chat-panel-message p {
margin: 0;
white-space: pre-wrap;
}
.quick-chat-message-content--plain {
white-space: pre-wrap;
}
.quick-chat-message-content--markdown {
white-space: normal;
overflow-wrap: anywhere;
}
.quick-chat-message-content--markdown > :first-child {
margin-top: 0;
}
.quick-chat-message-content--markdown > :last-child {
margin-bottom: 0;
}
.quick-chat-message-content--markdown p,
.quick-chat-message-content--markdown ul,
.quick-chat-message-content--markdown ol,
.quick-chat-message-content--markdown blockquote,
.quick-chat-message-content--markdown pre,
.quick-chat-message-content--markdown table {
margin: 0 0 var(--space-sm);
}
.quick-chat-message-content--markdown ul,
.quick-chat-message-content--markdown ol {
padding-left: var(--space-lg);
}
.quick-chat-message-content--markdown code {
font-family: var(--font-mono);
font-size: 0.75rem;
}
.quick-chat-message-content--markdown :not(pre) > code {
padding: 0 var(--space-xs);
border-radius: var(--radius-sm);
background: color-mix(in srgb, var(--surface) 55%, transparent);
}
.quick-chat-markdown-pre {
margin: 0 0 var(--space-sm);
padding: var(--space-sm);
border-radius: var(--radius-sm);
background: color-mix(in srgb, var(--surface) 65%, transparent);
overflow-x: auto;
white-space: pre;
max-width: 100%;
}
.quick-chat-markdown-table {
display: block;
width: 100%;
max-width: 100%;
overflow-x: auto;
border-collapse: collapse;
}
.quick-chat-markdown-table th,
.quick-chat-markdown-table td {
border: 1px solid color-mix(in srgb, var(--border) 85%, transparent);
padding: var(--space-xs) var(--space-sm);
}
.quick-chat-panel-message--sent {
align-self: flex-end;
background: color-mix(in srgb, var(--todo) 20%, transparent);
border-color: color-mix(in srgb, var(--todo) 45%, var(--border));
}
.quick-chat-panel-message--received {
position: relative;
align-self: flex-start;
background: var(--card);
}
.quick-chat-message-render-toggle {
position: absolute;
top: var(--space-xs);
right: var(--space-xs);
width: calc(var(--space-md) + var(--space-sm));
height: calc(var(--space-md) + var(--space-sm));
padding: 0;
display: flex;
align-items: center;
justify-content: center;
opacity: 0;
transition: opacity var(--transition-fast);
color: var(--text-muted);
background: transparent;
border: none;
border-radius: var(--radius-sm);
cursor: pointer;
outline: none;
}
.quick-chat-panel-message--received:hover .quick-chat-message-render-toggle,
.quick-chat-message-render-toggle:focus-visible {
opacity: 1;
}
.quick-chat-message-render-toggle--plain {
opacity: 1;
color: var(--accent);
}
.quick-chat-message-render-toggle:hover {
background: var(--surface-hover, color-mix(in srgb, var(--surface) 55%, transparent));
color: var(--text);
}
.quick-chat-message-render-toggle:focus-visible {
outline: none;
box-shadow: var(--focus-ring-strong);
}
.quick-chat-panel-input {
display: flex;
align-items: center;
gap: var(--space-sm);
padding: calc(var(--space-sm) + var(--space-xs)) var(--space-md);
border-top: 1px solid var(--border);
background: color-mix(in srgb, var(--surface) 85%, var(--bg));
}
.quick-chat-input-wrapper {
position: relative;
display: flex;
flex: 1;
flex-direction: column;
min-width: 0;
border: 1px solid var(--border);
border-radius: var(--radius-sm);
background: var(--bg);
padding: var(--space-xs);
}
.quick-chat-input-row {
display: flex;
align-items: center;
gap: var(--space-sm);
min-width: 0;
}
.quick-chat-panel .chat-skill-menu {
position: absolute;
left: var(--space-lg);
bottom: calc(100% + var(--space-xs));
min-width: calc((var(--space-xl) * 10) + var(--space-2xl) + (var(--space-xs) * 2));
max-width: calc(100% - (var(--space-lg) * 2));
max-height: calc(var(--space-xl) * 10);
overflow-y: auto;
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius-md);
box-shadow: var(--shadow-lg);
z-index: 50;
}
.quick-chat-panel .chat-skill-menu-item {
width: 100%;
border: none;
background: transparent;
color: inherit;
text-align: left;
padding: var(--space-sm) var(--space-md);
cursor: pointer;
display: flex;
flex-direction: column;
gap: var(--space-xs);
transition: background var(--transition-fast);
}
.quick-chat-panel .chat-skill-menu-item:hover,
.quick-chat-panel .chat-skill-menu-item--highlighted {
background: var(--card-hover);
}
.quick-chat-panel .chat-skill-menu-item:focus-visible {
outline: none;
box-shadow: var(--focus-ring-strong);
background: var(--card-hover);
}
.quick-chat-panel .chat-skill-menu-item-name {
font-size: 0.8125rem;
color: var(--text);
font-family: var(--font-mono);
}
.quick-chat-panel .chat-skill-menu-item-description {
font-size: 0.75rem;
color: var(--text-muted);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: calc((var(--space-xl) * 10) + var(--space-lg) + var(--space-xs));
}
.quick-chat-panel .chat-skill-menu-empty {
padding: var(--space-sm) var(--space-md);
color: var(--text-muted);
font-size: 0.8125rem;
}
.quick-chat-input-wrapper--dragover {
border-color: var(--todo);
background: color-mix(in srgb, var(--todo) 5%, var(--bg));
}
.quick-chat-attachment-input {
display: none;
}
.quick-chat-panel-input input {
flex: 1;
min-width: 0;
border-radius: var(--radius-sm);
border: none;
background: transparent;
color: var(--text);
padding: var(--space-sm);
}
/* Keep the attachment trigger compact inside the input wrapper so the composer
stays a single inline row with the text field. */
.quick-chat-attach-btn {
min-width: calc(var(--space-lg) + var(--space-md));
min-height: calc(var(--space-lg) + var(--space-md));
width: calc(var(--space-lg) + var(--space-md));
height: calc(var(--space-lg) + var(--space-md));
flex-shrink: 0;
}
/* The send/stop action stays in the same inline composer row as attach + input. */
.quick-chat-send-btn {
min-width: calc(var(--space-lg) + var(--space-xl));
min-height: calc(var(--space-lg) + var(--space-xl));
width: calc(var(--space-lg) + var(--space-xl));
height: calc(var(--space-lg) + var(--space-xl));
border-radius: var(--radius-sm);
border: 1px solid color-mix(in srgb, var(--todo) 45%, var(--border));
background: var(--todo);
color: var(--cta-text);
display: inline-flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
.quick-chat-send-btn:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.quick-chat-attachment-previews {
display: flex;
gap: var(--space-xs);
padding: var(--space-sm) var(--space-md);
border-top: 1px solid var(--border);
overflow-x: auto;
background: color-mix(in srgb, var(--surface) 85%, var(--bg));
}
.quick-chat-attachment-preview {
width: calc(var(--space-lg) * 3);
height: calc(var(--space-lg) * 3);
border-radius: var(--radius-sm);
border: 1px solid var(--border);
position: relative;
flex-shrink: 0;
display: inline-flex;
align-items: center;
justify-content: center;
background: color-mix(in srgb, var(--surface) 65%, var(--bg));
overflow: hidden;
}
.quick-chat-attachment-preview img {
width: 100%;
height: 100%;
object-fit: cover;
border-radius: inherit;
}
.quick-chat-attachment-preview-name {
width: 100%;
padding: var(--space-xs);
font-size: calc(var(--space-sm) + var(--space-xs));
text-align: center;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
color: var(--text-muted);
}
.quick-chat-attachment-remove {
position: absolute;
top: 0;
right: 0;
transform: translate(var(--space-xs), calc(var(--space-xs) * -1));
background: color-mix(in srgb, var(--color-error) 80%, transparent);
color: var(--cta-text);
border: none;
border-radius: 50%;
width: calc(var(--space-md) + var(--space-md));
height: calc(var(--space-md) + var(--space-md));
font-size: var(--space-sm);
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
line-height: 1;
}
.quick-chat-attachment-remove:focus-visible {
outline: none;
box-shadow: var(--focus-ring-strong);
}
/* === Quick Chat Mobile (FN: full-screen) =================================== */
@media (max-width: 768px) {
.quick-chat-panel {
/* Full-screen sheet that ignores drag position on mobile. We pin
every edge with !important so any stray inline value cannot pull
the panel off-screen. iOS's would-be visual-viewport shift on
input focus is suppressed at the source by the input's
onTouchStart handler in QuickChatFAB.tsx, so we don't need to
compensate with translateY here. */
position: fixed !important;
inset: 0 !important;
left: 0 !important;
right: 0 !important;
top: 0 !important;
bottom: 0 !important;
width: 100vw !important;
height: 100vh !important;
height: 100dvh !important;
height: var(--vv-height, 100dvh) !important;
max-width: 100vw;
max-height: 100vh;
max-height: 100dvh;
max-height: var(--vv-height, 100dvh);
/* Follow iOS's visual viewport offset. Without this, on the second
focus after a keyboard dismiss, vv.offsetTop becomes non-zero and
the position:fixed panel (anchored to layout top:0) renders above
the visible area — only the bottom of the panel (the input bar)
pokes into view near the top of the screen. */
transform: translateY(var(--vv-offset-top, 0px));
border-radius: 0;
border: none;
z-index: 1100;
}
.quick-chat-resize-handle {
display: none;
}
.quick-chat-panel-messages {
/* Let messages take all remaining space between header and input */
flex: 1 1 auto;
min-height: 0;
}
.quick-chat-panel-input {
/* Reserve safe-area space so the input clears the iOS home bar */
padding-bottom: calc(var(--space-sm) + var(--space-xs) + env(safe-area-inset-bottom, 0px));
}
.quick-chat-attachment-previews {
padding: var(--space-sm) max(var(--space-md), env(safe-area-inset-left, 0px));
}
.quick-chat-attachment-preview {
width: calc(var(--space-lg) * 2 + var(--space-sm));
height: calc(var(--space-lg) * 2 + var(--space-sm));
}
.quick-chat-send-btn {
min-width: calc(var(--space-lg) + var(--space-xl));
min-height: calc(var(--space-lg) + var(--space-xl));
}
.quick-chat-attachment-remove {
min-width: calc(var(--space-lg) + var(--space-xl));
min-height: calc(var(--space-lg) + var(--space-xl));
width: calc(var(--space-lg) + var(--space-xl));
height: calc(var(--space-lg) + var(--space-xl));
top: 0;
right: 0;
transform: translate(var(--space-xs), calc(var(--space-xs) * -1));
font-size: var(--space-md);
}
.quick-chat-panel-header {
flex-wrap: nowrap;
row-gap: 0;
/* iOS PWA: status bar (black-translucent) overlays the panel from top: 0,
clipping the close button. Reserve top inset on mobile. */
padding-top: calc(var(--space-sm) + (var(--space-xs) / 2) + env(safe-area-inset-top, 0px));
}
.quick-chat-panel-title-wrap {
flex: 1 1 auto;
min-width: 0;
}
.quick-chat-panel-header h3 {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.quick-chat-model-tag {
max-width: 12ch;
flex-shrink: 1;
}
.quick-chat-panel-header-actions {
--quick-chat-header-control-size: calc(var(--space-xl) + var(--space-md));
width: auto;
flex-shrink: 0;
justify-content: flex-end;
min-width: 0;
}
.quick-chat-inline-mode-toggle {
--quick-chat-header-control-size: calc(var(--space-xl) + var(--space-md));
width: 100%;
}
.quick-chat-mode-btn {
flex: 1 1 0;
}
.quick-chat-new-session-actions {
justify-content: stretch;
}
.quick-chat-new-session-actions .btn {
flex: 1 1 0;
}
.quick-chat-panel .chat-tool-calls-group-summary {
flex-wrap: nowrap;
flex-direction: row;
align-items: center;
}
.quick-chat-panel .chat-tool-calls-names,
.quick-chat-panel .chat-tool-call-name,
.quick-chat-panel .chat-tool-call-status-text,
.quick-chat-panel .chat-tool-calls-group-status {
white-space: nowrap;
}
.quick-chat-panel .chat-tool-calls-group-status {
justify-content: flex-end;
margin-left: auto;
}
.quick-chat-panel-message {
max-width: 90%;
}
.quick-chat-jump-to-latest {
bottom: calc(var(--space-xl) * 4 + env(safe-area-inset-bottom, 0px));
}
}
.quick-chat-panel .chat-message-thinking {
margin-top: var(--space-xs);
}
.quick-chat-panel .chat-message-thinking summary {
font-size: var(--space-md);
color: var(--text-muted);
cursor: pointer;
}
.quick-chat-panel .chat-message-thinking-content {
font-size: var(--space-md);
color: var(--text-muted);
padding: var(--space-sm);
background: var(--bg);
border-radius: var(--radius-sm);
margin-top: var(--space-xs);
white-space: pre-wrap;
font-family: var(--font-mono, monospace);
overflow-x: auto;
}
/* === Chat Tool Calls === */
.quick-chat-panel .chat-tool-calls {
margin-top: var(--space-sm);
display: flex;
flex-direction: column;
gap: var(--space-xs);
}
.quick-chat-panel .chat-tool-calls-header {
display: inline-flex;
align-items: center;
gap: var(--space-xs);
color: var(--text-muted);
font-size: var(--space-md);
}
.quick-chat-panel .chat-tool-calls-group {
border: var(--btn-border-width, 1px) solid color-mix(in srgb, var(--border) 85%, transparent);
border-radius: var(--radius-sm);
background: color-mix(in srgb, var(--surface) 35%, transparent);
}
.quick-chat-panel .chat-tool-calls-group-summary {
display: flex;
align-items: center;
gap: var(--space-sm);
list-style: none;
cursor: pointer;
padding: var(--space-xs) var(--space-sm);
color: var(--text-muted);
border-radius: var(--radius-sm);
font-size: var(--space-md);
min-width: 0;
white-space: nowrap;
}
.quick-chat-panel .chat-tool-calls-group-summary::marker {
content: "";
}
.quick-chat-panel .chat-tool-calls-group-summary::-webkit-details-marker {
display: none;
}
.quick-chat-panel .chat-tool-calls-group-summary:focus-visible {
outline: none;
box-shadow: var(--focus-ring-strong);
}
.quick-chat-panel .chat-tool-calls-count {
white-space: nowrap;
flex-shrink: 0;
}
.quick-chat-panel .chat-tool-calls-names {
color: var(--text-dim);
font-family: var(--font-mono, monospace);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
flex: 1 1 auto;
min-width: 0;
font-size: calc(var(--space-sm) + var(--space-xs) * 0.5);
}
.quick-chat-panel .chat-tool-calls-group-status {
margin-left: auto;
font-size: calc(var(--space-sm) + var(--space-xs) * 0.5);
color: var(--text-dim);
flex-shrink: 0;
white-space: nowrap;
}
.quick-chat-panel .chat-tool-calls-group > .chat-tool-call {
margin: 0 var(--space-sm) var(--space-xs) var(--space-sm);
}
.quick-chat-panel .chat-tool-calls-group > .chat-tool-call:last-child {
margin-bottom: var(--space-sm);
}
.quick-chat-panel .chat-tool-call {
border: var(--btn-border-width, 1px) solid color-mix(in srgb, var(--border) 85%, transparent);
border-radius: var(--radius-sm);
background: color-mix(in srgb, var(--surface) 35%, transparent);
}
.quick-chat-panel .chat-tool-call summary {
display: flex;
align-items: center;
gap: var(--space-xs);
list-style: none;
cursor: pointer;
padding: var(--space-xs) var(--space-sm);
color: var(--text-muted);
border-radius: var(--radius-sm);
font-size: var(--space-md);
min-width: 0;
white-space: nowrap;
}
.quick-chat-panel .chat-tool-call summary::marker {
content: "";
}
.quick-chat-panel .chat-tool-call summary::-webkit-details-marker {
display: none;
}
.quick-chat-panel .chat-tool-call summary:focus-visible {
outline: none;
box-shadow: var(--focus-ring-strong);
}
.quick-chat-panel .chat-tool-call-status-dot {
width: calc((var(--space-xs) + var(--space-sm)) / 2);
height: calc((var(--space-xs) + var(--space-sm)) / 2);
border-radius: 50%;
background: var(--color-success);
flex-shrink: 0;
}
.quick-chat-panel .chat-tool-call-name {
font-family: var(--font-mono, monospace);
flex: 0 1 auto;
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.quick-chat-panel .chat-tool-call-preview {
color: var(--text-muted);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
flex: 1;
min-width: 0;
font-size: calc(var(--space-sm) + var(--space-xs) * 0.5);
}
.quick-chat-panel .chat-tool-call-status-text {
margin-left: auto;
font-size: calc(var(--space-sm) + var(--space-xs) * 0.5);
text-transform: lowercase;
white-space: nowrap;
flex-shrink: 0;
}
.quick-chat-panel .chat-tool-call-content {
margin: var(--space-xs) var(--space-sm) var(--space-sm);
padding: var(--space-sm);
border-radius: var(--radius-sm);
background: var(--bg);
font-family: var(--font-mono, monospace);
display: flex;
flex-direction: column;
gap: var(--space-xs);
}
.quick-chat-panel .chat-tool-call-row {
display: grid;
grid-template-columns: auto 1fr;
gap: var(--space-xs);
align-items: start;
}
.quick-chat-panel .chat-tool-call-label {
color: var(--text-muted);
text-transform: uppercase;
letter-spacing: 0.04em;
font-size: calc(var(--space-sm) + var(--space-xs) * 0.5);
}
.quick-chat-panel .chat-tool-call-value {
color: var(--text);
word-break: break-word;
white-space: pre-wrap;
}
.quick-chat-panel .chat-tool-call--running .chat-tool-call-status-dot {
background: var(--color-info);
animation: tool-call-pulse var(--transition-slow) infinite;
}
.quick-chat-panel .chat-tool-call--error summary {
color: var(--color-error);
}
.quick-chat-panel .chat-tool-call--error .chat-tool-call-status-dot {
background: var(--color-error);
}
.quick-chat-panel .chat-tool-call-row--error {
background: color-mix(in srgb, var(--color-error) 10%, transparent);
border-radius: var(--radius-sm);
padding: var(--space-xs);
}
.quick-chat-panel .chat-tool-calls--compact .chat-tool-calls-header,
.quick-chat-panel .chat-tool-calls--compact .chat-tool-calls-group-summary,
.quick-chat-panel .chat-tool-calls--compact .chat-tool-calls-names,
.quick-chat-panel .chat-tool-calls--compact .chat-tool-calls-group-status,
.quick-chat-panel .chat-tool-calls--compact .chat-tool-call summary,
.quick-chat-panel .chat-tool-calls--compact .chat-tool-call-content,
.quick-chat-panel .chat-tool-calls--compact .chat-tool-call-preview,
.quick-chat-panel .chat-tool-calls--compact .chat-tool-call-value,
.quick-chat-panel .chat-tool-calls-group--compact .chat-tool-calls-group-summary,
.quick-chat-panel .chat-tool-calls-group--compact .chat-tool-calls-names {
font-size: calc(var(--space-sm) + var(--space-xs) * 0.5);
}
@keyframes tool-call-pulse {
0%,
100% {
opacity: 1;
}
50% {
opacity: 0.4;
}
}
/* Streaming indicator */
.quick-chat-panel .chat-message--streaming {
align-self: flex-start;
background: var(--bg-elevated, var(--bg-secondary));
color: var(--text);
border-bottom-left-radius: var(--radius-sm);
opacity: 0.9;
}
.quick-chat-panel .chat-pending-message {
display: flex;
align-items: center;
gap: var(--space-sm);
margin-top: var(--space-xs);
padding: var(--space-xs) var(--space-sm);
border-radius: var(--radius-sm);
background: color-mix(in srgb, var(--todo) 10%, transparent);
color: var(--text-muted);
font-size: var(--space-md);
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.quick-chat-panel .chat-pending-message span {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.quick-chat-panel .chat-pending-message-dismiss {
background: none;
border: none;
color: var(--text-dim);
cursor: pointer;
padding: var(--space-xs);
line-height: 1;
flex-shrink: 0;
font-size: var(--space-lg);
}
.quick-chat-panel .chat-pending-message-dismiss:hover {
color: var(--text-muted);
}
/* === Rescued: classes referenced in QuickChatFAB/ChatView TSX but never defined ====== */
.quick-chat-panel .chat-mention-chip {
display: inline-flex;
align-items: center;
gap: var(--space-xs);
padding: var(--space-xs) var(--space-sm);
margin: 0 var(--space-xs);
background: color-mix(in srgb, var(--todo) 14%, transparent);
color: var(--todo);
border: var(--btn-border-width, 1px) solid color-mix(in srgb, var(--todo) 30%, transparent);
border-radius: var(--radius-pill);
font-size: calc(var(--space-sm) + var(--space-xs) * 0.5);
font-weight: 500;
white-space: nowrap;
}
.quick-chat-panel-message--streaming {
position: relative;
opacity: 0.95;
}
.quick-chat-panel-message--streaming::after {
content: "▍";
display: inline-block;
margin-left: 2px;
color: var(--todo);
animation: quick-chat-cursor-blink 1s steps(1) infinite;
}
@keyframes quick-chat-cursor-blink {
50% { opacity: 0; }
}