/* ---- The grid contract (ARCHITECTURE.md §3.2) -------------------------------------------------
   One appearance for every grid on both sites. Pairs with CarvinGridPresentation.CustomizeElement,
   which assigns the class names below; the two are one contract and change together.

   THE MARKUP THIS EXPECTS is three nested elements, because a DxGrid cannot be styled from the
   outside without something to hang the rules on:

     <div class="carvin-grid-scroller">          horizontal overflow lives here, not on the page
       <div class="carvin-grid">                 the contract, and where --dxds-* is remapped
         <DxGrid CssClass="carvin-grid__control" CustomizeElement="..." />

   ONLY PUBLIC VENDOR API. Every variable below is a --dxds-* one, published by Fluent and
   documented. DevExpress's own class names (.dxbl-*) and private variables (--dxbl-*) appear
   nowhere, and must not: they are free to change in a patch release, and a rule that stops matching
   fails silently - the grid reverts to vendor chrome with nothing in the build to say so.

   WHY --dxds-* AT ALL, when the rules below already set colors: DevExpress draws chrome we never
   name - sort glyphs, the pager's buttons, the column chooser, the search box. Those read the
   design-system variables, so remapping them is the only way that furniture follows the theme.
   Without this block a dark page renders a white grid. */

.carvin-grid {
    /* Type */
    --dxds-font-family-sans-serif: var(--cv-font-sans);
    --dxds-font-size-base-sm: var(--cv-text-sm);
    --dxds-font-size-base-md: var(--cv-text-sm);

    /* Surfaces and the row states painted on them */
    --dxds-color-surface-neutral-default-rest: var(--cv-surface);
    --dxds-color-surface-neutral-default-hovered: var(--cv-row-hover);
    --dxds-color-surface-neutral-default-selected: var(--cv-row-selected);
    --dxds-color-surface-neutral-default-selected-hovered: var(--cv-row-hover);

    /* Content stays one color across all four states. Fluent dims text on hover, which on a row
       somebody is pointing at is the opposite of helpful. */
    --dxds-color-content-neutral-default-rest: var(--cv-text);
    --dxds-color-content-neutral-default-hovered: var(--cv-text);
    --dxds-color-content-neutral-default-selected: var(--cv-text);
    --dxds-color-content-neutral-default-selected-hovered: var(--cv-text);

    --dxds-color-border-neutral-default-rest: var(--cv-border);

    /* The horizontal rule between rows, named once. Softer than --cv-border: at 24px a full-strength
       line every row reads as a table of boxes rather than a list. */
    --cv-grid-rule: color-mix(in srgb, var(--cv-border) 78%, transparent);

    width: 100%;
    min-width: var(--cv-grid-min-width);
    overflow: visible;
    border: 0;
    background: var(--cv-surface);
    color: var(--cv-text);
    box-shadow: none;
    font-family: var(--cv-font-sans);
    font-size: var(--cv-text-sm);
    font-weight: var(--cv-weight-normal);
    line-height: var(--cv-leading);
}

/* Overflow belongs to the grid region. On the page body a wide grid scrolls the whole layout
   sideways - the heading and the toolbar leave the screen along with it. */
.carvin-grid-scroller {
    min-width: 0;
    overflow-x: auto;
    overflow-y: visible;
}

/* ---- Specificity --------------------------------------------------------------------------------
   The theme is registered before this file, so we win on order - but Fluent's own grid rules are
   more specific than a single class, and order only breaks ties at equal specificity.

   :is() takes the HIGHEST specificity of its arms, so pairing the class with an id lifts these
   rules to (1,1,0) while the class arm is what actually matches. #carvin-grid-anchor is never
   rendered and must never be: it exists only to be counted.

   Borrowed from Blueprint, which proved it necessary. If the plain class turns out to win here,
   delete the anchor rather than keeping a trick nobody needs. */

.carvin-grid:is(.carvin-grid, #carvin-grid-anchor) .carvin-grid__control {
    width: 100%;
    min-width: var(--cv-grid-min-width);
    border: 0;
    background: var(--cv-surface);
    box-shadow: none;
    font-family: var(--cv-font-sans);
    font-size: var(--cv-text-sm);
    line-height: var(--cv-leading);
}

/* ---- Header -------------------------------------------------------------------------------- */

.carvin-grid:is(.carvin-grid, #carvin-grid-anchor) .carvin-grid__header-row {
    height: var(--cv-header-height);
    min-height: var(--cv-header-height);
    background: var(--cv-surface);
}

.carvin-grid:is(.carvin-grid, #carvin-grid-anchor) .carvin-grid__header-cell {
    --dxds-color-content-neutral-default-rest: var(--cv-text-muted);

    box-sizing: border-box;
    height: var(--cv-header-height);
    min-height: var(--cv-header-height);
    padding: var(--cv-cell-pad-y) var(--cv-cell-pad-x);
    overflow: hidden;
    border: 0;
    border-bottom: 1px solid var(--cv-grid-rule);
    border-radius: 0;
    background: var(--cv-surface);
    color: var(--cv-text-muted);
    font-family: var(--cv-font-sans);
    font-size: var(--cv-text-xs);
    font-weight: var(--cv-weight-semibold);
    line-height: var(--cv-leading);
    text-align: left;
    vertical-align: middle;
    white-space: nowrap;
}

