| // Copyright (C) 2026 The Android Open Source Project |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| @use "typefaces" as *; |
| @use "common" as *; |
| |
| // Plugin styles are imported by each plugin's index.ts via Vite's CSS pipeline. |
| |
| // BigTrace-specific styles; `.pf-bt-` prefix avoids collisions. |
| |
| // ---------- Settings & endpoint ---------- |
| |
| .pf-bt-settings-card-wrapper--disabled { |
| opacity: 0.6; |
| } |
| |
| .pf-bt-settings-controls--disabled { |
| pointer-events: none; |
| } |
| |
| // Settings-card title row (bigtrace): Switch + title left, optional per-setting |
| // reset pushed right. pf-bt classes — not the shared pf-settings-card BEM. |
| .pf-bt-settings-card-title { |
| display: flex; |
| align-items: center; |
| } |
| |
| .pf-bt-settings-card-reset { |
| margin-left: auto; |
| } |
| |
| .pf-bt-textarea { |
| width: 100%; |
| min-height: 60px; |
| max-height: 200px; |
| resize: vertical; |
| font-family: var(--pf-font-monospace); |
| font-size: var(--pf-font-size-s); |
| padding: 6px 8px; |
| border: solid 1px var(--pf-color-border-secondary); |
| border-radius: 4px; |
| background: var(--pf-color-void); |
| color: inherit; |
| |
| &:hover { |
| border-color: var(--pf-color-border); |
| } |
| |
| &:focus { |
| outline: none; |
| border-color: var(--pf-color-primary); |
| } |
| } |
| |
| // ---------- Layout ---------- |
| |
| // Bounds the page + SplitPanel/Tabs chain so DataGrid fillHeight scrolls. |
| .pf-bt-query-page { |
| height: 100%; |
| min-height: 0; |
| |
| > .pf-split-panel { |
| height: 100%; |
| } |
| } |
| |
| .pf-bt-query-page__editor-tabs { |
| height: 100%; |
| |
| // Tab strip is 32px; give the content (the editor/results split) the rest. |
| .pf-tabs__content { |
| height: calc(100% - 32px); |
| } |
| |
| .pf-split-panel { |
| height: 100%; |
| } |
| } |
| |
| .pf-bt-query-page__results { |
| height: 100%; |
| } |
| |
| .pf-bt-query-page__history { |
| height: 100%; |
| min-height: 0; |
| } |
| |
| // Brand block at the far left of the topbar (the left nav is gone — the query |
| // page is the whole app). |
| .pf-bt-topbar-brand { |
| position: absolute; |
| left: 12px; |
| display: flex; |
| align-items: center; |
| gap: 8px; |
| font-size: 16px; |
| font-weight: 500; |
| color: var(--pf-color-text); |
| } |
| |
| .pf-bt-topbar-logo { |
| height: 1.2em; |
| } |
| |
| // Endpoint panel hanging off the topbar's connection button. |
| .pf-bt-connection-panel { |
| display: flex; |
| flex-direction: column; |
| gap: 6px; |
| padding: 4px; |
| min-width: 340px; |
| |
| &__title { |
| font-weight: 600; |
| } |
| |
| &__desc { |
| color: var(--pf-color-text-muted); |
| font-size: var(--pf-font-size-s); |
| } |
| |
| &__input { |
| width: 100%; |
| } |
| |
| &__actions { |
| display: flex; |
| gap: 6px; |
| justify-content: flex-end; |
| } |
| } |
| |
| // ---------- Launcher: start a query / Settings of an existing one ---------- |
| |
| // Fills the tab. One page for both jobs — start a query, or an existing |
| // query's Trace Selection: a scrolling body holding the Presets section and |
| // the trace-selection form, and a footer with the actions. |
| .pf-bt-launcher { |
| height: 100%; |
| min-height: 0; |
| display: flex; |
| flex-direction: column; |
| overflow: hidden; |
| |
| &__presets { |
| display: flex; |
| flex-direction: column; |
| gap: 16px; |
| } |
| |
| &__empty-detail { |
| color: var(--pf-color-text-muted); |
| margin-bottom: 12px; |
| } |
| |
| // Scrolls independently of the footer, which stays reachable. |
| &__body { |
| flex: 1; |
| min-height: 0; |
| overflow-y: auto; |
| padding: 16px 24px 0; |
| } |
| |
| &__footer { |
| display: flex; |
| align-items: center; |
| gap: 8px; |
| padding: 8px 24px; |
| border-top: 1px solid var(--pf-color-border); |
| background: var(--pf-color-background-secondary); |
| } |
| |
| &__footer-spacer { |
| flex: 1; |
| } |
| } |
| |
| // Name / group / description fields in the save-preset and edit-preset modals. |
| .pf-bt-save-preset { |
| display: flex; |
| flex-direction: column; |
| gap: 4px; |
| min-width: 320px; |
| |
| label { |
| color: var(--pf-color-text-muted); |
| font-size: var(--pf-font-size-s); |
| margin-top: 8px; |
| } |
| |
| // Why the name can't be saved as typed; sits right under the Name field. |
| &__message { |
| color: var(--pf-color-danger); |
| font-size: var(--pf-font-size-s); |
| } |
| } |
| |
| // ---------- Editor tabs & toolbar ---------- |
| |
| // Must fill the SplitPanel pane or .cm-editor (height:100%) collapses to one line. |
| .pf-bt-query-page__editor-panel { |
| display: flex; |
| flex-direction: column; |
| height: 100%; |
| min-height: 0; |
| |
| .pf-editor { |
| flex: 1; |
| min-height: 3rem; |
| } |
| } |
| |
| .pf-bt-query-page__editor-tabs > .pf-tabs__tabs { |
| overflow-x: auto; |
| scrollbar-width: thin; |
| scrollbar-color: var(--pf-color-border-secondary) transparent; |
| |
| > .pf-tabs__tab { |
| max-width: 220px; |
| } |
| } |
| |
| .pf-bt-tab-spacer { |
| flex: 1; |
| } |
| |
| .pf-bt-query-page__toolbar { |
| container-type: inline-size; |
| |
| // Without nowrap, "Persistent" wraps under its toggle when squeezed. |
| .pf-checkbox { |
| white-space: nowrap; |
| } |
| } |
| |
| @container (max-width: 520px) { |
| .pf-bt-query-page__hotkeys { |
| display: none; |
| } |
| } |
| |
| .pf-bt-divider { |
| display: inline-block; |
| width: 1px; |
| align-self: stretch; |
| margin: 4px 4px; |
| background-color: var(--pf-color-border-secondary); |
| } |
| |
| // ---------- Async status bar ---------- |
| |
| .pf-bt-status-bar { |
| padding: 12px 16px; |
| display: flex; |
| justify-content: space-between; |
| align-items: center; |
| gap: 16px; |
| } |
| |
| .pf-bt-status-bar-group { |
| display: inline-flex; |
| align-items: center; |
| gap: 16px; |
| } |
| |
| .pf-bt-status-bar-stat--rows { |
| margin-right: 16px; |
| } |
| |
| .pf-bt-status-bar--running { |
| .pf-bt-status-bar-stat--traces, |
| .pf-bt-status-bar-stat-label, |
| .pf-bt-status-bar-stat-value { |
| display: none; |
| } |
| } |
| |
| .pf-bt-status-bar-refresh { |
| position: relative; |
| display: inline-block; |
| } |
| |
| .pf-bt-status-bar-notif { |
| position: absolute; |
| top: -2px; |
| right: -2px; |
| width: 8px; |
| height: 8px; |
| border-radius: 50%; |
| background-color: var(--pf-color-success); |
| z-index: 10; |
| } |
| |
| .pf-bt-status-bar-stat { |
| display: inline-flex; |
| align-items: baseline; |
| gap: 6px; |
| font-variant-numeric: tabular-nums; |
| } |
| |
| .pf-bt-status-bar-stat--empty { |
| opacity: 0.55; |
| } |
| |
| .pf-bt-status-bar-duration { |
| display: inline-flex; |
| // Baseline aligns with the SUCCESS pill; center would sit ~2px high. |
| align-items: baseline; |
| gap: 6px; |
| font-variant-numeric: tabular-nums; |
| } |
| |
| // Wide: during a run it's the only progress signal (numbers are hover-only). |
| .pf-bt-inline-progress { |
| display: inline-block; |
| width: 140px; |
| height: 6px; |
| margin-left: 6px; |
| border-radius: 2px; |
| border: 1px solid var(--pf-color-border); |
| // Theme-aware track; hardcoded white rgba vanished on the light theme. |
| background-color: var(--pf-color-background-secondary); |
| overflow: hidden; |
| vertical-align: middle; |
| } |
| |
| .pf-bt-inline-progress-fill { |
| display: block; |
| height: 100%; |
| background-color: var(--pf-color-accent); |
| transition: width 0.3s ease-out; |
| will-change: width; |
| } |
| |
| // ---------- Query history ---------- |
| |
| // Fixed kind filter above a scrolling list (the panel itself never scrolls). |
| .pf-query-history { |
| display: flex; |
| flex-direction: column; |
| min-height: 0; |
| } |
| |
| .pf-bt-history-toolbar { |
| display: flex; |
| align-items: center; |
| justify-content: space-between; |
| gap: 4px; |
| padding: 4px 6px; |
| border-bottom: 1px solid var(--pf-color-border); |
| } |
| |
| // Two kind checkboxes; tight enough for a ~280px sidebar. |
| .pf-bt-history-filter { |
| display: flex; |
| align-items: center; |
| gap: 10px; |
| font-size: var(--pf-font-size-s); |
| |
| .pf-checkbox { |
| gap: 4px; |
| } |
| } |
| |
| .pf-bt-history-list { |
| flex: 1; |
| min-height: 0; |
| overflow-y: auto; |
| padding: 8px 4px 0; |
| } |
| |
| // Anchors the abs-positioned buttons; the shared float made a BFC that |
| // squeezed the meta card. |
| .pf-query-history__item { |
| // Real gap between entries so each reads as a distinct unit. Safe to set now |
| // that the buttons are position:absolute / float:none — the old float BFC |
| // that squeezed the meta card (and forced this margin off) is gone. |
| margin-bottom: 12px; |
| max-height: none; |
| overflow-y: visible; |
| position: relative; |
| } |
| |
| // Whole-entry hover highlight. The shared widgets/query_history.scss provides |
| // this via color_hover(), but the bigtrace bundle re-implements the history |
| // styles and dropped it — restate it here. The entry's surfaces (meta / |
| // details / pre) are opaque and layered, so overlay the translucent tint via |
| // background-image (which paints over each surface's background-color) instead |
| // of replacing the background. |
| .pf-query-history__item:hover { |
| .pf-bt-history-item-meta, |
| .pf-bt-history-item-details, |
| pre { |
| background-image: linear-gradient( |
| color_hover(transparent), |
| color_hover(transparent) |
| ); |
| } |
| } |
| |
| .pf-query-history__item-buttons { |
| position: absolute; |
| top: 4px; |
| right: 4px; |
| float: none; |
| z-index: 1; |
| } |
| |
| // Status-colored left bar, meta card only (clashes with the pre's border). |
| .pf-bt-history-item-meta { |
| border-left: 3px solid transparent; |
| // The band opens the query on click (same as the Open button). |
| cursor: pointer; |
| } |
| |
| .pf-query-history__item:has(.pf-bt-status-success) .pf-bt-history-item-meta { |
| border-left-color: var(--pf-color-success); |
| } |
| |
| .pf-query-history__item:has(.pf-bt-status-failed) .pf-bt-history-item-meta { |
| border-left-color: var(--pf-color-danger); |
| } |
| |
| .pf-query-history__item:has(.pf-bt-status-cancelled) .pf-bt-history-item-meta { |
| border-left-color: var(--pf-color-warning); |
| } |
| |
| .pf-query-history__item:has(.pf-bt-status-in-progress) |
| .pf-bt-history-item-meta { |
| border-left-color: var(--pf-color-primary); |
| } |
| |
| .pf-query-history__item:has(.pf-bt-status-queued) .pf-bt-history-item-meta, |
| .pf-query-history__item:has(.pf-bt-status-unknown) .pf-bt-history-item-meta { |
| border-left-color: var(--pf-color-text-muted); |
| } |
| |
| // padding-right reserves space for the abs-positioned Open/Delete buttons. |
| .pf-bt-history-item-meta { |
| position: relative; |
| background: var(--pf-color-background-tertiary); |
| padding: 6px 8px; |
| padding-right: 56px; |
| // Top + right only; the border-left status rule owns the left edge |
| // (shorthand would shrink it to 1px). |
| border-top: 1px solid var(--pf-color-border-secondary); |
| border-right: 1px solid var(--pf-color-border-secondary); |
| border-radius: 4px 4px 0 0; |
| display: flex; |
| flex-direction: column; |
| gap: 2px; |
| font-size: 11px; |
| color: var(--pf-color-text); |
| } |
| |
| .pf-bt-status-success { |
| color: var(--pf-color-success); |
| } |
| |
| .pf-bt-status-failed { |
| color: var(--pf-color-danger); |
| } |
| |
| .pf-bt-status-cancelled { |
| color: var(--pf-color-warning); |
| } |
| |
| .pf-bt-status-in-progress { |
| color: var(--pf-color-primary); |
| } |
| |
| .pf-bt-status-queued, |
| .pf-bt-status-unknown { |
| color: var(--pf-color-text-muted); |
| font-style: italic; |
| } |
| |
| .pf-bt-history-item-header { |
| display: flex; |
| align-items: baseline; |
| justify-content: space-between; |
| gap: 12px; |
| width: 100%; |
| |
| > span { |
| white-space: nowrap; |
| overflow: hidden; |
| text-overflow: ellipsis; |
| min-width: 0; |
| } |
| } |
| |
| .pf-bt-history-item-status { |
| flex-shrink: 0; |
| } |
| |
| // Ephemeral / Persistent marker — the list mixes both kinds. |
| .pf-bt-history-item-kind { |
| flex-shrink: 0; |
| font-size: var(--pf-font-size-xs); |
| text-transform: uppercase; |
| letter-spacing: 0.04em; |
| opacity: 0.75; |
| } |
| |
| .pf-bt-history-item-date { |
| text-align: right; |
| } |
| |
| // Materialized-only band between the meta header and the SQL pre. |
| .pf-bt-history-item-details { |
| background: var(--pf-color-background-secondary); |
| padding: 4px 8px; |
| border-left: 1px solid var(--pf-color-border-secondary); |
| border-right: 1px solid var(--pf-color-border-secondary); |
| border-top: 1px solid var(--pf-color-border-secondary); |
| border-bottom: 1px solid var(--pf-color-border-secondary); |
| display: flex; |
| align-items: baseline; |
| gap: 4px; |
| min-width: 0; |
| overflow: hidden; |
| font-size: var(--pf-font-size-xs); |
| font-variant-numeric: tabular-nums; |
| color: var(--pf-color-text-muted); |
| } |
| |
| .pf-bt-history-item-details--empty { |
| opacity: 0.55; |
| } |
| |
| .pf-bt-history-item-rows-value { |
| flex-shrink: 0; |
| } |
| |
| .pf-bt-history-item-table-link { |
| overflow: hidden; |
| text-overflow: ellipsis; |
| white-space: nowrap; |
| min-width: 0; |
| flex: 1 1 auto; |
| } |
| |
| .pf-bt-history-item-table-link--disabled { |
| color: var(--pf-color-text-muted); |
| pointer-events: none; |
| text-decoration: none; |
| } |
| |
| .pf-bt-history-item-table-link--active { |
| color: var(--pf-color-primary); |
| pointer-events: auto; |
| text-decoration: underline; |
| } |
| |
| .pf-query-history__item pre { |
| background: var(--pf-color-void); |
| padding: 8px; |
| border: solid 1px var(--pf-color-border-secondary); |
| border-top: none; |
| border-radius: 0 0 4px 4px; |
| margin: 0; |
| font-family: var(--pf-font-monospace, monospace); |
| font-size: 11px; |
| white-space: pre-wrap; |
| } |
| |
| .pf-query-history__item pre:hover::after { |
| content: none; |
| } |
| |
| // Clamped ~4 lines with a fade mask; click to expand. The `pre.` prefix |
| // keeps specificity == `.pf-query-history__item pre`. |
| pre.pf-bt-history-item-query, |
| pre.pf-bt-history-item-query--standalone { |
| cursor: pointer; |
| position: relative; |
| max-height: 4.5em; |
| overflow: hidden; |
| mask-image: linear-gradient(to bottom, black 70%, transparent 100%); |
| -webkit-mask-image: linear-gradient(to bottom, black 70%, transparent 100%); |
| } |
| |
| pre.pf-bt-history-item-query.pf-bt-history-item-query--expanded, |
| pre.pf-bt-history-item-query--standalone.pf-bt-history-item-query--expanded { |
| max-height: 50vh; |
| overflow: auto; |
| mask-image: none; |
| -webkit-mask-image: none; |
| } |
| |
| // Standalone (delete-confirm modal) has no .pf-query-history__item parent, so |
| // it declares the frame the sidebar variant inherits from |
| // `.pf-query-history__item pre`. |
| pre.pf-bt-history-item-query--standalone { |
| font-family: var(--pf-font-monospace, monospace); |
| background: var(--pf-color-void); |
| border: solid 1px var(--pf-color-border-secondary); |
| border-radius: 4px; |
| padding: 8px; |
| margin: 0; |
| white-space: pre-wrap; |
| } |
| |
| .pf-bt-history-item-query--empty { |
| font-style: italic; |
| opacity: 0.5; |
| } |
| |
| .pf-bt-history-empty-hint { |
| margin-top: 8px; |
| opacity: 0.7; |
| } |
| |
| .pf-bt-history-delete-date { |
| margin-bottom: 8px; |
| opacity: 0.7; |
| } |
| |
| // ---------- Results panel ---------- |
| |
| .pf-bt-error-tab-title { |
| color: var(--pf-color-danger); |
| } |
| |
| .pf-bt-error-content { |
| overflow: auto; |
| max-height: 100%; |
| padding: 12px; |
| margin: 0; |
| font-size: 0.85em; |
| white-space: pre-wrap; |
| } |
| |
| // A fetch_results failure shown in place of the results grid: a short heading |
| // plus the selectable, scrollable error body (reusing .pf-bt-error-content). |
| .pf-bt-results-error { |
| display: flex; |
| flex-direction: column; |
| height: 100%; |
| min-height: 0; |
| |
| &__title { |
| padding: 12px 12px 0; |
| font-weight: 500; |
| color: var(--pf-color-danger); |
| } |
| |
| .pf-bt-error-content { |
| flex: 1; |
| } |
| } |
| |
| // min-height:0 chain lets DataGrid fillHeight work; only the body scrolls. |
| .pf-bt-results-panel { |
| display: flex; |
| flex-direction: column; |
| height: 100%; |
| min-height: 0; |
| } |
| |
| .pf-bt-results-container { |
| display: flex; |
| flex-direction: column; |
| flex: 1; |
| min-height: 0; |
| } |
| |
| .pf-bt-results-container > .pf-data-grid { |
| flex: 1; |
| min-height: 0; |
| } |
| |
| // ---------- Query settings form ---------- |
| |
| .pf-bt-settings-page { |
| &__plugin-section { |
| margin-bottom: 32px; |
| |
| &:last-child { |
| margin-bottom: 0; |
| } |
| } |
| |
| &__plugin-title { |
| font-size: var(--pf-font-size-xl); |
| font-weight: 600; |
| margin: 0 0 16px 0; |
| padding: 8px 12px; |
| background: var(--pf-minimal-background); |
| border-radius: 4px; |
| } |
| |
| // The settings cards live in a CardStack, but BigTraceSettingsCard wraps |
| // each Card in a <div> for its disabled-state class — that wrapper hides the |
| // cards from CardStack's unified-seam styling, so they render flush with no |
| // gap. Render every settings card as a distinct, spaced, bordered card |
| // instead (clearer for the mix of simple key/value settings and the compound |
| // Traces / Query Result Columns cards). |
| .pf-card-stack { |
| border: none; |
| box-shadow: none; |
| overflow: visible; |
| gap: 12px; |
| } |
| |
| .pf-card-stack > .pf-card, |
| .pf-card-stack > div > .pf-card { |
| border: solid 1px var(--pf-color-border); |
| border-radius: 4px; |
| } |
| } |
| |
| // ---------- Query-page settings bar + per-chip modals ---------- |
| |
| .pf-bt-editor-tab { |
| display: flex; |
| flex-direction: column; |
| height: 100%; |
| min-height: 0; |
| } |
| |
| .pf-bt-editor-tab > .pf-split-panel { |
| flex: 1 1 auto; |
| min-height: 0; |
| } |
| |
| .pf-bt-settings-bar { |
| display: flex; |
| align-items: flex-start; |
| gap: 8px; |
| padding: 6px 12px; |
| background: var(--pf-color-background-secondary); |
| border-bottom: 1px solid var(--pf-color-border-secondary); |
| flex: 0 0 auto; |
| |
| // Right-pinned action; never squeezed by a long chip row. |
| &__end { |
| flex: 0 0 auto; |
| margin-left: auto; |
| } |
| |
| &__chips { |
| flex: 1 1 auto; |
| min-width: 0; |
| |
| // A chip with a long value (e.g. a trace-path filter) must ellipsize, not |
| // grow the editor panel past the split and scroll the whole page. The |
| // shared chip pins min-width: max-content, so cap and let it shrink here; |
| // its label already has text-overflow: ellipsis. |
| .pf-chip { |
| min-width: 0; |
| max-width: 100%; |
| } |
| } |
| } |
| |
| // The per-query settings form — scrollable container, no SettingsShell |
| // chrome (it isn't a page). |
| .pf-bt-settings-embedded { |
| overflow: auto; |
| height: 100%; |
| box-sizing: border-box; |
| padding: 16px 20px 24px; |
| |
| .pf-bt-settings-page { |
| margin: 0; |
| } |
| } |
| |
| // Page heading of the launcher / Trace Selection page. |
| .pf-bt-corpus-head { |
| display: flex; |
| flex-direction: column; |
| gap: 6px; |
| margin: 4px 0 20px; |
| |
| &__title { |
| font-size: var(--pf-font-size-xl); |
| font-weight: 600; |
| } |
| |
| &__subtitle { |
| color: var(--pf-color-text-muted); |
| font-size: var(--pf-font-size-s); |
| } |
| } |
| |
| // UUID mode: the paste box IS the page, so the whole chain from the |
| // launcher body down to the textarea stretches to fill the height the grid |
| // otherwise would. min-height: 0 at every flex level or the intrinsic |
| // textarea height wins and the page overflows instead of fitting. |
| .pf-bt-launcher--uuid { |
| .pf-bt-launcher__body { |
| display: flex; |
| flex-direction: column; |
| } |
| |
| .pf-bt-settings-embedded, |
| .pf-bt-settings-page, |
| .pf-bt-settings-page__plugin-section, |
| .pf-card-stack, |
| .pf-bt-uuid-settings-card, |
| .pf-bt-uuid-card { |
| flex: 1; |
| display: flex; |
| flex-direction: column; |
| min-height: 0; |
| } |
| |
| .pf-bt-settings-page__plugin-section { |
| margin-bottom: 0; |
| } |
| |
| // The shared settings-card style centers its children (it lays out |
| // title/controls); here the card is a column and the paste box must span it. |
| .pf-bt-uuid-settings-card { |
| align-items: stretch; |
| } |
| |
| .pf-bt-uuid-card__input { |
| flex: 1; |
| } |
| } |
| |
| // UUID-mode card: paste box + count. |
| .pf-bt-uuid-card { |
| display: flex; |
| flex-direction: column; |
| gap: 8px; |
| |
| &__head { |
| display: flex; |
| align-items: center; |
| justify-content: space-between; |
| gap: 12px; |
| } |
| |
| &__title-row { |
| display: flex; |
| align-items: center; |
| gap: 6px; |
| } |
| |
| // Format help lives behind the icon, not as page text. |
| &__info { |
| color: var(--pf-color-text-muted); |
| font-size: 16px; |
| cursor: help; |
| } |
| |
| &__input { |
| width: 100%; |
| min-height: 160px; |
| resize: vertical; |
| box-sizing: border-box; |
| font-family: var(--pf-font-monospace, monospace); |
| font-size: var(--pf-font-size-s); |
| color: var(--pf-color-text); |
| background: var(--pf-color-background); |
| border: 1px solid var(--pf-color-border); |
| border-radius: 4px; |
| padding: 8px 10px; |
| |
| &:focus-visible { |
| outline: 1px solid var(--pf-color-primary); |
| } |
| } |
| |
| &__count { |
| color: var(--pf-color-text-muted); |
| font-size: var(--pf-font-size-s); |
| } |
| } |
| |
| // Category selector + per-category preset dropdown; the UUID-mode entry |
| // anchors to the row's right edge (auto margin, so it holds even when the |
| // row wraps). Descriptions are tooltips, not page text. |
| .pf-bt-preset-picker { |
| display: flex; |
| align-items: center; |
| flex-wrap: wrap; |
| gap: 8px 16px; |
| margin-bottom: 8px; |
| |
| // The dropdown trigger holds a steady width; label left, arrow right. |
| &__select { |
| min-width: 260px; |
| justify-content: space-between; |
| } |
| |
| &__uuid { |
| margin-left: auto; |
| } |
| } |
| |
| // Manage-presets modal: one row per preset saved in this browser. List |
| // styling like a menu — hover highlight instead of hairlines; the danger |
| // color is the confirm dialog's, not every row's. |
| .pf-bt-manage-presets { |
| display: flex; |
| flex-direction: column; |
| gap: 2px; |
| min-width: min(440px, 80vw); |
| |
| &__row { |
| display: flex; |
| align-items: center; |
| gap: 4px; |
| padding: 6px 8px; |
| border-radius: 4px; |
| |
| &:hover { |
| background: var(--pf-color-background-secondary); |
| } |
| } |
| |
| // A row expanded into its inline editor: a contained panel with the form |
| // stacked over right-aligned actions, so it reads as one unit in the list. |
| &__row--editing { |
| flex-direction: column; |
| align-items: stretch; |
| background: var(--pf-color-background-secondary); |
| padding: 8px; |
| |
| &:hover { |
| background: var(--pf-color-background-secondary); |
| } |
| } |
| |
| &__form { |
| min-width: 0; |
| |
| label:first-child { |
| margin-top: 0; |
| } |
| } |
| |
| &__form-actions { |
| display: flex; |
| justify-content: flex-end; |
| gap: 4px; |
| margin-top: 8px; |
| } |
| |
| &__text { |
| flex: 1; |
| min-width: 0; |
| margin-right: 16px; |
| } |
| |
| &__name { |
| font-weight: 500; |
| } |
| |
| &__meta { |
| color: var(--pf-color-text-muted); |
| font-size: smaller; |
| } |
| |
| &__empty { |
| color: var(--pf-color-text-muted); |
| } |
| } |
| |
| // A chosen experiment's name can be a sentence; the chip states which arm |
| // and as much of it as fits, with the whole of both arms in the tooltip. |
| .pf-bt-settings-bar .pf-chip__label { |
| overflow: hidden; |
| text-overflow: ellipsis; |
| white-space: nowrap; |
| max-width: 32rem; |
| } |
| |
| // Trace-grid header row: column picker left, experiment filter hard right. |
| .pf-bt-trace-columns { |
| display: flex; |
| align-items: center; |
| gap: 8px; |
| } |
| |
| // Chosen experiment: arm toggle, the active arm, and the way to clear it. |
| // The name is free to clamp; the id stays whole. |
| .pf-bt-experiment-filter { |
| display: flex; |
| align-items: center; |
| gap: 8px; |
| min-width: 0; |
| margin-left: auto; |
| |
| &__open { |
| margin-left: auto; |
| } |
| |
| &__arm { |
| overflow: hidden; |
| text-overflow: ellipsis; |
| white-space: nowrap; |
| max-width: 320px; |
| } |
| } |
| |
| // The popup box itself, so the one thing that can hang off the screen is |
| // bounded on the element that hangs. Everything from here down is sized by |
| // its content, so the viewport is the only fixed thing to measure against: |
| // its width less the 8px per side Popup keeps clear of the edges. Border and |
| // padding are inside the number, the box being border-box. |
| // Two classes deep to outrank the widget's own `--fit-content`, which unsets |
| // max-width to let content decide the size — content still decides, it just |
| // can't decide to leave the screen. |
| .pf-popup.pf-bt-experiment-popup { |
| max-width: calc(100vw - 16px); |
| } |
| |
| // Experiment search popup. Own block, like the connection panel — the shared |
| // popup content class stays untouched. |
| .pf-bt-experiment-picker { |
| display: flex; |
| flex-direction: column; |
| gap: 8px; |
| // Follows the window, so a wide screen gets a wide popup; bounded in rem |
| // so it also respects the reader's font size, stays usable when narrow, |
| // and never runs a name past a comfortable line length. |
| width: clamp(30rem, 40vw, 60rem); |
| // The floor would otherwise win over a very narrow window; yielding to the |
| // box around it is what makes that cap effective, since a width this |
| // explicit would happily overflow its container. |
| max-width: 100%; |
| |
| &__body { |
| display: flex; |
| flex-direction: column; |
| gap: 2px; |
| max-height: 60vh; |
| overflow-y: auto; |
| } |
| |
| &__note { |
| color: var(--pf-color-text-muted); |
| padding: 4px 0; |
| } |
| |
| // One experiment: both arms, picked as a unit. |
| &__row { |
| display: flex; |
| flex-direction: column; |
| gap: 2px; |
| padding: 6px 8px; |
| border-radius: 4px; |
| cursor: pointer; |
| |
| &:hover { |
| background: var(--pf-color-background-secondary); |
| } |
| } |
| |
| &__arm { |
| display: flex; |
| align-items: baseline; |
| gap: 8px; |
| min-width: 0; |
| } |
| |
| &__label { |
| color: var(--pf-color-text-muted); |
| font-size: smaller; |
| flex: 0 0 72px; |
| } |
| |
| &__id { |
| font-variant-numeric: tabular-nums; |
| flex: 0 0 auto; |
| } |
| |
| // Choosing is done by the name, so it wraps rather than truncates; the id |
| // and label keep their column while it does. |
| &__name { |
| flex: 1; |
| min-width: 0; |
| overflow-wrap: anywhere; |
| |
| &--denied { |
| color: var(--pf-color-text-muted); |
| } |
| } |
| } |
| |
| // Query-settings modal (gear in the run toolbar): the settings form without |
| // the page chrome — the modal provides the frame and the scrolling. |
| .pf-bt-query-settings-modal { |
| width: min(640px, 90vw); |
| |
| .pf-bt-settings-embedded { |
| height: auto; |
| max-height: 65vh; |
| padding: 0; |
| } |
| } |