/* DataTable Organism - SPACING CONTRACT: No external margins */
.data-table-container {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  width: 100%;
  margin: 0;
}

.table-toolbar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--space-3);
  flex-wrap: wrap;
}

.table-toolbar-left,
.table-toolbar-right {
  display: flex;
  gap: var(--space-2);
  align-items: center;
}

/* A table is table-layout:auto with nowrap cells, so its width is CONTENT-driven and
   cannot shrink. Clipping the overflow made the trailing column -- which by house rule
   holds the row actions -- unreachable: measured on stage, 77 tables across 29 screens
   at 1024x768, 75 of them losing their action buttons (TLP-938). So the x-axis scrolls,
   like every other wide organism here (MatrixGrid, KanbanBoard, SlicedPlane,
   BookingColumns, TaskTeamColumns, Timeline, UnifiedGrid).
   overflow-y stays HIDDEN and is load-bearing: with x non-visible, `overflow-y: visible`
   computes to `auto` and every wide table becomes a second vertical scroller inside the
   panel body -- the defect TLP-913 just retired. It also keeps today's y behaviour and
   the rounded-corner clip exactly as they were. */
.table-wrapper {
  overflow-x: auto;
  overflow-y: hidden;
  border: var(--border-width-1) solid var(--border-subtle);
  border-radius: var(--radius-md);
  /* The global thumb (--border-default on transparent, layout.css) is barely visible on
     a white table -- present, but not an affordance. Every sibling scroller overrides
     it; match them. */
  scrollbar-color: var(--border-strong) var(--bg-panel);
}

.table-wrapper::-webkit-scrollbar-thumb {
  background: var(--border-strong);
}

.table-wrapper::-webkit-scrollbar-thumb:hover {
  background: var(--text-muted);
}

.data-table {
  /* Note (TLP-938): this does NOT cap the table. Under table-layout:auto with nowrap
     cells the min-content width wins, so a wide table is 100% only as a floor and
     renders at its content width -- measured 1548px inside a 936px wrapper on stage.
     The overflow was always the WRAPPER's to scroll; it just clipped instead. */
  width: 100%;
  border-collapse: collapse;
  border-spacing: 0;
  font-size: var(--text-sm);
  table-layout: auto;
}

.table-head {
  background-color: var(--bg-panel);
  border-bottom: var(--border-width-1) solid var(--border-subtle);
}

/* STICKY COLUMN HEADINGS (TLP-985) -- and why the plumbing above them is necessary.

   TLP-981 moved scrolling into the panel body, so a long list now scrolls with the PANEL
   header pinned above it. The TABLE's heading row was not sticky, so column names scrolled
   away immediately and you were reading unlabelled columns. That was a defect TLP-981
   created; before it the whole tab scrolled and the names went with everything else.

   `position: sticky` alone does nothing here, and it is worth knowing why: sticky resolves
   against the nearest ancestor with a scrolling box, and `.table-wrapper` is one -- it
   carries `overflow-x: auto` so a wide table can reach its action column (TLP-938). So the
   heading pinned to the WRAPPER, which never scrolls vertically, and drifted off with it.
   Measured on stage: heading top 288 -> -1712 with the sticky declaration in place.

   The fix is to make the thing it pins to the thing that actually scrolls. A table that IS
   the panel body takes the y-axis as well, and the panel body is then left with nothing to
   scroll -- so this is still ONE scroller, not the nested pair TLP-913 retired. Measured
   after: heading holds at 288, `bodyScrolls: false`, `wrapScrolls: true`.

   Scoped to a table that is a DIRECT child of the panel body (optionally through the
   [data-section] wrapper the redraw contract adds). A table nested deeper -- inside an
   expanded row, say -- keeps today's behaviour, because bounding it against the panel
   would fight the open-row cap. Tables in modals are untouched: their header/body/footer
   contract already works. */
.section-content > [data-section]:has(> .data-table-container),
.section-content > .data-table-container,
.section-content > [data-section] > .data-table-container {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
}

.section-content > .data-table-container > .table-wrapper,
.section-content > [data-section] > .data-table-container > .table-wrapper {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
}