/* DevExpress adds unclassified filler cells when the visible columns do not fill the table, and
   CustomizeElement is never called for them - so the separator is applied to every direct child of
   the header row instead. Without this the rule stops at the last real column and the grid looks
   like it was cut off. */
.carvin-grid:is(.carvin-grid, #carvin-grid-anchor) .carvin-grid__header-row > *,
.carvin-grid:is(.carvin-grid, #carvin-grid-anchor) .carvin-grid__data-row
    > :last-child:not(.carvin-grid__data-cell):not(.carvin-grid__command-cell) {
    border-bottom: 1px solid var(--cv-grid-rule);
}

/* ---- Rows ------------------------------------------------------------------------------------
   Horizontal separators only. No vertical rules and no cell borders: columns are already separated
   by alignment and whitespace, and drawing both makes a spreadsheet out of a list. */

.carvin-grid:is(.carvin-grid, #carvin-grid-anchor) .carvin-grid__data-row {
    height: var(--cv-row-height);
    min-height: var(--cv-row-height);
    background: var(--cv-surface);
    color: var(--cv-text);
}

.carvin-grid:is(.carvin-grid, #carvin-grid-anchor) .carvin-grid__data-cell {
    box-sizing: border-box;
    height: var(--cv-row-height);
    min-height: var(--cv-row-height);
    max-height: var(--cv-row-height);
    padding: var(--cv-cell-pad-y) var(--cv-cell-pad-x);
    overflow: hidden;
    border: 0;
    border-bottom: 1px solid var(--cv-grid-rule);
    border-radius: 0;
    background: var(--cv-surface);
    color: var(--cv-text);
    font-family: var(--cv-font-sans);
    font-size: var(--cv-text-sm);
    font-weight: var(--cv-weight-normal);
    line-height: var(--cv-leading);
    text-overflow: ellipsis;
    vertical-align: middle;
    white-space: nowrap;
}

.carvin-grid:is(.carvin-grid, #carvin-grid-anchor) .carvin-grid__command-cell {
    box-sizing: border-box;
    height: var(--cv-row-height);
    min-height: var(--cv-row-height);
    max-height: var(--cv-row-height);
    padding-block: 0;
    border-bottom: 1px solid var(--cv-grid-rule);
    vertical-align: middle;
}

/* ---- Row states ------------------------------------------------------------------------------
   Painted on the CELLS. A row's background sits underneath its cells, so coloring the row alone is
   covered by every cell on top of it. */

.carvin-grid:is(.carvin-grid, #carvin-grid-anchor) .carvin-grid__data-cell.is-selected {
    background: var(--cv-row-selected);
}

.carvin-grid:is(.carvin-grid, #carvin-grid-anchor) .carvin-grid__data-row:hover .carvin-grid__data-cell,
.carvin-grid:is(.carvin-grid, #carvin-grid-anchor)
    .carvin-grid__data-row:hover
    .carvin-grid__data-cell.is-selected {
    background: var(--cv-row-hover);
}

/* Inset, so a focused first or last row is not clipped by the grid's own edge. */
.carvin-grid:is(.carvin-grid, #carvin-grid-anchor) .carvin-grid__data-row.is-focused {
    outline: 2px solid var(--cv-accent);
    outline-offset: -2px;
}

/* The column naming the record. CarvinGridPresentation decides which one; the screen names it. */
.carvin-grid:is(.carvin-grid, #carvin-grid-anchor) .carvin-grid__data-cell.is-accent {
    color: var(--cv-accent);
    font-weight: var(--cv-weight-semibold);
}

/* ---- Badges in cells -------------------------------------------------------------------------
   A badge carries its own padding and line-height, which at 24px is enough to push the row taller
   than every other grid's. Clamped here rather than in each screen's CSS, so one module cannot
   silently set the density for everybody. */
.carvin-grid:is(.carvin-grid, #carvin-grid-anchor) .carvin-badge {
    min-height: 18px;
    max-height: 18px;
    padding: 0 0.35rem;
    border-radius: var(--cv-radius-sm);
    font-size: var(--cv-text-xs);
    font-weight: var(--cv-weight-semibold);
    line-height: var(--cv-leading);
    vertical-align: top;
}

/* ---- Filter row ------------------------------------------------------------------------------
   Kept, unlike Blueprint's grids - they disable the vendor's filter UI because the application owns
   filter state, and we have no such state of our own. DevExpress's row IS our filtering. */

.carvin-grid:is(.carvin-grid, #carvin-grid-anchor) .carvin-grid__filter-row {
    min-height: var(--cv-control-height);
    background: var(--cv-surface);
}

.carvin-grid:is(.carvin-grid, #carvin-grid-anchor) .carvin-grid__filter-cell {
    min-height: var(--cv-control-height);
    padding: var(--cv-cell-pad-y) var(--cv-cell-pad-x);
    border: 0;
    border-bottom: 1px solid var(--cv-grid-rule);
    background: var(--cv-surface);
    color: var(--cv-text);
    font-family: var(--cv-font-sans);
    font-size: var(--cv-text-sm);
    line-height: var(--cv-leading);
}

/* ---- Pager ---------------------------------------------------------------------------------- */

.carvin-grid:is(.carvin-grid, #carvin-grid-anchor) .carvin-grid__pager {
    box-sizing: border-box;
    min-height: 34px;
    padding: var(--cv-space-1) var(--cv-space-2);
    align-items: center;
    border-top: 1px solid var(--cv-border);
    background: var(--cv-surface);
    color: var(--cv-text);
    font-family: var(--cv-font-sans);
    font-size: var(--cv-text-sm);
    font-weight: var(--cv-weight-normal);
    line-height: var(--cv-leading);
}

.carvin-grid:is(.carvin-grid, #carvin-grid-anchor) .carvin-grid__pager > * {
    margin-bottom: 0;
}

/* Set by CustomizeElement when the grid has no visible rows. Hiding the container takes the page
   navigation, the size selector, the summary AND the reserved height with it - "Page 1 of 1, 0
   items" under a message that already said the grid is empty. */
.carvin-grid:is(.carvin-grid, #carvin-grid-anchor) .carvin-grid__pager.is-empty {
    display: none;
}

/* ---- Empty state and column chooser ---------------------------------------------------------- */

.carvin-grid:is(.carvin-grid, #carvin-grid-anchor) .carvin-grid__empty-area {
    background: var(--cv-surface);
    color: var(--cv-text-soft);
    font-family: var(--cv-font-sans);
    font-size: var(--cv-text-sm);
}

/* For an <EmptyDataAreaTemplate>: a bold line saying what is missing, then one saying what to do. */
.carvin-grid:is(.carvin-grid, #carvin-grid-anchor) .carvin-grid__empty-content {
    display: grid;
    gap: var(--cv-space-1);
    justify-items: center;
    padding: var(--cv-space-4);
    color: var(--cv-text-soft);
    text-align: center;
}

.carvin-grid:is(.carvin-grid, #carvin-grid-anchor) .carvin-grid__empty-content strong {
    color: var(--cv-text);
}

/* Rendered in a popup outside .carvin-grid, so it is scoped by its own class alone. */
.carvin-grid__chooser-item {
    min-height: var(--cv-control-height);
    color: var(--cv-text);
    font-family: var(--cv-font-sans);
    font-size: var(--cv-text-sm);
    line-height: var(--cv-leading);
}

/* ---- Roomier ---------------------------------------------------------------------------------
   For the applicant portal. Same treatment - same colors, same separators, same quiet header - at
   a height somebody reads once on a phone rather than works in all day.

   Height only. There is no minimum width to undo here: --cv-grid-min-width is 0 for every grid,
   for the reason carvin-tokens.css records. */

.carvin-grid--roomy {
    --cv-row-height: 34px;
    --cv-header-height: 36px;
    --cv-cell-pad-y: 6px;

    font-size: var(--cv-text-base);
}

.carvin-grid--roomy:is(.carvin-grid, #carvin-grid-anchor) .carvin-grid__data-cell {
    font-size: var(--cv-text-base);
    white-space: normal;
}

/* ---- Action cells ------------------------------------------------------------------------------
   A cell holding two links ran them together as one: "Resend inviteDeactivate". The buttons are
   inline with no padding, and Razor emits no whitespace between elements for a browser to collapse
   into a space - so the gap has to be stated rather than assumed. Wrapping rather than overflowing,
   because an action column is the first thing a narrow window squeezes. */

.carvin-grid__actions {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 0.25rem 0.9rem;
}

/* ---- Forced colors ---------------------------------------------------------------------------
   Windows high-contrast replaces our palette wholesale. Separators drawn with color-mix disappear
   entirely, so they are restated in system colors - otherwise the grid becomes one undifferentiated
   block of text for the readers who most need the structure. */

@media (forced-colors: active) {
    .carvin-grid:is(.carvin-grid, #carvin-grid-anchor) .carvin-grid__header-cell,
    .carvin-grid:is(.carvin-grid, #carvin-grid-anchor) .carvin-grid__data-cell,
    .carvin-grid:is(.carvin-grid, #carvin-grid-anchor) .carvin-grid__command-cell,
    .carvin-grid:is(.carvin-grid, #carvin-grid-anchor) .carvin-grid__filter-cell,
    .carvin-grid:is(.carvin-grid, #carvin-grid-anchor) .carvin-grid__pager,
    .carvin-grid__chooser-item {
        border-color: CanvasText;
    }

    .carvin-grid:is(.carvin-grid, #carvin-grid-anchor) .carvin-grid__data-cell.is-selected {
        border-color: Highlight;
        background: Highlight;
        color: HighlightText;
    }

    .carvin-grid:is(.carvin-grid, #carvin-grid-anchor) .carvin-grid__data-row.is-focused {
        outline-color: Highlight;
    }

    .carvin-grid:is(.carvin-grid, #carvin-grid-anchor) .carvin-badge {
        border: 1px solid CanvasText;
        background: Canvas;
        color: CanvasText;
    }
}
