/* Presentation for the shared Tabulator grid (`x-platform::tabulator`, driven by the `data-table`
   Stimulus controller). One stylesheet for the ONE list grid every module reuses, so the look is
   consistent across documents, companies, counterparties, users, groups and any future list
   (coding-standards §3). Renders inside the shell content frame in either mode; token-driven so a host
   re-skins without touching markup (§4, §12).

   NOTE: the vendored `tabulator.min.css` is Tabulator's BASE theme, which hardcodes its colours/padding
   (grey #e6e6e6 headers, #999 borders, 4px cells) and does NOT read `--tabulator-*` custom properties —
   so we refine the grid by overriding its real classes here, scoped to `.platform-grid`, mapped to the
   design tokens. This sheet loads after tabulator.min.css, so ties in specificity resolve our way.

   BOOTSTRAP-CONSISTENCY (M-045b): with Bootstrap 5.3 vendored (M-045a), this override layer is tuned to
   Bootstrap's `.table` conventions so the grid reads like the rest of the Bootstrap-based UI — 0.5rem
   cell padding, 1px horizontal row dividers in the border colour (no vertical cell rules), a light
   `.table-light`-style header, a subtle row hover, all wrapped in a rounded bordered container for a
   `.card`/`.table`-in-a-card feel. We keep the `.platform-*` token vocabulary rather than reading
   `--bs-*` directly: the Bootstrap variables the grid would want (`--bs-border-color`, `--bs-body-bg`,
   `--bs-table-*`) already map to these same `--platform-*` tokens (bootstrap-theme.css), so one
   vocabulary stays DRY, the fallbacks keep meaning, and the whole grid still flips with `data-theme`. */

/* ---- Root container ----------------------------------------------------- */
/* Phone-width containment: the grid element is capped at 100% of its column and clips its own overflow,
   so a grid can never widen the page body. The `data-table` controller runs Tabulator with
   `layout: "fitColumns"` + `responsiveLayout: "collapse"`, so columns already shrink/collapse to fit the
   viewport (they don't overflow); any horizontal scroll a future wide layout needed would live inside
   Tabulator's own `.tabulator-tableholder`, never on the page. `max-width: 100%` is the guard that keeps
   that promise regardless of layout mode. */