.section-content > .data-table-container .table-head,
.section-content > [data-section] > .data-table-container .table-head {
  position: sticky;
  top: 0;
  /* Above the cells passing under it, and above the pinned actions COLUMN (z-index 1)
     so the corner where the two meet belongs to the heading. */
  z-index: 2;
}

/* A sticky row is only as opaque as its cells: <thead> paints its background behind them,
   but the cells themselves are transparent, so data would show straight through. Same
   reasoning as the pinned actions column below. */
.section-content > .data-table-container .table-head .table-header-cell,
.section-content > [data-section] > .data-table-container .table-head .table-header-cell {
  background-color: var(--bg-panel);
}

/* The corner cell is sticky on BOTH axes -- top from the heading, right from the actions
   column -- so it needs to outrank each of them individually. */
.section-content > .data-table-container .table-head .table-header-cell--actions,
.section-content > [data-section] > .data-table-container .table-head .table-header-cell--actions {
  z-index: 3;
}

.table-header-cell {
  padding: var(--space-2) var(--space-3);
  text-align: left;
  font-size: var(--text-xs);
  font-weight: var(--font-weight-semibold);
  text-transform: uppercase;
  letter-spacing: var(--tracking-caps);
  color: var(--text-muted);
  position: relative;
  white-space: nowrap;
}

.header-cell-content {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  overflow: hidden;
}

