/* Shared data table (DataTable.razor).
   Every selector is prefixed `bdt-` so it cannot reach another module's
   markup. These rules started life as the Tessera table and keep its look;
   tessera.css now aliases its own tokens onto the ones defined here so the
   module's cards and tree stay visually identical. */

:root {
    --bdt-border: #e5e7eb;
    --bdt-border-strong: #d1d5db;
    --bdt-muted: #6b7280;
    --bdt-head: #374151;
    --bdt-accent: #1b6ec2;
    --bdt-surface: #f9fafb;
    --bdt-hover: #f3f4f6;
}

/* ---------- toolbar above the table ---------- */

.bdt-toolbar {
    display: flex;
    align-items: center;
    gap: .75rem;
    flex-wrap: wrap;
    margin-bottom: .5rem;
    font-size: .8125rem;
    color: var(--bdt-muted);
}

.bdt-count {
    font-variant-numeric: tabular-nums;
}

.bdt-chip {
    display: inline-flex;
    align-items: center;
    gap: .35rem;
    padding: .1rem .5rem;
    border: 1px solid var(--bdt-border);
    border-radius: 999px;
    background: #fff;
    font-size: .75rem;
    color: var(--bdt-head);
}

.bdt-chip-clear {
    border: 0;
    background: none;
    padding: 0;
    line-height: 1;
    color: var(--bdt-muted);
    cursor: pointer;
    font-size: .875rem;
}

.bdt-chip-clear:hover {
    color: #b02a37;
}

/* ---------- table shell ---------- */

/* The component root stacks toolbar, scroller and grip. */
.bdt {
    display: flex;
    flex-direction: column;
    min-width: 0;
}

.bdt-h-fill {
    min-height: 0;
}

/* The scroll container. Sticky positioning resolves against the nearest
   scrolling ancestor, so the header only stays put once *this* element is what
   scrolls — a wrapper with no height cap scrolls the page instead and the
   header sails away with it. */
.bdt-wrap {
    border: 1px solid var(--bdt-border);
    border-radius: .5rem;
    overflow: auto;
    background: #fff;
    min-width: 0;
}

.bdt-h-fixed > .bdt-wrap {
    max-height: var(--bdt-h, 60vh);
}

/* Fill measures the space left below the table and caps itself there, rather
   than inheriting a height. The app shell scrolls the document — nothing above
   has a resolved height for `height: 100%` to resolve against — so the number
   comes from JS and is refreshed on resize. */
.bdt-h-fill > .bdt-wrap {
    /* `height`, not `max-height`: Fill means "occupy the space", so the frame
       reaches the bottom of the window even when the rows do not fill it. A
       short list then sits in a bordered area that ends where the page ends,
       instead of a floating box with dead space beneath it. */
    height: var(--bdt-h, 60vh);
    min-height: 8rem;
}

/* Fill mode has no grip: the window decides the height, so there is nothing to
   drag and nothing to reset. */

/* When a grip follows the scroller, the rounded bottom corners belong to the
   grip — otherwise the two read as separate boxes stacked by accident. */
.bdt:has(> .bdt-grip) > .bdt-wrap {
    border-bottom-left-radius: 0;
    border-bottom-right-radius: 0;
}

/* ---------- height grip ---------- */

.bdt-grip {
    height: .75rem;
    margin-top: -1px;
    border: 1px solid var(--bdt-border);
    border-top: 0;
    border-radius: 0 0 .5rem .5rem;
    background: var(--bdt-surface);
    cursor: ns-resize;
    position: relative;
    transition: background-color .12s ease-in-out;
}

/* The dots are the affordance — a bare strip reads as a border, not a handle. */
.bdt-grip::after {
    content: "";
    position: absolute;
    left: 50%;
    top: 50%;
    width: 1.75rem;
    height: 2px;
    transform: translate(-50%, -50%);
    border-top: 2px dotted var(--bdt-border-strong);
}

.bdt-grip:hover,
.bdt-grip.is-dragging {
    background: var(--bdt-hover);
}

table.bdt-table {
    width: 100%;
    margin: 0;
    border-collapse: separate;
    border-spacing: 0;
    font-size: .875rem;
}

