/* ==========================================================================
   .tp-table — P1.F2.T3
   ©2026 Vexstorm Studios – All Rights Reserved

   The most load-bearing component in the product. The observation explorer is a
   table, every chart's mandatory exact-value table is a table, and the audit
   viewer is a table — so this file gets more attention than its size suggests.

   Variants   --compact  --zebra  --fixed  --bordered
   Elements   __scroll  __caption  __head  __row  __cell  __header  __sort
              __empty  __footer  __actions
   Modifiers  __cell--numeric  __cell--action  __row--selected  __row--muted
   States     :hover  :focus-visible  aria-sort  aria-selected

   Three rules this file exists to enforce:

   1. **A caption is first class.** ACC-003 requires one, and a table style that
      assumes there is no caption quietly discourages writing one. .tp-table__caption
      is styled as a visible heading, not as an afterthought.

   2. **A wide table scrolls inside itself, never the page.** .tp-table__scroll is
      the overflow container (UX-004). It carries tabindex="0" in the template
      so a keyboard user can reach the scroll, and it therefore needs — and has
      — a visible focus ring.

   3. **Numbers are compared down a column.** __cell--numeric is end-aligned and
      tabular so two figures of the same magnitude are the same width.
   ========================================================================== */

/* The overflow container. The table itself never sets overflow: a scrollbar on
   a <table> element is inconsistent across engines. */
.tp-table__scroll {
  overflow-x: auto;
  overscroll-behavior-x: contain;
  /* Keeps the scroll shadow from clipping the sticky header. */
  position: relative;
  max-width: 100%;
  border-radius: var(--tp-radius-md);
}

.tp-table__scroll:focus-visible {
  outline-offset: 0;
}

.tp-table {
  width: 100%;
  border-collapse: collapse;
  background-color: var(--tp-color-surface-raised);
  color: var(--tp-color-text-primary);
  font-size: var(--tp-text-sm);
  line-height: var(--tp-leading-normal);
}

/* --------------------------------------------------------------------------
   Caption
   -------------------------------------------------------------------------- */

.tp-table__caption {
  padding: var(--tp-space-3) var(--tp-space-4);
  color: var(--tp-color-text-secondary);
  font-size: var(--tp-text-sm);
  font-weight: var(--tp-weight-medium);
  line-height: var(--tp-leading-normal);
  text-align: start;
  caption-side: top;
}

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

.tp-table__head {
  background-color: var(--tp-color-surface-sunken);
}

/* Every header carries scope="col" or scope="row" in the template. Without it
   a screen reader cannot associate a cell with its heading, which turns a
   17-column explorer into an unnavigable grid (ACC-003). */
.tp-table__header {
  padding: var(--tp-space-3) var(--tp-space-4);
  border-bottom: var(--tp-border-width-thick) solid var(--tp-color-border-strong);
  color: var(--tp-color-text-secondary);
  font-size: var(--tp-text-xs);
  font-weight: var(--tp-weight-bold);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  text-align: start;
  white-space: nowrap;
  vertical-align: bottom;
}

/* Sticky header for long listings. Sticky rather than a cloned header row, so
   there is exactly one header in the accessibility tree. */
.tp-table__head--sticky .tp-table__header {
  position: sticky;
  top: 0;
  z-index: var(--tp-z-sticky);
  background-color: var(--tp-color-surface-sunken);
}

/* A sortable header is a button inside the <th>, not a clickable <th>: only
   the button is focusable, and aria-sort on the <th> announces the state. */
.tp-table__sort {
  display: inline-flex;
  align-items: center;
  gap: var(--tp-space-1);
  min-height: var(--tp-space-target-min);
  padding: var(--tp-space-1) var(--tp-space-2);
  margin: calc(-1 * var(--tp-space-1)) calc(-1 * var(--tp-space-2));
  border-radius: var(--tp-radius-sm);
  color: inherit;
  font: inherit;
  letter-spacing: inherit;
  text-transform: inherit;
  cursor: pointer;
}

.tp-table__sort:hover {
  background-color: var(--tp-color-surface-raised);
  color: var(--tp-color-text-primary);
}