.header-cell-content > span:first-child {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.table-body .table-row {
  border-bottom: var(--border-width-1) solid var(--border-subtle);
  transition: background-color var(--duration-150) var(--easing-out);
}

.table-row:hover {
  background-color: var(--bg-surface-hover);
}

.table-row.selected {
  background-color: var(--primary-wash);
}

.table-cell {
  padding: var(--space-2) var(--space-3);
  color: var(--text-body);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.table-cell-checkbox {
  width: var(--space-10);
  padding: var(--space-2);
}

.table-footer {
  display: flex;
  justify-content: center;
  padding: var(--space-3) 0;
}

.table-actions {
  display: flex;
  gap: var(--space-2);
}

.table-title {
  font-size: var(--text-sm);
  font-weight: var(--font-weight-semibold);
  text-transform: uppercase;
  color: var(--text-muted);
  letter-spacing: 0.025em;
}

/* Column alignment.
   text-align carries the BODY cells. It cannot carry the header: the label sits in
   .header-cell-content, which is display:flex, and flex ignores text-align -- so a
   numeric column right-aligned its values and left-aligned its header. The header
   needs justify-content, and it needs it on both header variants (a plain div and
   the sortable <button>, which both carry .header-cell-content). TLP-873. */
.table-align-right { text-align: right; }
.table-align-center { text-align: center; }

.table-header-cell.table-align-right .header-cell-content { justify-content: flex-end; }
.table-header-cell.table-align-center .header-cell-content { justify-content: center; }

/* ...and justify-content alone is not enough on a SORTABLE header: .sort-indicator
   sets margin-left:auto to pin the chevron right, and an auto margin absorbs all the
   free space BEFORE justify-content is applied, leaving the label at the left. Drop
   the auto margin when the column is aligned, so label and chevron travel together. */
.table-header-cell.table-align-right .sort-indicator,
.table-header-cell.table-align-center .sort-indicator { margin-left: 0; }

/* Built-in action icons cell */
.table-cell-actions {
  display: inline-flex;
  gap: var(--space-2);
  align-items: center;
}

/* The row-action column is PINNED to the right edge (TLP-953).
   TLP-938 opened the wrapper's x-axis so a wide table scrolls instead of clipping. That
   made the buttons reachable, but what the scroll moves out of view is still, by house
   rule, the rightmost column -- which is the action column: measured on stage at
   1024x768, 77 clipping tables across 29 screens, 75 of them losing their buttons.
   Pinned, the scroll can only ever hide DATA.
   Applied unconditionally rather than gated on a width check, because sticky is inert
   when there is nothing to scroll: the cell is already at right: 0 and does not move.
   Mirrors the sticky row header in MatrixGrid.css -- opaque background, a divider on
   the scroll-facing side, a z-index above the cells that pass under it. */
.table-header-cell--actions,
.table-cell--actions {
  position: sticky;
  right: 0;
  z-index: 1;
  /* An inset shadow, not border-left: under border-collapse the border belongs to the
     table's border grid and is painted below this positioned cell, so it would not
     travel with it. The inset paints inside the cell and always does. */
  box-shadow: inset var(--border-width-1) 0 0 0 var(--border-default);
}

/* A sticky cell is transparent by default, so the columns scrolling underneath would
   show straight through it. Each state paints the SAME colour its row does, or the
   pinned cell visibly detaches from its row as the pointer moves. */
.table-header-cell--actions {
  background-color: var(--bg-panel);
}

.table-cell--actions {
  background-color: var(--bg-surface);
}

.table-row:hover .table-cell--actions {
  background-color: var(--bg-surface-hover);
}

/* --primary-wash is translucent (rgba, 5%), so it cannot BE the opaque background --
   it is layered over the surface, which is exactly how it renders on the row itself. */
.table-row.selected .table-cell--actions {
  background-color: var(--bg-surface);
  background-image: linear-gradient(var(--primary-wash), var(--primary-wash));
}

/* Opt-in sortable column headers. Non-sortable headers are unaffected -- these
   rules only target the .table-header-cell--sortable variant, so at rest the table
   looks identical and only sortable headers gain a hover affordance + active chevron. */
.table-header-cell--sortable {
  cursor: pointer;
  transition: background-color var(--duration-150) var(--easing-out);
}

.table-header-cell--sortable:hover {
  background-color: var(--bg-surface-hover);
}

.header-sort-button {
  width: 100%;
  margin: 0;
  padding: 0;
  border: none;
  background: none;
  font: inherit;
  color: inherit;
  text-align: inherit;
  cursor: pointer;
}

/* The indicator is ALWAYS visible (never hover-gated) so sortable columns are
   self-evident. Idle columns show a faint neutral up/down glyph; the active
   column shows its direction chevron in the primary text colour. Vertically
   centered via the flex row; sized xs so it stays subtle, not obstructive. */
.sort-indicator {
  display: inline-flex;
  align-items: center;
  flex-shrink: 0;
  margin-left: auto;
  color: var(--text-light);
}

.sort-indicator.is-active {
  color: var(--text-primary);
}

/* Column resize handle. Rendered by DataTable only when the table opts into
   persistence via tableId; the drag itself is wired by TabModule._initTableResize.
   A transparent grab strip on the right edge of each header cell (the cell is
   position:relative), revealed on hover and while a drag is in progress. */
.col-resize-handle {
  position: absolute;
  top: 0;
  right: 0;
  z-index: 2;
  /* 12px, not 4px. Four pixels is a target you find by accident, and it read as
     "nothing here" rather than "drag me". Kept inside the cell rather than straddling
     the boundary so the last column's handle cannot poke past the table edge and add
     phantom horizontal scroll. */
  width: var(--space-3);
  height: 100%;
  cursor: col-resize;
  user-select: none;
  /* Pointer events own the gesture; without this a touch drag scrolls the table. */
  touch-action: none;
  background-color: transparent;
}

/* A permanent hairline so a resizable column edge LOOKS resizable. Previously the
   handle was fully transparent until hovered, so the whole feature was invisible
   until you happened to graze it. */
.col-resize-handle::after {
  content: '';
  position: absolute;
  top: 25%;
  bottom: 25%;
  right: 0;
  width: var(--border-width-1);
  background-color: var(--border-default);
}

.col-resize-handle:hover::after,
.data-table-container.is-resizing .col-resize-handle::after {
  top: 0;
  bottom: 0;
  width: var(--border-width-2);
  background-color: var(--border-strong);
}

/* Explicit widths on every column -- honoured exactly instead of being re-spread.
   Set by DataTable when stored widths exist, and by the drag as it starts.

   `width: min-content` overrides the base `width: 100%` and is load-bearing. Fixed
   layout needs a DEFINITE width, and at 100% a table whose columns sum to less than
   its container has leftover space, which fixed layout shares out across every column
   -- so re-opening a screen with narrowed columns would silently re-inflate them all.
   min-content resolves to the sum of the specified column widths: the table is exactly
   its columns, and a narrow one ends short of the wrapper rather than stretching. */
.data-table--sized {
  table-layout: fixed;
  width: min-content;
}

.data-table-container.is-resizing {
  cursor: col-resize;
  user-select: none;
}