/* Applied only once every visible column has an explicit width. Fixed layout is
   what makes a drag move one column instead of reflowing all of them; with a
   width missing the browser starts redistributing again and the drag fights
   itself.

   The width stays at 100% and the component supplies min-width as the exact sum
   of the chosen column widths. `max-content` would be wrong: it measures the
   *content*, so a table whose columns comfortably fit would still be forced
   wide enough for its longest cell and scroll sideways for no reason. */
table.bdt-table.is-fixed {
    table-layout: fixed;
}

table.bdt-table.is-fixed th,
table.bdt-table.is-fixed td {
    overflow: hidden;
    text-overflow: ellipsis;
}

table.bdt-table.is-fixed .bdt-head-row th {
    white-space: nowrap;
}

/* ---------- header ---------- */

/* The label row is sticky so a long table keeps its column names while the
   filter row scrolls away with the data — filters are set once, column names
   are read constantly. */
.bdt-table thead tr.bdt-head-row th {
    position: sticky;
    top: 0;
    z-index: 3;
    background: var(--bdt-surface);
    padding: .5rem .625rem;
    border-bottom: 1px solid var(--bdt-border);
    white-space: nowrap;
    text-align: inherit;
}

/* A heading is a label that happens to be clickable, so it carries no button
   chrome at all — the affordance is the chevron and the hover colour. */
.bdt-sort {
    all: unset;
    display: inline-flex;
    align-items: baseline;
    gap: .3rem;
    cursor: pointer;
    font-size: .6875rem;
    font-weight: 600;
    letter-spacing: .05em;
    text-transform: uppercase;
    color: var(--bdt-muted);
    transition: color .12s ease-in-out;
}

.bdt-sort:hover,
.bdt-sort:focus-visible {
    color: var(--bdt-accent);
}

.bdt-sort:focus-visible {
    outline: 2px solid rgba(27, 110, 194, .35);
    outline-offset: 2px;
    border-radius: 2px;
}

.bdt-head-static {
    font-size: .6875rem;
    font-weight: 600;
    letter-spacing: .05em;
    text-transform: uppercase;
    color: var(--bdt-muted);
}

/* Reserve the arrow's width always, so labels do not shift sideways when a
   column becomes sorted. */
.bdt-arrow {
    display: inline-block;
    min-width: .6em;
    font-size: .625rem;
    opacity: 0;
    transition: opacity .12s ease-in-out;
}

.bdt-sort:hover .bdt-arrow {
    opacity: .4;
}

.bdt-sort.is-sorted {
    color: var(--bdt-accent);
}

.bdt-sort.is-sorted .bdt-arrow {
    opacity: 1;
}

.bdt-rank {
    font-size: .5625rem;
    font-weight: 700;
    color: #fff;
    background: var(--bdt-accent);
    border-radius: 999px;
    padding: 0 .3em;
    line-height: 1.4;
}

/* ---------- filter row ---------- */

.bdt-table thead tr.bdt-filter-row th {
    position: sticky;
    /* Set from JS once the label row has been laid out — the offset depends on
       whether headings wrapped, which CSS cannot know up front. */
    top: var(--bdt-head-h, 2rem);
    z-index: 2;
    background: #fff;
    padding: .35rem .5rem .5rem;
    border-bottom: 2px solid var(--bdt-border-strong);
}

.bdt-filter {
    width: 100%;
    /* Kept small on purpose: this minimum is multiplied by every column, so a
       generous value here is what stops an otherwise-fitting table from fitting
       its card. Three characters of feedback is enough for a filter box. */
    min-width: 3rem;
    border: 1px solid transparent;
    border-radius: .375rem;
    background: var(--bdt-surface);
    padding: .2rem .45rem;
    font-size: .75rem;
    font-weight: 400;
    color: var(--bdt-head);
    transition: border-color .12s ease-in-out, background-color .12s ease-in-out;
}

.bdt-filter::placeholder {
    color: #b6bcc6;
}

.bdt-filter:hover {
    border-color: var(--bdt-border);
}

.bdt-filter:focus {
    outline: none;
    background: #fff;
    border-color: var(--bdt-accent);
    box-shadow: 0 0 0 3px rgba(27, 110, 194, .12);
}

/* A choice filter is the same control in a different shape. box-sizing matters
   here and not on the input: a select's default content-box would push the
   column past the width the header measured. */
select.bdt-filter {
    box-sizing: border-box;
    padding-right: .25rem;
    cursor: pointer;
}

/* An active filter has to be obvious — otherwise an empty-looking table reads
   as missing data rather than a narrowed view. */