.platform-grid.tabulator {
    border: 1px solid var(--platform-color-border, #cfd8dc);
    border-radius: var(--platform-radius-md, 0.375rem);
    overflow: hidden;
    max-width: 100%;
    background: var(--platform-color-surface, #ffffff);
    color: var(--platform-color-text, #2c3e50);
    font-size: var(--platform-font-size-sm, 0.875rem);

    /* Inset the table from its own border, so the grid reads like the app's other content boxes instead of a
       table jammed into a frame: header, rows and footer all ran flush into the edge. HALF a card's padding —
       a grid brings its own internal structure (its rows are already spaced) and its width is the point, so a
       prose-sized margin would only take room away from the columns. Expressed as a fraction of the card's
       padding rather than a token of its own, so it stays half by construction if the scale is retuned. */
    padding: calc(var(--platform-space-lg, 1.5rem) / 2);
}

/* ---- Inside a card (M-207) ---------------------------------------------- */
/* A grid inside ANY card must not draw its own box: the card already provides the border, radius and surface,
   so the grid's own would double up into a border-in-a-border and a surface-on-surface. The card is the box.

   Keyed off `.platform-card` itself, NOT off the flush body it used to be scoped to. That scoping quietly
   coupled "the grid is borderless" to "the card has no padding", so the moment a grid card was given an inset
   the grid's border came back and framed a second box inside the first. Those are two independent decisions:
   whether the card insets its content, and whether the content draws its own edge. A grid in a card never
   does — at any padding. A STANDALONE grid (not in a card) still keeps its own box and is unchanged. */
.platform-card .platform-grid.tabulator {
    border: 0;
    border-radius: 0;
    background: transparent;
}

/* ---- Header ------------------------------------------------------------- */
/* The header is the grid's one TINTED block, and once the grid gained its inset (above) the tint stopped
   being clipped by the box's own rounded corners — it became a floating strip with four square corners inside
   a rounded box, which is exactly the mismatch that reads as unfinished. It carries the same radius as the
   box, the cards and the badges, so the grid is made of the same shapes as everything around it.

   The bottom edge stays SQUARE: that border is the header/body divider, a rule that must run the full width
   of the table and meet the rows beneath it. Curling its ends away from the columns they separate would be
   decoration fighting the thing the line is for. Round where the strip is free, square where it joins. */
.platform-grid .tabulator-header {
    background: var(--platform-color-surface-muted, #ecf0f1);
    border-bottom: 1px solid var(--platform-color-border, #cfd8dc);
    border-radius: var(--platform-radius-md, 0.375rem) var(--platform-radius-md, 0.375rem) 0 0;
    color: var(--platform-color-text-muted, #7f8c8d);
    font-weight: 600;
}

/* Header cells: transparent so the header's `--platform-color-surface-muted` shows through (and thus
   flips with the palette), and borderless to match the body cells. The `.tabulator-header` in the
   selector is REQUIRED, not cosmetic: Tabulator's base theme hardcodes
   `.tabulator .tabulator-header .tabulator-col { background:#e6e6e6; border-right:1px solid #aaa }`
   (a 3-class selector). A 2-class `.platform-grid .tabulator-col` loses on specificity, so that hardcoded
   light grey leaked through on every grid — invisible in light mode (≈ surface-muted) but a pale stripe
   across the header in dark. Adding `.tabulator-header` ties the specificity, and since this sheet loads
   after the base one we win the tie — so the header cell reads the token in both themes. */
.platform-grid .tabulator-header .tabulator-col {
    background: transparent;
    border-right: 0;
}

.platform-grid .tabulator-col .tabulator-col-content {
    padding: 0.5rem;
}

.platform-grid .tabulator-col .tabulator-col-title {
    font-weight: 600;
    color: var(--platform-color-text-muted, #7f8c8d);
    letter-spacing: 0.01em;
}

/* Sort arrows: muted when idle, accent-tinted on the sorted column. Tabulator draws the arrow as a CSS
   triangle (border trick) — an up-pointing triangle uses border-bottom, a down one border-top. */
.platform-grid .tabulator-col .tabulator-arrow {
    border-bottom-color: var(--platform-color-border, #cfd8dc);
}

.platform-grid .tabulator-col[aria-sort="ascending"] .tabulator-arrow {
    border-bottom-color: var(--platform-color-accent, #16a085);
}

.platform-grid .tabulator-col[aria-sort="descending"] .tabulator-arrow {
    border-top-color: var(--platform-color-accent, #16a085);
}

/* Sortable-header hover: Tabulator's base theme hardcodes a light grey with a HIGH-specificity selector —
   `.tabulator .tabulator-header .tabulator-col.tabulator-sortable.tabulator-col-sorter-element:hover
   { background-color:#cdcdcd }` (0,6,0 + :hover). A `.platform-grid`-scoped rule at (0,7,0) out-specifies
   it (and, loading after, wins any tie) so the hover reads an accent-surface token — a subtle themed
   highlight that flips with the palette instead of flashing that fixed grey in dark. */
.platform-grid.tabulator .tabulator-header
    .tabulator-col.tabulator-sortable.tabulator-col-sorter-element:hover {
    background-color: var(--platform-color-accent-surface, #d1f2eb);
}

/* ---- Header filter row (per-column inputs / selects / ranges) ----------- */
.platform-grid .tabulator-header-filter input,
.platform-grid .tabulator-header-filter select {
    width: 100%;
    height: var(--platform-input-height, 1.9rem);
    box-sizing: border-box;
    padding: 0 0.4rem;
    font: inherit;
    font-size: var(--platform-font-size-sm, 0.875rem);
    color: var(--platform-color-text, #2c3e50);
    background: var(--platform-color-surface, #ffffff);
    border: 1px solid var(--platform-color-border, #cfd8dc);
    border-radius: var(--platform-radius-sm, 0.25rem);
}

.platform-grid .tabulator-header-filter input:focus,
.platform-grid .tabulator-header-filter select:focus {
    outline: none;
    border-color: var(--platform-color-accent, #16a085);
    box-shadow: 0 0 0 2px var(--platform-color-accent-surface, #d1f2eb);
}

/* A free-text filter with a value gets the same accent-tinted "active" look as a filled select/range
   button (the placeholder set by the controller is what makes `:placeholder-shown` meaningful). */
.platform-grid .tabulator-header-filter input:not(:placeholder-shown) {
    color: var(--platform-color-accent, #16a085);
    border-color: var(--platform-color-accent, #16a085);
    background: var(--platform-color-accent-surface, #d1f2eb);
    font-weight: 600;
}

/* A range filter (amounts / dates) is a compact header button — a funnel that shows the active bound(s)
   — which opens a small modal (DialogHelper.rangeFilter) instead of cramming two inputs into the header
   (the old inline from/to was too bulky). Full width of its cell, truncates a long summary. */
.platform-grid__filter-btn {
    display: flex;
    align-items: center;
    gap: 0.3rem;
    width: 100%;
    height: var(--platform-input-height, 1.9rem);
    box-sizing: border-box;
    padding: 0 0.4rem;
    font: inherit;
    font-size: var(--platform-font-size-sm, 0.875rem);
    text-align: left;
    color: var(--platform-color-text-muted, #7f8c8d);
    background: var(--platform-color-surface, #ffffff);
    border: 1px solid var(--platform-color-border, #cfd8dc);
    border-radius: var(--platform-radius-sm, 0.25rem);
    cursor: pointer;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}

.platform-grid__filter-btn::before {
    content: "";
    flex: none;
    width: 0.85em;
    height: 0.85em;
    background-color: currentColor;
    -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolygon points='22 3 2 3 10 12.46 10 19 14 21 14 12.46 22 3'/%3E%3C/svg%3E") center / contain no-repeat;
    mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolygon points='22 3 2 3 10 12.46 10 19 14 21 14 12.46 22 3'/%3E%3C/svg%3E") center / contain no-repeat;
}

.platform-grid__filter-btn:hover {
    border-color: var(--platform-color-accent, #16a085);
}

/* Active state — a value/bound is set: accent-tinted so the column reads as filtered. */
.platform-grid__filter-btn--active {
    color: var(--platform-color-accent, #16a085);
    border-color: var(--platform-color-accent, #16a085);
    background: var(--platform-color-accent-surface, #d1f2eb);
    font-weight: 600;
}

/* The filter popover — a small panel anchored under the header button (appended to <body>, so the grid's
   rounded overflow never clips it). Holds the searchable SlimSelect control (select) or from/to fields
   (range). `.platform-grid` scoping is unnecessary here since it lives on <body>. */
.platform-grid__filter-pop {
    z-index: 100;
    min-width: 11rem;
    max-width: 22rem;
    padding: 0.35rem;
    font-size: var(--platform-font-size-sm, 0.875rem);
    color: var(--platform-color-text, #2c3e50);
    background: var(--platform-color-surface, #ffffff);
    border: 1px solid var(--platform-color-border, #cfd8dc);
    border-radius: var(--platform-radius-md, 0.375rem);
    box-shadow: var(--platform-shadow-md, 0 4px 14px rgba(44, 62, 80, 0.14));
}

/* Range (from/to) body. */
.platform-grid__filter-range {
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
}

.platform-grid__filter-field {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
}

.platform-grid__filter-field span {
    font-size: var(--platform-font-size-sm, 0.875rem);
    color: var(--platform-color-text-muted, #7f8c8d);
}

.platform-grid__filter-actions {
    display: flex;
    justify-content: flex-end;
    gap: 0.35rem;
    margin-top: 0.15rem;
}

/* ---- Rows & cells ------------------------------------------------------- */
/* Bootstrap `.table` draws horizontal row dividers in the BORDER colour (`--bs-table-border-color`,
   which maps to `--platform-color-border`) and no vertical cell rules — so rows use the border token
   (not the lighter surface-muted) for that crisp Bootstrap divider, and cells drop their right border. */
.platform-grid .tabulator-row {
    background: var(--platform-color-surface, #ffffff);
    border-bottom: 1px solid var(--platform-color-border, #cfd8dc);
}

/* Zebra striping: every even row is nudged a fraction of the way from the surface toward the muted surface
   — a *little* tint (35% of the way), well short of the full surface-muted the hover state uses, so the two
   never read the same and the stripe stays subtle. `color-mix` derives it from the existing theme tokens, so
   it adapts to every palette (light themes darken slightly, dark themes lighten) with no per-theme value and
   no new token; a browser without `color-mix` simply ignores the rule and the row keeps its base surface. */
.platform-grid .tabulator-row.tabulator-row-even {
    background: color-mix(in srgb, var(--platform-color-surface, #ffffff) 65%, var(--platform-color-surface-muted, #ecf0f1));
}

.platform-grid .tabulator-row:hover,
.platform-grid .tabulator-row.tabulator-selectable:hover {
    background: var(--platform-color-surface-muted, #ecf0f1);
}

.platform-grid .tabulator-cell {
    padding: 0.5rem;
    border-right: 0;
    color: var(--platform-color-text, #2c3e50);
}

/* ---- Responsive collapse (narrow-viewport per-row field/value block) ---- */
/* With `responsiveLayout: "collapse"`, once the viewport is too narrow Tabulator folds the overflow
   columns into a per-row block rendered as a plain `<table>` of field-name / value pairs:
   `<div class="tabulator-responsive-collapse"><table><tr><td><strong>Field</strong></td><td>value</td></tr>…`.
   The base theme leaves that text at its vendored default (dark #333) — readable in light, invisible on
   dark, and never flips with `data-theme`. Theme both cells with our tokens so the collapse reads like the
   rest of the grid in either mode. Scoped under `.platform-grid` so no other Tabulator instance is touched.

   Ordering/specificity: the general value `td` rule comes FIRST; the field-name `td:first-of-type` rule
   follows and also out-specifies it (`:first-of-type` adds a pseudo-class, lifting (0,2,1) → (0,3,1)), so
   the label ends up accent (like `.platform-grid__link`) and the value ends up text (like `.tabulator-cell`).
   Colour only — the native `<strong>` keeps the label bold. */
.platform-grid .tabulator-responsive-collapse td {
    color: var(--platform-color-text, #2c3e50);
    overflow-wrap: anywhere;
}

.platform-grid .tabulator-responsive-collapse td:first-of-type,
.platform-grid .tabulator-responsive-collapse td:first-of-type strong {
    color: var(--platform-color-accent, #16a085);
}

/* Tabulator sizes that table from its content, so a cell holding a form control (an `editDate` editor collapses
   WITH its column — Tabulator runs the column formatter for collapsed cells) makes the row wider than the grid and
   the page scrolls sideways at phone width (§12, M-223). Pin it to the row and let the fixed layout decide the two
   columns: label a third and wrapping, value the rest. */
.platform-grid .tabulator-responsive-collapse table {
    width: 100%;
    table-layout: fixed;
}

.platform-grid .tabulator-responsive-collapse td:first-of-type {
    width: 33%;
}

/* ---- Empty state -------------------------------------------------------- */
.platform-grid .tabulator-placeholder .tabulator-placeholder-contents {
    color: var(--platform-color-text-muted, #7f8c8d);
    font-weight: 400;
}

/* ---- Loading / error overlay (Tabulator's ajax "alert" pane) ------------- */
.platform-grid .tabulator-alert {
    background: var(--platform-color-overlay, rgba(255, 255, 255, 0.66));
}

.platform-grid .tabulator-alert .tabulator-alert-msg {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.55rem 1rem;
    font-size: var(--platform-font-size-sm, 0.875rem);
    font-weight: 500;
    background: var(--platform-color-surface, #ffffff);
    border-radius: var(--platform-radius-md, 0.375rem);
    box-shadow: var(--platform-shadow-md, 0 4px 14px rgba(44, 62, 80, 0.14));
}

/* Border + colour live on the state-specific selectors so they out-specify Tabulator's base state rules
   (which put a heavy 4px #333 / #d00 border there). */
.platform-grid .tabulator-alert .tabulator-alert-msg.tabulator-alert-state-msg {
    color: var(--platform-color-text-muted, #7f8c8d);
    border: 1px solid var(--platform-color-border, #cfd8dc);
}

.platform-grid .tabulator-alert .tabulator-alert-msg.tabulator-alert-state-error {
    color: var(--platform-color-error-text, #c0392b);
    border: 1px solid var(--platform-color-error, #c0392b);
}

/* A small accent spinner precedes the loading message. */
.platform-grid .tabulator-alert .tabulator-alert-msg.tabulator-alert-state-msg::before {
    content: "";
    width: 1em;
    height: 1em;
    border: 2px solid var(--platform-color-accent-surface, #d1f2eb);
    border-top-color: var(--platform-color-accent, #16a085);
    border-radius: 50%;
    animation: platform-grid-spin 0.6s linear infinite;
}

@keyframes platform-grid-spin {
    to {
        transform: rotate(360deg);
    }
}

/* ---- Footer / pagination (centred, refined) ----------------------------- */
.platform-grid .tabulator-footer {
    background: var(--platform-color-surface, #ffffff);
    border-top: 1px solid var(--platform-color-border, #cfd8dc);
    color: var(--platform-color-text-muted, #7f8c8d);
    font-weight: 400;
    padding: 0.4rem;
    /* Establish an inline-size container so the footer's OWN width — not the viewport — decides when the
       counter + pager stack (M-082): the grid can be narrow on a wide desktop when the side nav is open. */
    container-type: inline-size;
}

/* Footer layout (M-082): WIDE state — the row-counter and the pager share ONE row, counter left, pager
   right. The narrow two-row stack is handled by the container query below, NOT by flex-wrap: flex-wrap
   alone can't do it here, because a short counter + the pager "fit" side by side, so the pager wraps its
   own BUTTONS internally (growing tall and overlapping the counter) instead of dropping to a second row. */
.platform-grid .tabulator-footer .tabulator-footer-contents {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
}

.platform-grid .tabulator-page-counter {
    flex: 0 1 auto;
    margin: 0;
    white-space: nowrap;
}

.platform-grid .tabulator-paginator {
    display: inline-flex;
    flex: 0 0 auto;
    flex-wrap: wrap;
    align-items: center;
    justify-content: flex-end;
    gap: 0.15rem;
    width: auto;
    max-width: 100%;
}

/* Tabulator's base theme hardcodes `.tabulator-footer .tabulator-paginator { color:#555 }` (0,2,0), which
   leaks onto the "Page Size" label so it reads a different grey from the "Showing X of Y" counter (that one
   sits outside the paginator and correctly inherits the footer's muted token). Re-scope the paginator text to
   the SAME token — `.tabulator-footer` raises us to (0,3,0) to beat the base — so both footer labels match.
   The page BUTTONS set their own `color` (above) and are unaffected. */
.platform-grid .tabulator-footer .tabulator-paginator {
    color: var(--platform-color-text-muted, #7f8c8d);
}

/* Narrow state (M-082): once the FOOTER itself is too narrow for the counter + pager to sit side by side,
   switch the contents to a column so the WHOLE pager drops onto its own row — counter row 1, pager row 2,
   each full width — the only reliable way to stop the pager wrapping its buttons up into the counter. A
   container query keys this off the footer's width (not the viewport), so it also triggers when the side
   nav squeezes an otherwise-wide grid. Threshold tuned to flip just before the two would collide; the wide
   layout above is unchanged past it. */
@container (max-width: 34rem) {
    .platform-grid .tabulator-footer .tabulator-footer-contents {
        flex-direction: column;
        align-items: flex-start;
        gap: var(--platform-space-xs, 0.25rem);
    }

    .platform-grid .tabulator-footer-contents .tabulator-page-counter,
    .platform-grid .tabulator-footer-contents .tabulator-paginator {
        width: 100%;
        max-width: 100%;
    }

    .platform-grid .tabulator-footer-contents .tabulator-paginator {
        justify-content: flex-start;
    }
}

/* Every pager control (First/Prev/Next/Last + the page numbers) reads like the ONE theme button:
   same transparent bg / border / weight the `.platform-btn` system uses, so the pager is visibly
   part of the button family (M-055). `inline-flex` + `min-width` = `height` makes a single-digit
   page number a SQUARE chip; multi-digit numbers and the worded nav buttons widen from their
   content past that floor. */
.platform-grid .tabulator-page {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    box-sizing: border-box;
    min-width: var(--platform-input-height, 1.9rem);
    height: var(--platform-input-height, 1.9rem);
    margin: 0 2px;
    padding: 0 0.5rem;
    font: inherit;
    font-size: var(--platform-font-size-sm, 0.875rem);
    font-weight: 600;
    color: var(--platform-color-text, #2c3e50);
    background: transparent;
    border: 1px solid var(--platform-color-border, #cfd8dc);
    border-radius: var(--platform-radius-sm, 0.25rem);
}

.platform-grid .tabulator-page:not(.active):not(:disabled):hover {
    background: var(--platform-color-surface-muted, #ecf0f1);
    border-color: var(--platform-color-accent, #16a085);
    color: var(--platform-color-text, #2c3e50);
}

/* Active page = a filled-accent square with a WHITE number. The `.tabulator-footer` scope raises this
   to (0,4,0) so it matches AND (loading after) beats Tabulator's base theme, which hardcodes
   `.tabulator .tabulator-footer .tabulator-page.active { color:#d00 }` (0,4,0) — the sole reason the
   active number rendered red. Everything stays on `--platform-*` tokens (light + dark). */
.platform-grid .tabulator-footer .tabulator-page.active {
    background: var(--platform-color-accent, #16a085);
    border-color: var(--platform-color-accent, #16a085);
    color: var(--platform-color-on-accent, #ffffff);
}

.platform-grid .tabulator-page:disabled {
    opacity: 0.5;
}

.platform-grid .tabulator-page-size {
    padding: 0.2rem 0.4rem;
    font: inherit;
    font-size: var(--platform-font-size-sm, 0.875rem);
    color: var(--platform-color-text, #2c3e50);
    background: var(--platform-color-surface, #ffffff);
    border: 1px solid var(--platform-color-border, #cfd8dc);
    border-radius: var(--platform-radius-sm, 0.25rem);
}

/* ---- Cell affordances (links + the trailing row-action icons) ----------- */
.platform-grid__link {
    color: var(--platform-color-accent, #16a085);
    text-decoration: none;
}

.platform-grid__link:hover {
    text-decoration: underline;
}

.platform-grid__actions {
    display: flex;
    flex-wrap: nowrap;
    gap: 0.35em;
    align-items: center;
}

/* The inline editor of an `editDate` column (data_table_controller.js `editDateCell()`) — a real date field
   living in the row, so a value that is meant to be CHANGED from the list looks changeable instead of hiding
   behind a detail page. It keeps the shared `.platform-form__input` skin (one field look in the whole app) and
   only trims itself to a table cell: field plus its ✓ commit control on one line, tighter padding, the grid's own
   type scale. Both are disabled while a commit is in flight, so a second commit cannot race the first. */
.platform-grid__edit-cell {
    display: flex;
    align-items: center;
    gap: 0.25rem;
    min-width: 0;
}

.platform-grid__edit {
    flex: 1 1 auto;
    min-width: 0;
    padding: 0.15rem 0.4rem;
    font-size: var(--platform-font-size-sm, 0.875rem);
}

.platform-grid__edit:disabled {
    opacity: 0.6;
    cursor: progress;
}

/* A commit the field itself could not parse (a half-entered date). The refusal is marked on the ELEMENT, not only
   in a toast, so the feedback is where the user is looking and cannot be missed or dismissed. Cleared as soon as
   the value changes again. */
.platform-grid__edit--invalid {
    border-color: var(--platform-color-error, #c0392b);
    background: var(--platform-color-error-surface, #fdeceb);
}

/* The ✓ that COMMITS the edit — this grid never auto-saves one (see editDateCell()). It appears only once the
   field differs from the stored value, so an untouched row carries no button at all: the affordance shows up
   exactly when there is something to confirm. `hidden` must win over the button's own display. */
.platform-grid__edit-confirm {
    flex: none;
}

.platform-grid__edit-confirm[hidden] {
    display: none;
}

/* TOUCH (M-223): on a phone the ✓ is the ONLY way to commit — a native date picker has no Enter key — so it must be
   a real target, not the 1.7em glyph a mouse is happy with (~24px, barely half the 44px minimum). Raise BOTH controls
   of the cell to the 44×44 CSS-px tap-target token on coarse pointers only, so the desktop row height is untouched;
   `hover: none` keeps a hybrid laptop with a touchscreen out of it. The floor is set with `min-*` on purpose: it beats
   `.platform-btn--icon`'s `height/width: 1.7em` in the box-sizing rules whatever the two sheets' cascade order says,
   so the target cannot be silently lost by a stylesheet re-order. The field grows with the button because a finger
   has to hit that too, and a taller row is what a phone wants anyway. */
@media (hover: none) and (pointer: coarse) {
    .platform-grid__edit-cell {
        gap: var(--platform-space-sm, 0.5rem);
    }

    .platform-grid__edit {
        min-height: var(--platform-tap-target, 2.75rem);
    }

    .platform-grid__edit-confirm {
        min-width: var(--platform-tap-target, 2.75rem);
        min-height: var(--platform-tap-target, 2.75rem);
    }
}

/* Status / lifecycle / tag pill — a small token-driven chip whose tone comes from a semantic variant
   (ok / muted / danger), so light↔dark is a token switch and every surface gets one consistent pill.
   Promoted to the platform layer (G1) so the grid's `badge` column, each module's status/lifecycle pill
   and free-form tag chips all share ONE shape instead of copy-pasting it (coding-standards §3). The grid
   keeps its `.platform-grid__badge` name — the Tabulator formatter in data_table_controller.js emits it —
   as an alias of the base. The pill radius is a fixed shape token, not a theme colour. */
.platform-badge,
.platform-grid__badge,
.platform-grid__chip--group,
.platform-grid__chip--danger {
    display: inline-block;
    padding: 0.15rem 0.55rem;
    border-radius: var(--platform-radius-pill, 999px);
    font-size: var(--platform-font-size-xs, 0.75rem);
    font-weight: 600;
    line-height: 1.4;
    white-space: nowrap;
    color: var(--platform-color-text, #2c3e50);
    background: var(--platform-color-surface-muted, #ecf0f1);
}

.platform-badge--ok,
.platform-grid__badge--ok {
    color: var(--platform-color-on-accent, #ffffff);
    background: var(--platform-color-ok, #27ae60);
}

.platform-badge--muted,
.platform-grid__badge--muted {
    color: var(--platform-color-text, #2c3e50);
    background: var(--platform-color-surface-muted, #ecf0f1);
}

.platform-badge--danger,
.platform-grid__badge--danger,
.platform-grid__chip--danger {
    color: var(--platform-color-on-accent, #ffffff);
    background: var(--platform-color-error, #c0392b);
}

/* ── Multi-part cell: the grid's `chips` column (data_table_controller.js `chipsCell()`) ──────────
   One cell that says several things of DIFFERENT kinds — e.g. the contracts reminder overview's Recipients
   cell, where a responsible GROUP is a pill (it stands for people you cannot see) and a responsible PERSON is
   just their name. Without the cue the two are told apart only by naming convention ("Legal" vs "Jan Novák"),
   which is not a cue at all. Parts wrap rather than overflow a narrow column. Token-driven (§12). */
.platform-grid__chips {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.35em;
    min-width: 0;
}

.platform-grid__chip {
    white-space: nowrap;
}

/* A group: an accent-tinted pill carrying a people glyph — "this is a box of humans", not a human. The glyph
   is an inline SVG data-URI painted in `currentColor` via a mask, exactly as the icon buttons do. */
.platform-grid__chip--group {
    --platform-chip-group-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2'/%3E%3Ccircle cx='9' cy='7' r='4'/%3E%3Cpath d='M23 21v-2a4 4 0 0 0-3-3.87'/%3E%3Cpath d='M16 3.13a4 4 0 0 1 0 7.75'/%3E%3C/svg%3E");

    display: inline-flex;
    align-items: center;
    gap: 0.3em;
    color: var(--platform-color-text, #2c3e50);
    background: var(--platform-color-accent-surface, #d1f2eb);
}

.platform-grid__chip--group::before {
    content: "";
    flex: none;
    width: 0.9em;
    height: 0.9em;
    background-color: currentColor;
    -webkit-mask: var(--platform-chip-group-icon) center / contain no-repeat;
    mask: var(--platform-chip-group-icon) center / contain no-repeat;
}

/* The head-count tail ("· 3 people") — quiet, and marked as a UNIT so the number cannot be misread as a count
   of the names printed before it. The separator is decoration, not prose, so it lives here and not in a
   translation string. */
.platform-grid__chip--count {
    color: var(--platform-color-text-muted, #7f8c8d);
    font-size: var(--platform-font-size-xs, 0.75rem);
}

.platform-grid__chip--count::before {
    content: "·";
    margin-right: 0.35em;
}

/* Tag chips wrap onto the next line instead of forcing a single line — the neutral pill minus nowrap. */
.platform-badge--wrap {
    white-space: normal;
}

/* A wrapping row of pill chips (e.g. a contract's tags) — flex, wraps, no list bullets. Pairs with
   `.platform-badge` chips inside it. */
.platform-chip-row {
    display: flex;
    flex-wrap: wrap;
    gap: var(--platform-space-sm, 0.5rem);
    margin: 0 0 var(--platform-space-md, 1rem);
    padding: 0;
    list-style: none;
}

/* ── Hand-rolled data table (M-184) ──────────────────────────────────────────────────────────────
   A semantic `<table>` styled to READ like the shared Tabulator grid above (muted header, 0.5rem cells,
   1px row dividers in the border token, a subtle row hover, all wrapped in a rounded bordered container)
   — WITHOUT the Tabulator machinery, for surfaces that need inline editing / drag ordering the grid
   can't host (e.g. the lookup editor). Promoted to the platform layer so any future hand-rolled admin
   table reuses ONE look instead of copy-pasting the grid's styling (coding-standards §3). Token-driven,
   so light↔dark is a token switch, and the wrapper scrolls on a narrow viewport rather than widening the
   page (§12). */
.platform-table-wrap {
    max-width: 100%;
    overflow-x: auto;
    background: var(--platform-color-surface, #ffffff);
    border: 1px solid var(--platform-color-border, #cfd8dc);
    border-radius: var(--platform-radius-md, 0.375rem);
}

.platform-table {
    width: 100%;
    border-collapse: collapse;
    font-size: var(--platform-font-size-sm, 0.875rem);
    color: var(--platform-color-text, #2c3e50);
}

.platform-table thead th {
    padding: var(--platform-space-sm, 0.5rem);
    text-align: left;
    font-weight: 600;
    letter-spacing: 0.01em;
    color: var(--platform-color-text-muted, #7f8c8d);
    background: var(--platform-color-surface-muted, #ecf0f1);
    border-bottom: 1px solid var(--platform-color-border, #cfd8dc);
}

.platform-table tbody td {
    padding: var(--platform-space-sm, 0.5rem);
    vertical-align: middle;
    border-bottom: 1px solid var(--platform-color-border, #cfd8dc);
}

/* The container already draws the outer border, so the last row drops its divider to avoid a double line. */
.platform-table tbody tr:last-child td {
    border-bottom: 0;
}

.platform-table tbody tr:hover {
    background: var(--platform-color-surface-muted, #ecf0f1);
}

/* ── Key/value detail table (G4) ─────────────────────────────────────────────────────────────────
   A two-column key→value detail list — a contract's / směrnice's / notification's textual details tuned
   to the Bootstrap `.table` look: 0.5rem cells, 1px row dividers in the border token, a muted key column,
   value alongside. Token-driven so light↔dark is a token switch. Promoted to the platform layer so
   documents, směrnice and the admin notification page share ONE shape instead of copy-pasting it
   (coding-standards §3). Key-column WIDTH is always a modifier, never baked into the base. */
.platform-kv-table {
    width: 100%;
    border-collapse: collapse;
}

.platform-kv-table__key,
.platform-kv-table__value {
    padding: var(--platform-space-sm, 0.5rem);
    text-align: left;
    vertical-align: top;
    border-bottom: 1px solid var(--platform-color-border, #cfd8dc);
}

.platform-kv-table__key {
    font-size: var(--platform-font-size-sm, 0.875rem);
    color: var(--platform-color-text-muted, #57606a);
}

/* An error value (e.g. a notification's delivery error) tints red. */
.platform-kv-table__value--error {
    color: var(--platform-color-danger, #d1242f);
}

/* `--fixed`: fixed table layout + hard word-breaking keeps a long unbreakable value (a spaceless contract
   number, a run-on counterparty list) inside the card at phone width instead of widening the page (§12);
   the contract/směrnice detail pages that use it also read a notch smaller, carry a bottom margin, and
   bold the key column. */
.platform-kv-table--fixed {
    table-layout: fixed;
    margin: 0 0 var(--platform-space-md, 1rem);
    font-size: var(--platform-font-size-sm, 0.875rem);
}

.platform-kv-table--fixed .platform-kv-table__key,
.platform-kv-table--fixed .platform-kv-table__value {
    overflow-wrap: anywhere;
}

.platform-kv-table--fixed .platform-kv-table__key {
    font-weight: 600;
}

/* Key-column width is a modifier (never baked in): `--prop` is the contract/směrnice detail's 35%
   proportional key, `--fixed` the notification page's 12rem fixed key. */
.platform-kv-table__key--prop {
    width: 35%;
}

.platform-kv-table__key--fixed {
    width: 12rem;
}

/* ---- Grid toolbar (M-013 search, M-206 actions slot) -------------------- */
/* The strip above the grid: an optional global search box (`:searchable`) on the leading edge and an
   optional caller `toolbar` slot (e.g. a list-page create button) on the trailing edge. The wrapper is the
   controller host; the toolbar is a sibling of the grid mount, so Tabulator never overwrites it. A flex row
   that wraps on narrow viewports; the actions block is pushed to the end with an auto inline start margin,
   so a toolbar with no search box still sits at the trailing edge. Token-driven, mobile-first (§4, §12). */
.platform-grid__toolbar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--platform-space-sm, 0.5rem);
}

/* The toolbar's card. The gap to the grid card below belongs HERE, on the outside of the box — the strip's
   old `margin-bottom` became dead space trapped INSIDE the card the moment the toolbar was wrapped in one,
   padding the card out and leaving nothing between it and the grid. Same token, correct side of the border. */
.platform-grid__toolbar-card {
    margin-block-end: var(--platform-space-md, 1rem);
}

.platform-grid__toolbar-actions {
    margin-inline-start: auto;
}

.platform-grid__search {
    width: 100%;
}

@media (min-width: 36rem) {
    .platform-grid__search {
        max-width: 22rem;
    }
}