.tp-table__sort:active {
  background-color: var(--tp-color-accent-subtle);
}

.tp-table__sort:disabled {
  opacity: var(--tp-opacity-disabled);
  cursor: not-allowed;
}

.tp-table__sort-icon {
  width: var(--tp-space-icon);
  height: var(--tp-space-icon);
  flex: none;
  color: var(--tp-color-text-muted);
}

/* The sorted column is marked by aria-sort in the markup and by a stronger
   label plus a filled arrow here — direction is never colour alone. */
.tp-table__header[aria-sort="ascending"],
.tp-table__header[aria-sort="descending"] {
  color: var(--tp-color-text-primary);
  box-shadow: inset 0 calc(-1 * var(--tp-border-width-thick)) 0 0
    var(--tp-color-accent-default);
}

/* --------------------------------------------------------------------------
   Body
   -------------------------------------------------------------------------- */

.tp-table__row {
  border-bottom: var(--tp-border-width-hairline) solid var(--tp-color-border-subtle);
}

.tp-table__row:hover {
  background-color: var(--tp-color-surface-sunken);
}

/* Selection is announced by aria-selected and by a checked checkbox in the
   row's first cell; the wash and the rail are reinforcement, not the signal. */
.tp-table__row--selected {
  background-color: var(--tp-color-accent-subtle);
  box-shadow: inset var(--tp-border-width-thick) 0 0 0 var(--tp-color-accent-default);
}

/* A soft-deleted or superseded row: still readable, visibly inert. */
.tp-table__row--muted {
  color: var(--tp-color-text-muted);
}

.tp-table__cell {
  padding: var(--tp-space-3) var(--tp-space-4);
  vertical-align: top;
  overflow-wrap: break-word;
}

.tp-table__cell--numeric {
  text-align: end;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* Row actions sit at the inline end and never wrap onto a second line, which
   is what keeps row heights uniform in a long listing. */
.tp-table__cell--action {
  width: 1%;
  white-space: nowrap;
  text-align: end;
}

.tp-table__actions {
  display: inline-flex;
  align-items: center;
  gap: var(--tp-space-1);
}

/* The "no rows" row. Rendered as a real row so the table structure — and its
   caption and headers — survive an empty result set. */
.tp-table__empty {
  padding: var(--tp-space-8) var(--tp-space-4);
  color: var(--tp-color-text-muted);
  text-align: center;
}

.tp-table__footer {
  border-top: var(--tp-border-width-thick) solid var(--tp-color-border-strong);
  background-color: var(--tp-color-surface-sunken);
  font-weight: var(--tp-weight-medium);
}

/* --------------------------------------------------------------------------
   Variants
   -------------------------------------------------------------------------- */

.tp-table--compact .tp-table__cell,
.tp-table--compact .tp-table__header {
  padding: var(--tp-space-2) var(--tp-space-3);
}

/* Zebra striping helps the eye track across a wide row. nth-child is a
   structural pseudo-class, not a second class, so specificity stays inside the
   one-class-plus-one-state budget. */
.tp-table--zebra .tp-table__row:nth-child(even) {
  background-color: var(--tp-color-surface-sunken);
}

.tp-table--zebra .tp-table__row:hover {
  background-color: var(--tp-color-accent-subtle);
}

/* Predictable column widths for a listing whose content length varies wildly.
   Must be paired with explicit column widths in the template. */
.tp-table--fixed {
  table-layout: fixed;
}

.tp-table--bordered .tp-table__cell,
.tp-table--bordered .tp-table__header {
  border-inline-end: var(--tp-border-width-hairline) solid
    var(--tp-color-border-subtle);
}

/* --------------------------------------------------------------------------
   Focus inside a table
   -------------------------------------------------------------------------- */

/* A focused control inside a cell must not have its ring clipped by the
   neighbouring cell's background. */
.tp-table__cell:focus-within {
  position: relative;
  z-index: var(--tp-z-base);
}

.tp-table__row:focus-visible {
  outline-offset: calc(-1 * var(--tp-border-width-thick));
}
