/* --------------------------------------------------------------------------- query/query.css — the Query module's own stylesheet. The Query module IS the database module — `shell-db-frame` + `DbHead` + `CustomerGrid` — so the frame, the header, 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 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 { color: var(--lp-muted); font-size: var(--lp-fs-2xs); } /* 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: provenance line, then the grid ──────────────────────────── */ .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; } .qy-prov { flex: 0 0 auto; border-bottom: 1px solid var(--lp-line); background: var(--lp-surface); } .qy-prov-btn { display: flex; align-items: baseline; gap: 10px; width: 100%; padding: 7px 14px; border: 0; background: transparent; font: inherit; text-align: left; cursor: pointer; } .qy-prov-q { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--lp-muted); font-size: var(--lp-fs-xs); } .qy-prov-toggle { flex: 0 0 auto; color: var(--lp-blue-solid); font-size: var(--lp-fs-2xs); font-weight: 600; } .qy-prov-detail { margin: 0; padding: 0 14px 9px; color: var(--lp-muted); font-size: var(--lp-fs-2xs); line-height: var(--lp-lh); word-break: break-word; } /* ── 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); }