/* Scrolls horizontally within its own box on a narrow viewport instead
of forcing the whole page to overflow — see Table.tsx's comment. */
.ui-table-scroll {
overflow-x: auto;
}
.ui-table {
width: 100%;
border-collapse: collapse;
}
.ui-table th {
text-align: left;
font-weight: 600;
color: var(--muted);
padding: 0.5em 0.75em;
border-bottom: 1px solid var(--border);
}
.ui-table td {
padding: 0.5em 0.75em;
border-bottom: 1px solid var(--border);
}
.ui-table tr:last-child td {
border-bottom: none;
}
.ui-table-empty {
color: var(--muted);
text-align: center;
padding: 1.25em 0.75em;
}
/* A cell holding free-form prose (an operator- or agent-provided string,
not a short discrete label) rather than open-ended growth that drags
the whole table wider — caps the column and wraps within it instead. */
.ui-table-prose {
max-width: 32em;
white-space: normal;
word-break: break-word;
}
/* Sortable header — the whole header cell is the click target, not a
separate icon-only button next to it, same "control lives on the
thing it affects" reasoning as `Badge`'s own click-to-toggle shape. */
.ui-table-sort-button {
display: inline-flex;
align-items: center;
gap: 0.35em;
background: none;
border: none;
padding: 0;
margin: 0;
font: inherit;
font-weight: 600;
color: inherit;
cursor: pointer;
}
.ui-table-sort-button:hover {
color: var(--fg);
}
.ui-table-sort-glyph {
opacity: 0.6;
font-size: 0.85em;
}
.ui-table-sort-button:hover .ui-table-sort-glyph {
opacity: 1;
}
/* `.ui-table-th-filterable` (set on a filterable column's `
`, no
rule of its own) exists purely as a `:hover`/`:focus-within` selector
target for the fade below — nothing to do with positioning the
popover itself, which is computed in JS and rendered via a portal
instead (see Table.tsx's own comment on `popoverPos` for why it
isn't just `position: absolute` under this ` | `).
The filter-icon trigger — invisible by default, `opacity` transition
rather than a hard show/hide (mara: "fade in out animation"). Shown
on three signals, matching Table.tsx's own comment on `filterValue`:
hovering/focusing the header cell (so it's discoverable without a
filter already set), the popover being open (still visible while
you're using it, even if the pointer has moved off the header), or
`.ui-table-filter-icon-active` — a filter is *set* on this column,
so the icon stays put as a persistent "this column is filtered"
indicator rather than disappearing the moment the header isn't
hovered (mara: "when a filter is set, the filter icon does not
disappear"). `:focus-within` (not just `:hover`) so a keyboard user
tabbing to the icon sees it appear too, not just a mouse hovering. */
.ui-table-filter-icon {
display: inline-flex;
align-items: center;
justify-content: center;
margin-left: 0.35em;
padding: 0.15em;
background: none;
border: none;
border-radius: 4px;
color: var(--muted);
cursor: pointer;
opacity: 0;
transition: opacity 0.15s ease;
}
.ui-table-th-filterable:hover .ui-table-filter-icon,
.ui-table-th-filterable:focus-within .ui-table-filter-icon,
.ui-table-filter-icon-active {
opacity: 1;
}
.ui-table-filter-icon:hover {
color: var(--fg);
background: var(--bg);
}
/* A filter is live on this column — `--purple`, theme.css's own "active
tabs, links, highlights" accent, so an operator scanning the header
row reads it the same way anything else marked active does. */
.ui-table-filter-icon-active {
color: var(--purple);
}
/* `position`/`top`/`left` are inline styles, not here — Table.tsx
computes them from the anchor ` | `'s own `getBoundingClientRect()`
and renders this via a portal onto `document.body` (see its own
`popoverPos` comment for the full reasoning: escaping
`.ui-table-scroll`'s clip). `z-index: 10` matches the existing
overlay-menu convention (`LinksMenu`/`UserMenu`), now that this
sits alongside them as a `document.body`-level sibling rather than
nested inside the table. */
.ui-table-filter-popover {
z-index: 10;
min-width: 12em;
padding: 0.5em;
background: var(--bg-elev);
border: 1px solid var(--border);
border-radius: 6px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.25);
}
.ui-table-filter-input {
width: 100%;
box-sizing: border-box;
background: var(--bg);
color: var(--fg);
border: 1px solid var(--border);
border-radius: 4px;
padding: 0.25em 0.5em;
font: inherit;
font-size: 0.9em;
}
/* `filterMode: "multiselect"`'s actual checkbox-list content is
`MultiselectFilterOptions` (`ui/multiselect-filter/`) now — its own
colocated CSS, not here. */
/* The negate toggle sits under every filter mode's own control (mara:
"you should be able to change if the filter is negated or not") —
a hairline rule separates it from the control above so "exclude"
doesn't read as one more option belonging to that control. */
.ui-table-filter-negate {
display: flex;
align-items: center;
gap: 0.35em;
margin-top: 0.5em;
padding-top: 0.5em;
border-top: 1px solid var(--border);
color: var(--muted);
font-size: 0.85em;
cursor: pointer;
}
/* One button clears every column's filter on this table at once (mara:
"have a small reset filters btn") — text-button styling matching
`.ui-table-sort-button`'s "no chrome, just a clickable label"
treatment, not a full `Badge`/bordered-button — this is a quiet
secondary action, not a primary one. */
.ui-table-reset-filters {
display: inline-block;
background: none;
border: none;
padding: 0;
margin: 0 0 0.5em;
font: inherit;
font-size: 0.85em;
color: var(--muted);
text-decoration: underline;
cursor: pointer;
}
.ui-table-reset-filters:hover {
color: var(--fg);
}
|