.bdt-filter.is-active {
    background: #fff;
    border-color: var(--bdt-accent);
}

/* ---------- body ---------- */

.bdt-table tbody td {
    padding: .45rem .625rem;
    border-bottom: 1px solid var(--bdt-border);
    vertical-align: middle;
}

.bdt-table tbody tr:last-child td {
    border-bottom: 0;
}

.bdt-table tbody tr:hover td {
    background: var(--bdt-hover);
}

.bdt-table tbody td a {
    text-decoration: none;
}

.bdt-table tbody td a:hover {
    text-decoration: underline;
}

.bdt-empty {
    padding: 1.5rem .625rem;
    text-align: center;
    color: var(--bdt-muted);
}

/* Numbers read wrong ragged; tabular figures keep the columns aligned. */
.bdt-table .text-end {
    font-variant-numeric: tabular-nums;
}

/* ---------- column resize handle ---------- */

/* Sits in the header cell's padding, not beside the label, so it does not
   consume width the column could use for content. */
.bdt-resizer {
    position: absolute;
    top: 0;
    right: -3px;
    width: 7px;
    height: 100%;
    cursor: col-resize;
    z-index: 4;
    touch-action: none;
    user-select: none;
}

.bdt-resizer::after {
    content: "";
    position: absolute;
    top: 15%;
    left: 3px;
    width: 1px;
    height: 70%;
    background: var(--bdt-border-strong);
    opacity: 0;
    transition: opacity .12s ease-in-out;
}

.bdt-resizer:hover::after,
.bdt-resizer.is-dragging::after {
    opacity: 1;
    background: var(--bdt-accent);
}

.bdt-resizer.is-dragging::after {
    width: 2px;
}

/* While dragging, the pointer owns the gesture: text selection and hover
   feedback elsewhere are only noise. */
body.bdt-dragging {
    user-select: none;
    cursor: col-resize;
}

/* ---------- toolbar: settings ---------- */

.bdt-toolbar-gap {
    flex: 1;
}

.bdt-hidden-note {
    font-size: .75rem;
    color: var(--bdt-muted);
}

.bdt-pop-anchor {
    position: relative;
}

.bdt-cog {
    all: unset;
    cursor: pointer;
    padding: .1rem .35rem;
    border-radius: .25rem;
    font-size: .9375rem;
    line-height: 1.2;
    color: var(--bdt-muted);
    transition: color .12s ease-in-out, background-color .12s ease-in-out;
}

.bdt-cog:hover,
.bdt-cog:focus-visible,
.bdt-cog.is-open {
    color: var(--bdt-accent);
    background: var(--bdt-hover);
}

.bdt-cog:focus-visible {
    outline: 2px solid rgba(27, 110, 194, .35);
    outline-offset: 1px;
}

/* ---------- column settings popover ---------- */

/* A popover rather than a modal: the user needs to see the table react behind
   it while they toggle columns. */
.bdt-pop {
    /* Fixed, with coordinates from JS, so the panel escapes whatever the host
       page wraps the table in. Absolute positioning put it at the mercy of every
       ancestor: a card with `overflow: hidden` — which is exactly what Tessera's
       cards use for their rounded corners — silently cut the panel off, and so
       would any scroll container. */
    position: fixed;
    top: 0;
    left: 0;
    z-index: 1080;
    width: 17rem;
    max-height: 24rem;
    display: flex;
    flex-direction: column;
    border: 1px solid var(--bdt-border-strong);
    border-radius: .5rem;
    background: #fff;
    box-shadow: 0 .5rem 1.5rem rgba(0, 0, 0, .12);
    font-size: .8125rem;
    color: var(--bdt-head);
}

.bdt-pop-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: .5rem .625rem;
    border-bottom: 1px solid var(--bdt-border);
}

.bdt-pop-close {
    all: unset;
    cursor: pointer;
    padding: 0 .25rem;
    color: var(--bdt-muted);
    font-size: 1rem;
    line-height: 1;
}

.bdt-pop-close:hover {
    color: #b02a37;
}

.bdt-pop-actions {
    display: flex;
    gap: .35rem;
    flex-wrap: wrap;
    padding: .5rem .625rem;
    border-bottom: 1px solid var(--bdt-border);
}

