loopable / web /src /customer-grid /gridChat.css
fsanyoto's picture
Deploy AIOS web (React glide grid + FastAPI slice)
f2db836 verified
Raw
History Blame
9.73 kB
/* customer-grid/gridChat.css β€” the docked chat panel (W37-T40, contract C8).
*
* β›” MODULE-LOCAL BY CONTRACT, not by preference. C8 hands `index.css` (12k+ lines) to lane A
* alone this wave, and every other lane adds styles in its own per-surface sheet imported by its
* own component. The precedent already exists next door in `scriptView.css` and `navExtras.css`.
* ⚠ Colours come from the design tokens (navy #1F4E78 + gold #C8A24B, DESIGN.md), never from fresh
* hexes: a surface that invents its own palette is the thing the constitution exists to prevent.
* Only the tokens this file actually uses are named.
* β›”β›” NO FALLBACK LITERAL INSIDE A `font:` SHORTHAND, and this sheet shipped ten of them before
* `web_ui` said so (lane A, mailbox A-47). A fallback there is a SECOND SOURCE OF TRUTH for a size
* that silently becomes THE size the day the token is renamed, and `index.css` always loads, so it
* can never actually fire. Sizes are therefore `var(--lp-fs-xs)` bare; colours keep their fallback
* because a missing colour is a legibility failure rather than a silent wrong number.
* ⚠ NO EMOJIS AND NO ALL-CAPS CHROME (DESIGN.md). */
.cg-chat {
display: flex;
flex-direction: column;
height: 100%;
min-height: 0;
/* ⚠ A FLOOR AND A CEILING, NOT A FIXED WIDTH. The host docks this beside a grid whose columns
are the reason the person is here; a panel that cannot give width back squeezes the thing it
is talking about. Below the floor the transcript stops being readable, so the floor is real. */
min-width: 280px;
max-width: 420px;
flex: 0 0 340px;
background: var(--lp-surface, #ffffff);
border-left: 1px solid var(--lp-border, #e4e7ec);
}
/* Below 1024px a docked panel and a grid cannot both be usable, so the panel takes the surface.
⚠ It does NOT hide itself: hiding would leave the host's toggle saying "open" with nothing on
screen, which is a worse failure than a full-width panel the person can close. */
@media (max-width: 1024px) {
.cg-chat { flex: 1 1 auto; max-width: none; border-left: 0; }
}
.cg-chat-head {
display: flex;
align-items: center;
gap: 8px;
padding: 10px 12px;
border-bottom: 1px solid var(--lp-border, #e4e7ec);
background: var(--lp-surface, #ffffff);
}
.cg-chat-title {
font: 600 var(--lp-fs-xs)/1.4 Inter, system-ui, sans-serif;
color: var(--lp-text, #1d2939);
/* The database name can be long and the header is narrow. Truncating beats wrapping into a
two-line header that shifts the whole panel down. */
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
flex: 1 1 auto;
min-width: 0;
}
.cg-chat-close {
display: inline-flex;
align-items: center;
justify-content: center;
width: 24px;
height: 24px;
border: 0;
border-radius: 6px;
background: transparent;
color: var(--lp-text-muted, #667085);
cursor: pointer;
}
.cg-chat-close:hover { background: var(--lp-surface-sunken, #f2f4f7); color: var(--lp-text, #1d2939); }
/* ── the transcript ─────────────────────────────────────────────────────── */
.cg-chat-log {
display: flex;
flex-direction: column;
gap: 10px;
flex: 1 1 auto;
min-height: 0;
overflow-y: auto;
padding: 14px 12px;
}
.cg-chat-turn { display: flex; flex-direction: column; gap: 6px; }
.cg-chat-msg {
max-width: 92%;
padding: 8px 10px;
border-radius: 10px;
font: 400 var(--lp-fs-xs)/1.55 Inter, system-ui, sans-serif;
white-space: pre-wrap;
/* ⚠ A pasted column name or an id has no spaces to break on and would otherwise push the panel
wider than its own max-width. */
overflow-wrap: anywhere;
}
.cg-chat-msg.is-you {
align-self: flex-end;
background: var(--lp-navy, #1f4e78);
color: #ffffff;
}
.cg-chat-msg.is-assistant {
align-self: flex-start;
background: var(--lp-surface-sunken, #f2f4f7);
color: var(--lp-text, #1d2939);
}
/* ⚠ The panel talking about ITSELF (a write landed, a proposal was declined) is neither side of
the conversation, so it is centred and quiet rather than dressed as an answer. */
.cg-chat-msg.is-note {
align-self: center;
max-width: 100%;
background: transparent;
color: var(--lp-text-muted, #667085);
font-size: var(--lp-fs-2xs, 11px);
text-align: center;
padding: 2px 4px;
}
/* β›” An error is a KIND OF TURN, in the transcript where it can be re-read while the person
rephrases. Not a toast that has already faded by then. */
.cg-chat-msg.is-error {
align-self: flex-start;
background: #fef3f2;
color: #b42318;
border: 1px solid #fecdca;
}
.cg-chat-pending {
display: flex;
align-items: center;
gap: 8px;
padding: 2px 2px 4px;
font: 400 var(--lp-fs-2xs)/1.4 Inter, system-ui, sans-serif;
color: var(--lp-text-muted, #667085);
}
/* ── the write confirm (R10) ────────────────────────────────────────────── */
.cg-chat-edits {
border: 1px solid var(--lp-border, #e4e7ec);
border-radius: 10px;
background: var(--lp-surface, #ffffff);
padding: 10px;
}
.cg-chat-edits-head {
margin: 0 0 8px;
font: 600 var(--lp-fs-2xs)/1.4 Inter, system-ui, sans-serif;
color: var(--lp-text, #1d2939);
}
.cg-chat-edits-table {
width: 100%;
border-collapse: collapse;
font: 400 var(--lp-fs-3xs)/1.45 Inter, system-ui, sans-serif;
/* A proposal can name more cells than fit; it scrolls rather than being clipped, because a
confirm the person cannot fully read is not a confirm. */
display: block;
max-height: 220px;
overflow: auto;
}
.cg-chat-edits-table th {
text-align: left;
font-weight: 600;
color: var(--lp-text-muted, #667085);
padding: 0 8px 4px 0;
position: sticky;
top: 0;
background: var(--lp-surface, #ffffff);
}
.cg-chat-edits-table td {
padding: 3px 8px 3px 0;
color: var(--lp-text, #1d2939);
border-top: 1px solid var(--lp-border, #e4e7ec);
vertical-align: top;
overflow-wrap: anywhere;
}
/* ⚠ The two values are told apart by WEIGHT and colour, never by colour alone: a red/green pair
is unreadable to a substantial minority of people, and this is a confirm before a write. */
.cg-chat-before { color: var(--lp-text-muted, #667085); text-decoration: line-through; }
.cg-chat-after { color: var(--lp-navy, #1f4e78); font-weight: 600; }
/* ⚠ Centred under the note it belongs to, and quiet: an undo control that shouted would read as
a warning that something went wrong, when what happened is exactly what the person confirmed. */
.cg-chat-undo { display: flex; justify-content: center; margin-top: 2px; }
.cg-chat-edits-act {
display: flex;
justify-content: flex-end;
gap: 8px;
margin-top: 10px;
}
.cg-chat-ghost,
.cg-chat-go {
border-radius: 7px;
padding: 5px 12px;
font: 500 var(--lp-fs-2xs)/1.2 Inter, system-ui, sans-serif;
cursor: pointer;
}
.cg-chat-ghost {
border: 1px solid var(--lp-border, #e4e7ec);
background: var(--lp-surface, #ffffff);
color: var(--lp-text, #1d2939);
}
.cg-chat-go {
border: 1px solid var(--lp-navy, #1f4e78);
background: var(--lp-navy, #1f4e78);
color: #ffffff;
}
.cg-chat-ghost:disabled,
.cg-chat-go:disabled { opacity: 0.55; cursor: default; }
/* ── the opening and the composer ───────────────────────────────────────── */
.cg-chat-opening {
display: flex;
flex-direction: column;
justify-content: center;
flex: 1 1 auto;
min-height: 0;
gap: 10px;
padding: 16px 12px;
text-align: center;
}
.cg-chat-opening-h {
margin: 0;
font: 600 var(--lp-fs-lg)/1.3 Inter, system-ui, sans-serif;
color: var(--lp-text, #1d2939);
}
.cg-chat-opening-p {
margin: 0 0 6px;
font: 400 var(--lp-fs-2xs)/1.55 Inter, system-ui, sans-serif;
color: var(--lp-text-muted, #667085);
}
.cg-chat-foot { padding: 10px 12px 12px; border-top: 1px solid var(--lp-border, #e4e7ec); }
.cg-chat-composer {
border: 1px solid var(--lp-border, #e4e7ec);
border-radius: 12px;
background: var(--lp-surface, #ffffff);
padding: 8px;
text-align: left;
}
.cg-chat-composer:focus-within { border-color: var(--lp-navy, #1f4e78); }
.cg-chat-input {
width: 100%;
border: 0;
outline: 0;
resize: none;
background: transparent;
color: var(--lp-text, #1d2939);
font: 400 var(--lp-fs-xs)/1.5 Inter, system-ui, sans-serif;
}
.cg-chat-input::placeholder { color: var(--lp-text-muted, #667085); }
.cg-chat-input:disabled { color: var(--lp-text-muted, #667085); }
/* ⚠ The foot row sits INSIDE the composer's border, which is the shape `cg-agent-composer-foot`
already established. A second card outline under the input would read as two controls. */
.cg-chat-composer-foot {
display: flex;
align-items: center;
gap: 8px;
margin-top: 6px;
}
.cg-chat-scope {
font: 400 var(--lp-fs-3xs)/1.3 Inter, system-ui, sans-serif;
color: var(--lp-text-muted, #667085);
}
.cg-chat-spacer { flex: 1 1 auto; }
.cg-chat-send {
display: inline-flex;
align-items: center;
justify-content: center;
width: 26px;
height: 26px;
border: 0;
border-radius: 50%;
background: var(--lp-navy, #1f4e78);
color: #ffffff;
cursor: pointer;
}
.cg-chat-send:disabled {
background: var(--lp-surface-sunken, #f2f4f7);
color: var(--lp-text-muted, #667085);
cursor: default;
}