loopable / web /src /query /query.css
fsanyoto's picture
Deploy AIOS web (React glide grid + FastAPI slice)
cf17b22 verified
Raw
History Blame
11 kB
/* ---------------------------------------------------------------------------
query/query.css β€” the Query module's own stylesheet.
The Query module IS the database module β€” `shell-db-frame` + `CustomerGrid` β€”
so the frame, the grid and every view kind are styled by rules that already
exist. What is left here is what this surface adds: the VIEW RAIL (owner item
3: the AI's views, grouped by the database they read), a one-line provenance
disclosure, and the empty state.
⚠ THE UNIVERSAL DATABASE HEADER IS GONE FROM THIS FRAME (owner item 7,
W36-T67), so the rail's group heading is now the only place the source
database is named. That is not a gap: it was always the richer of the two,
carrying the icon as well, and the header was the copy.
The chat rules live in `assistant/assistant.css` with the markup they style.
EVERY FONT SIZE IS A `--lp-fs-*` TOKEN AND EVERY COLOUR A `--lp-*` TOKEN.
Wave-21 R5 is gated app-wide over every CSS file under src, and a literal
here reds `web_ui` for the whole tree. No emojis, no ALL-CAPS chrome
(DESIGN.md R6).
AND DO NOT WRITE A GLOB IN THIS COMMENT. A star-star followed by a slash
spells the CSS COMMENT TERMINATOR β€” the comment would end in the middle of
its own explanation and `lightningcss` would die far from the cause. Found
by `web_build` in wave 32's QA; it blocked the deploy outright.
--------------------------------------------------------------------------- */
/* ── the workspace: rail + surface, in the database module's own geometry ─── */
.qy-workspace {
display: flex;
width: 100%;
height: 100%;
min-width: 0;
overflow: hidden;
background: var(--lp-surface);
}
/* The same width and hairline `CustomerGrid`'s own views rail uses
(`.cg-views`, index.css) β€” this rail stands in that slot, so it has to
measure the same or Query stops looking like a database. */
.qy-rail {
flex: 0 0 var(--lp-rail-w);
width: var(--lp-rail-w);
min-width: var(--lp-rail-w);
height: 100%;
box-sizing: border-box;
display: flex;
flex-direction: column;
padding: 10px 8px;
border-right: 1px solid var(--lp-line);
background: var(--lp-surface);
overflow: hidden;
}
.qy-rail-head {
margin: 0 0 6px;
padding: 0 6px;
color: var(--lp-muted);
font-size: var(--lp-fs-xs);
font-weight: 600;
}
.qy-rail-scroll {
flex: 1 1 auto;
min-height: 0;
overflow-y: auto;
}
.qy-rail-group { margin-bottom: 10px; }
/* ── R20: the per-view menu, the same vocabulary a database view offers ───── */
.qy-rail-more {
flex: 0 0 auto;
width: 24px;
height: 24px;
margin-right: 4px;
display: inline-flex;
align-items: center;
justify-content: center;
border: 0;
border-radius: 6px;
background: transparent;
color: var(--lp-muted);
opacity: 0;
cursor: pointer;
}
.qy-rail-more svg { fill: currentColor; stroke: none; }
.qy-rail-row:hover .qy-rail-more,
.qy-rail-row.is-active .qy-rail-more,
.qy-rail-more:focus-visible,
.qy-rail-more[aria-expanded="true"] { opacity: 1; }
/* Sits above the rows, under the menu, so a click anywhere else closes it without every row
needing its own outside-click listener. */
.qy-rail-scrim {
position: fixed;
inset: 0;
z-index: 20;
border: 0;
padding: 0;
background: transparent;
cursor: default;
}
/* FIXED, not absolute: its natural parent `.qy-rail-scroll` is `overflow-y: auto`, which clips
both axes, so a menu opened on a row near the bottom of the list would render cut off or
invisible. `top`/`right` are supplied inline from the button's own rect. */
.qy-rail-menu {
position: fixed;
z-index: 21;
min-width: 168px;
margin-top: 2px;
padding: 4px;
display: flex;
flex-direction: column;
border: 1px solid var(--lp-line);
border-radius: var(--lp-r-md);
background: var(--lp-surface);
box-shadow: 0 6px 18px rgba(20, 24, 40, 0.12);
}
.qy-rail-item {
display: block;
padding: 6px 10px;
border: 0;
border-radius: 6px;
background: transparent;
color: var(--lp-ink);
font: inherit;
font-size: var(--lp-fs-2xs);
text-align: left;
text-decoration: none;
cursor: pointer;
}
.qy-rail-item:hover { background: var(--lp-surface-2); }
.qy-rail-item.is-danger { color: var(--lp-red-deep); }
.qy-rail-edit { flex: 1 1 auto; min-width: 0; padding: 2px 4px; }
.qy-rail-input {
width: 100%;
box-sizing: border-box;
padding: 5px 8px;
border: 1px solid var(--lp-blue-solid);
border-radius: 6px;
background: var(--lp-surface);
color: var(--lp-ink);
font: inherit;
font-size: var(--lp-fs-2xs);
}
.qy-rail-note {
flex: 1 0 100%;
margin: 0 0 4px;
padding: 0 10px;
color: var(--lp-muted);
font-size: var(--lp-fs-2xs);
line-height: var(--lp-lh);
}
.qy-rail-problem {
margin: 0 6px 6px;
color: var(--lp-red-deep);
font-size: var(--lp-fs-2xs);
}
/* A confirmation, not a refusal. Same slot, different voice. */
.qy-rail-notice {
margin: 0 6px 6px;
color: var(--lp-muted);
font-size: var(--lp-fs-2xs);
line-height: var(--lp-lh);
}
.qy-rail-db {
display: flex;
align-items: center;
gap: 6px;
margin: 0 0 2px;
padding: 4px 6px;
color: var(--lp-muted);
font-size: var(--lp-fs-xs);
font-weight: 600;
}
.qy-rail-db-mark {
flex: 0 0 auto;
display: inline-flex;
width: 14px;
height: 14px;
color: var(--lp-muted);
}
.qy-rail-db-mark svg {
width: 14px;
height: 14px;
fill: none;
stroke: currentColor;
stroke-width: 1.4;
stroke-linecap: round;
stroke-linejoin: round;
}
.qy-rail-db-name {
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.qy-rail-row {
position: relative;
display: flex;
/* R20's description sits on its own line under the name, so the row wraps. `position: relative`
was already here and is what the menu anchors to. */
flex-wrap: wrap;
align-items: center;
min-width: 0;
border-radius: var(--lp-r-md);
}
.qy-rail-row:hover { background: var(--lp-surface-2); }
.qy-rail-row.is-active { background: var(--lp-blue-tint); }
.qy-rail-view {
flex: 1 1 auto;
min-width: 0;
min-height: 32px;
display: flex;
flex-direction: column;
justify-content: center;
gap: 1px;
padding: 5px 8px;
border: 0;
background: transparent;
font: inherit;
text-align: left;
color: var(--lp-ink);
cursor: pointer;
}
.qy-rail-name {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-size: var(--lp-fs-xs);
font-weight: 500;
}
.qy-rail-row.is-active .qy-rail-name { font-weight: 600; }
.qy-rail-kind {
display: flex;
align-items: center;
gap: 6px;
min-width: 0;
color: var(--lp-muted);
font-size: var(--lp-fs-2xs);
}
/* ⭐ W35-T25 (R3) β€” the Edited mark. Quiet on purpose: it reports a state the reader created
themselves, so it belongs beside the kind rather than competing with the view's name. */
.qy-rail-edited {
flex: 0 0 auto;
padding: 0 5px;
border-radius: var(--lp-r-sm);
background: var(--lp-surface-2);
color: var(--lp-muted);
font-size: var(--lp-fs-2xs);
font-weight: 600;
line-height: 15px;
}
.qy-rail-row.is-active .qy-rail-edited { background: var(--lp-surface); }
/* ── ⭐⭐ W35-T47 (R4, C2) β€” the SHARED star button, re-placed for a rail row ─────────────────
*
* β›” GEOMETRY ONLY. `StarButton` is B's component and `starred.css` owns everything about how it
* looks; overriding its colour or its glyph here would be a second opinion about one mark. What a
* rail row genuinely needs different is placement: the shared rule is `position: absolute` on a
* TILE wrapper, and this row is a flex list whose right end already holds the actions button, so
* an absolutely positioned star would sit on top of it.
*
* ⚠ AND THE REVEAL RULE HAS TO BE RESTATED, not inherited. The shared sheet reveals the star with
* `.st-tilewrap:hover`, a wrapper that does not exist here β€” so without the row's own hover rule
* the button would be `opacity: 0` forever except when starred or focused, i.e. a control you can
* only find by tabbing to it. `.is-on` and `:focus-visible` keep working from the shared sheet.
*/
.qy-rail-row .st-star {
position: static;
transform: none;
flex: 0 0 auto;
width: 22px;
height: 22px;
margin-right: 2px;
}
.qy-rail-row:hover .st-star { opacity: 1; }
/* Hover-revealed, like the grid rail's own row menu β€” visible on focus so it is
reachable from the keyboard rather than only from a pointer. */
.qy-rail-del {
flex: 0 0 auto;
width: 24px;
height: 24px;
margin-right: 4px;
display: inline-flex;
align-items: center;
justify-content: center;
border: 0;
border-radius: 6px;
background: transparent;
color: var(--lp-muted);
opacity: 0;
cursor: pointer;
}
.qy-rail-del svg {
fill: none;
stroke: currentColor;
stroke-width: 1.3;
stroke-linecap: round;
stroke-linejoin: round;
}
.qy-rail-row:hover .qy-rail-del,
.qy-rail-row.is-active .qy-rail-del,
.qy-rail-del:focus-visible { opacity: 1; }
.qy-rail-confirm {
flex: 0 0 auto;
margin-right: 4px;
padding: 3px 8px;
border: 0;
border-radius: 6px;
background: var(--lp-red-deep);
color: var(--lp-surface);
font: inherit;
font-size: var(--lp-fs-2xs);
font-weight: 600;
cursor: pointer;
}
.qy-rail-ask {
flex: 0 0 auto;
margin-top: 8px;
padding: 7px 8px;
border-radius: var(--lp-r-md);
color: var(--lp-blue-solid);
font-size: var(--lp-fs-xs);
font-weight: 600;
text-decoration: none;
}
.qy-rail-ask:hover { background: var(--lp-surface-2); }
/* ── the surface: the grid, and nothing above it ──────────────────────────── */
/* W35-T21 (owner item 4 / R2): the `.qy-prov*` family is deleted with the component. */
.qy-surface {
flex: 1 1 auto;
min-width: 0;
height: 100%;
display: flex;
flex-direction: column;
overflow: hidden;
}
.qy-grid-host {
flex: 1 1 auto;
min-height: 0;
overflow: hidden;
}
/* ── the empty state ──────────────────────────────────────────────────────── */
.qy-empty {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
min-height: 260px;
padding: 34px 44px;
box-sizing: border-box;
background: var(--lp-wash);
text-align: center;
}
.qy-empty-h { margin: 0 0 8px; color: var(--lp-ink); font-size: var(--lp-fs-lg); font-weight: 650; }
.qy-empty-p { max-width: 58ch; margin: 0 0 18px; color: var(--lp-muted); font-size: var(--lp-fs-sm); line-height: var(--lp-lh); }
.qy-empty-go { padding: 8px 14px; border-radius: var(--lp-r-md); background: var(--lp-blue-solid); color: var(--lp-surface); font-size: var(--lp-fs-sm); font-weight: 650; text-decoration: none; }
.qy-empty-go:hover { background: var(--lp-blue-solid); }