.bdt-pop-actions button {
    all: unset;
    cursor: pointer;
    padding: .15rem .45rem;
    border: 1px solid var(--bdt-border);
    border-radius: .25rem;
    font-size: .75rem;
    color: var(--bdt-head);
    background: var(--bdt-surface);
}

.bdt-pop-actions button:hover {
    border-color: var(--bdt-accent);
    color: var(--bdt-accent);
}

.bdt-pop-list {
    list-style: none;
    margin: 0;
    padding: .25rem;
    overflow-y: auto;
}

.bdt-pop-item {
    display: flex;
    align-items: center;
    gap: .35rem;
    padding: .15rem .35rem;
    border-radius: .25rem;
}

.bdt-pop-item:hover {
    background: var(--bdt-hover);
}

.bdt-pop-item label {
    display: flex;
    align-items: center;
    gap: .4rem;
    flex: 1;
    min-width: 0;
    margin: 0;
    cursor: pointer;
}

.bdt-pop-item label span {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* A hidden column stays listed but reads as switched off. */
.bdt-pop-item.is-hidden label span {
    color: var(--bdt-muted);
}

.bdt-pop-item input[type="checkbox"]:disabled {
    cursor: not-allowed;
}

.bdt-pop-item.is-hidden label {
    cursor: pointer;
}

.bdt-pop-move {
    display: inline-flex;
    gap: .1rem;
}

.bdt-pop-move button {
    all: unset;
    cursor: pointer;
    width: 1.1rem;
    text-align: center;
    border-radius: .2rem;
    color: var(--bdt-muted);
    font-size: .75rem;
}

.bdt-pop-move button:hover:not(:disabled) {
    color: var(--bdt-accent);
    background: #fff;
}

.bdt-pop-move button:disabled {
    opacity: .25;
    cursor: default;
}

/* ---------- saved views ---------- */

.bdt-pop-views {
    border-top: 1px solid var(--bdt-border);
    padding: .35rem .25rem .5rem;
}

.bdt-pop-subhead {
    padding: .25rem .375rem;
    font-size: .6875rem;
    font-weight: 600;
    letter-spacing: .05em;
    text-transform: uppercase;
    color: var(--bdt-muted);
}

.bdt-pop-none {
    margin: 0;
    padding: .1rem .375rem .35rem;
    font-size: .75rem;
    color: var(--bdt-muted);
}

.bdt-pop-list-flat {
    max-height: 9rem;
}

.bdt-pop-apply {
    all: unset;
    cursor: pointer;
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: var(--bdt-accent);
}

.bdt-pop-apply:hover {
    text-decoration: underline;
}

.bdt-pop-badge {
    font-size: .625rem;
    padding: 0 .3em;
    border-radius: 999px;
    background: var(--bdt-surface);
    border: 1px solid var(--bdt-border);
    color: var(--bdt-muted);
}

/* The author is what tells a shared view apart from your own — without it the
   two lists read as one. */
.bdt-pop-author {
    font-size: .6875rem;
    color: var(--bdt-muted);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    max-width: 6rem;
}

.bdt-pop-del {
    all: unset;
    cursor: pointer;
    padding: 0 .2rem;
    color: var(--bdt-muted);
    font-size: .875rem;
    line-height: 1;
}

.bdt-pop-del:hover {
    color: #b02a37;
}

.bdt-pop-save {
    display: flex;
    align-items: center;
    gap: .35rem;
    padding: .35rem .375rem 0;
}

.bdt-pop-save input[type="text"],
.bdt-pop-save input:not([type]) {
    flex: 1;
    min-width: 0;
    border: 1px solid var(--bdt-border);
    border-radius: .25rem;
    padding: .15rem .35rem;
    font-size: .75rem;
    background: var(--bdt-surface);
    color: var(--bdt-head);
}

.bdt-pop-save input:focus {
    outline: none;
    background: #fff;
    border-color: var(--bdt-accent);
}

.bdt-pop-save label {
    display: inline-flex;
    align-items: center;
    gap: .2rem;
    margin: 0;
    font-size: .6875rem;
    color: var(--bdt-muted);
    cursor: pointer;
    white-space: nowrap;
}

.bdt-pop-save button {
    all: unset;
    cursor: pointer;
    padding: .15rem .5rem;
    border: 1px solid var(--bdt-accent);
    border-radius: .25rem;
    font-size: .75rem;
    color: #fff;
    background: var(--bdt-accent);
}

.bdt-pop-save button:disabled {
    opacity: .4;
    cursor: default;
}


/* ---------- action-cell icons ---------- */

/* Row actions are icons, not labels: a table's trailing column is width the
   data wants back, and "Edit" next to a bare × read as two different kinds of
   control. Drawn with mask-image rather than background-image so the glyph
   takes the button's own colour — these buttons invert on hover, and a
   fixed-fill background image would stay dark against the filled state. */
.bdt-ico {
    display: inline-block;
    width: 1em;
    height: 1em;
    vertical-align: -.125em;
    background-color: currentColor;
    -webkit-mask-repeat: no-repeat;
    mask-repeat: no-repeat;
    -webkit-mask-position: center;
    mask-position: center;
    -webkit-mask-size: contain;
    mask-size: contain;
}

.bdt-ico-edit {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M12.146.146a.5.5 0 0 1 .708 0l3 3a.5.5 0 0 1 0 .708l-10 10a.5.5 0 0 1-.168.11l-5 2a.5.5 0 0 1-.65-.65l2-5a.5.5 0 0 1 .11-.168zM11.207 2.5 13.5 4.793 14.793 3.5 12.5 1.207zm1.586 3L10.5 3.207 4 9.707V10h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.293zm-9.761 5.175-.106.106-1.528 3.821 3.821-1.528.106-.106A.5.5 0 0 1 5 12.5V12h-.5a.5.5 0 0 1-.5-.5V11h-.5a.5.5 0 0 1-.468-.325'/%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M12.146.146a.5.5 0 0 1 .708 0l3 3a.5.5 0 0 1 0 .708l-10 10a.5.5 0 0 1-.168.11l-5 2a.5.5 0 0 1-.65-.65l2-5a.5.5 0 0 1 .11-.168zM11.207 2.5 13.5 4.793 14.793 3.5 12.5 1.207zm1.586 3L10.5 3.207 4 9.707V10h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.293zm-9.761 5.175-.106.106-1.528 3.821 3.821-1.528.106-.106A.5.5 0 0 1 5 12.5V12h-.5a.5.5 0 0 1-.5-.5V11h-.5a.5.5 0 0 1-.468-.325'/%3E%3C/svg%3E");
}

/* The action cell holds a row of icon buttons and must never wrap them: in an
   automatic layout the column is only as wide as the table can spare, and a
   second button then drops onto its own line and staggers down the row. */
.bdt-table .bdt-actions {
    white-space: nowrap;
}

/* ---- Display modes, grouping and tree ---- */

.bdt-modes {
    display: inline-flex;
    border: 1px solid var(--bs-border-color);
    border-radius: 0.25rem;
    overflow: hidden;
}

.bdt-mode {
    border: 0;
    background: transparent;
    padding: 0.1rem 0.6rem;
    font-size: 0.8rem;
}

.bdt-mode + .bdt-mode {
    border-left: 1px solid var(--bs-border-color);
}

.bdt-mode.is-active {
    background: var(--bs-primary);
    color: #fff;
}

/* Leading column holding the tree toggle and the nesting indent. */
.bdt-table .bdt-lead {
    padding-left: 0.25rem;
    padding-right: 0;
    white-space: nowrap;
    vertical-align: middle;
}

/* Indentation of nested and grouped rows, one 18px step per level. */
.bdt-indent {
    display: inline-block;
    width: calc(var(--bdt-depth, 0) * 18px);
}

.bdt-toggle {
    display: inline-block;
    width: 18px;
    text-align: center;
}

.bdt-toggle {
    border: 0;
    padding: 0;
    background: transparent;
    color: var(--bs-secondary-color);
    line-height: 1;
}

.bdt-toggle:hover {
    color: var(--bs-body-color);
}

.bdt-group-row > td {
    background: var(--bs-secondary-bg);
    font-weight: 600;
}

.bdt-group-count {
    margin-left: 0.5rem;
    font-weight: 400;
    color: var(--bs-secondary-color);
}

.bdt-child-row > td {
    background: var(--bs-tertiary-bg);
}

.bdt-pop-group {
    border: 1px solid var(--bs-border-color);
    border-radius: 0.2rem;
    background: transparent;
    font-size: 0.7rem;
    padding: 0 0.3rem;
    margin-right: 0.25rem;
    color: var(--bs-secondary-color);
}

.bdt-pop-group.is-grouped {
    border-color: var(--bs-primary);
    color: var(--bs-primary);
}
