/* ---- The table (style guide 7.6) ------------------------------------------
   One table for every list in the product: the assessment workspace, cases,
   products, team, the audit log, monitoring, the printed report. This file is
   that one primitive and nothing else; it replaces `assessment-table.css`,
   which was the workspace's table plus the phone fixes of UX-303.

   Two things it has to hold at once:

   1. **A wide table never moves the page sideways** (UX-303). `.table-scroll`
      keeps the overflow inside the table's own box. That is the floor, not
      the fix: a cell can always be handed a value nothing will shrink.
   2. **Below 48rem the table stacks** (style guide 6.5). Each row becomes a
      card: the first cell is the title, the status chip sits at the top
      right, every other cell is a `label: value` line read off `data-label`,
      and the row's actions are a quiet row at the bottom. Done once here and
      inherited by every table, which is what closes UX-303 for the twelve
      pages that were dropping columns to fit.

   The cost of (2), stated plainly because the previous round of this file
   argued the other way: `display: block` on table elements takes the table
   role out of the accessibility tree in Chrome and Firefox. The style guide
   accepts that trade for the phone layout, and `data-label` is what carries
   the head text a screen reader would otherwise have read off the column.
   Above the breakpoint nothing about the markup changes.

   48rem is measured, not chosen: the body is 72rem with 1rem of padding a
   side, so a 768px viewport leaves 736px of content, just under what six
   columns of assessment ask for. */

/* ---- The scroll box -------------------------------------------------------
   Also the table's visible surface: one border and one radius, so a table
   that scrolls does not grow a second frame inside the first. */

.table-scroll {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  /* A scroll container still reports its *contents'* width when something
     asks it for an intrinsic size, and a grid item's automatic minimum size
     is exactly that measurement, so on the case workspace the table's width
     climbed back out through the wrapper and moved the page anyway (920px at
     a 390px viewport). `width: 0` makes the wrapper contribute nothing to
     that measurement; `min-width: 100%` then gives it all the room its
     parent actually has. */
  width: 0;
  min-width: 100%;
}

/* ---- The table ------------------------------------------------------------ */

.table {
  width: 100%;
  /* `separate` rather than `collapse`: a collapsed border is painted by the
     table, not the cell, and a sticky head then leaves its rule behind when
     it moves. Every rule below is a cell's own `border-bottom`. */
  border-collapse: separate;
  border-spacing: 0;
  background: var(--surface);
  color: var(--ink-2);
  font-size: var(--fs-small);
  line-height: var(--lh-small);
}

/* The table's name for a screen reader, when the legend above it already
   names it on the page (style guide 9). */
.table__caption {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  border: 0;
  clip-path: inset(50%);
  overflow: hidden;
  white-space: nowrap;
}

.table thead th {
  position: sticky;
  top: 0;
  z-index: var(--z-sticky);
  background: var(--surface-sunk);
  border-bottom: 1px solid var(--rule);
  padding: 10px var(--sp-12);
  color: var(--slate);
  font-size: var(--fs-micro);
  line-height: var(--lh-micro);
  font-weight: var(--fw-medium);
  text-align: left;
  vertical-align: bottom;
}

.table tbody td {
  padding: 10px var(--sp-12);
  border-bottom: 1px solid var(--line-soft);
  text-align: left;
  vertical-align: top;
}

/* The last rule in the table would be drawn against the scroll box's own
   border, one pixel under it. The assessment's last row is followed by
   its (empty) detail slot, so that row is the second-last one. */
.table tbody tr:last-child > td,
.table tbody tr:has(+ tr.table__detail:last-child) > td { border-bottom: none; }

/* Numbers and dates: right-aligned, and figures that line up under each
   other rather than jostling by digit (style guide 7.6). */
.table__num,
th.table__num {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

/* A date is a number that reads left to right, and it holds its own line:
   the column is sized by its content, and "Not recorded" broken over two
   lines in every row is noise where a value would be. */
.table__date {
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* Nothing recorded yet: present, and quiet enough not to read as a value. */
.table__none { color: var(--slate); }

/* ---- The row as the link (style guide 6.4, 7.6) ---------------------------
   A row with one obvious destination is that destination. The title cell
   holds the `<a>`; the anchor's `::after` covers the row, so the target is
   the whole row height and the link still works with scripts off and reads
   as one link to a screen reader. Anything else in the row that is itself
   interactive lifts above that cover (`.table__actions` below). */

.table__row--link { position: relative; }

.table__row--link:hover > td,
.table__row--link:focus-within > td { background: var(--surface-sunk); }

.table__link {
  color: var(--ink);
  text-decoration: none;
}

.table__link::after {
  content: "";
  position: absolute;
  inset: 0;
}

.table__link:hover { color: var(--accent-deep); }

/* An ID tag is drawn on `--surface-sunk`, which is exactly what the row's
   hover ground becomes: without this the identifier dissolves into the row
   under the pointer. */
.table__row--link:hover .tag-id,
.table__row--link:focus-within .tag-id { background: var(--surface); }

/* The ring goes inside the row: at the default offset it would be drawn over
   the rows above and below. */
.table__link:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
}

/* ---- Cells with a job ----------------------------------------------------- */

/* The identifier column: mono, one line, as narrow as its content. */
.table__id { white-space: nowrap; }

/* The prose column: the one cell allowed to be long. `anywhere` because
   requirement statements quote identifiers ("prEN 40000-1-2:2025,") that no
   line-breaking rule will split, and one of them held the column 59px wider
   than a phone screen. */
.table__prose {
  overflow-wrap: anywhere;
  max-width: 34rem;
}

/* Status: chips, wrapping between chips rather than inside one. The flex box
   is a child of the cell and never the cell itself: `display` on a `<td>`
   stops it being a table cell, and the row breaks around it. */
.table__chips {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-4);
}

/* Actions that are not the row's destination: ghost buttons, or one
   `<details>` menu when there are more than two. Above the row's cover. */
.table__actions {
  position: relative;
  z-index: 1;
  width: 1%;
  white-space: nowrap;
  text-align: right;
}

/* ---- A cell that holds more than one block --------------------------------
   Below 48rem a stacked card's cell is laid out as a `label: value` flex row,
   so a cell with two children of its own becomes two columns squeezed to a
   character a line (a name beside its address, a role list beside the control
   that adds to it). One wrapper makes it one flex item again, and the blocks
   read down inside it at every width.

   A table primitive concern rather than a page's: the layout it answers to is
   the stacking rule above, which every table on `.table` inherits. It used to
   be written out twice, in `team.css` and in `recurring.css`. */

.cell-stack {
  display: grid;
  gap: var(--sp-4);
  flex: 1 1 auto;
  min-width: 0;
}
.cell-stack__line {
  margin: 0;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--sp-4) var(--sp-8);
}
.cell-stack .note { margin: 0; }

/* ---- The row that opens in place ------------------------------------------
   The assessment's detail. One full-width cell holding a `.panel--sunk`, so
   what opens is a surface below the row rather than a second table. */

.table__detail > td {
  padding: 0 var(--sp-12) var(--sp-12);
  background: var(--surface-sunk);
}

/* A closed slot is an empty cell: no padding, no ground, and no rule of its
   own: the row above it has already drawn one. */
.table__detail > td:empty {
  padding: 0;
  background: none;
  border-bottom: none;
}

/* The panel answers the click that asked for it: it is revealed on the way in
   and collapses on the way out, and nothing else on this table moves. Both
   classes are put on by `row-panel.js` and only for a swap the row link asked
   for, so a write made inside the panel re-renders it without replaying the
   reveal, and the panel the server rendered open (`?open=<pk>`) is simply
   there. Under `prefers-reduced-motion` the rule in `base.css` cuts both to
   1ms; the script empties the slot either way. */
@keyframes row-panel-reveal {
  from { opacity: 0; transform: translateY(-6px); }
  to { opacity: 1; transform: translateY(0); }
}

@keyframes row-panel-collapse {
  from { opacity: 1; transform: translateY(0); }
  to { opacity: 0; transform: translateY(-6px); }
}

.table__detail .detail-panel.is-opening {
  animation: row-panel-reveal var(--dur-2) var(--ease) both;
}

.table__detail .detail-panel.is-closing {
  animation: row-panel-collapse var(--dur-2) var(--ease) both;
}

/* ---- A sortable head cell -------------------------------------------------
   Sort is URL state, so the control is a link. `aria-sort` says which way. */

.table th[aria-sort] > a {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-4);
  color: inherit;
  text-decoration: none;
}

.table th[aria-sort="none"] > a::after { content: ""; }
.table th[aria-sort="ascending"] > a::after { content: "\2191"; }
.table th[aria-sort="descending"] > a::after { content: "\2193"; }

/* ---- Stacking below 48rem (style guide 6.5) -------------------------------
   `screen` on purpose: a printed page is often narrower than 48rem, and the
   report's tables must print as tables. */

@media screen and (max-width: 48rem) {
  .table-scroll {
    /* Nothing overflows once the rows are cards, and a scroll box around a
       column of cards is a gesture nobody expects. */
    overflow-x: visible;
  }

  .table,
  .table > thead,
  .table > tbody,
  .table > tbody > tr,
  .table > tbody > tr > td {
    display: block;
    /* A card is as wide as the phone and no wider: a route pattern or a hash
       in a code span breaks mid-token rather than pushing the page sideways
       (the audit log's detail cells, UX-303). */
    overflow-wrap: anywhere;
    min-width: 0;
    width: auto;
  }

  /* The head text moves onto each cell as `data-label`. */
  .table > thead { display: none; }

  .table > tbody > tr {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    gap: var(--sp-4) var(--sp-8);
    padding: var(--sp-12);
    border-top: 1px solid var(--line-soft);
  }

  .table > tbody > tr:first-child { border-top: none; }

  .table > tbody > tr > td {
    grid-column: 1 / -1;
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--sp-12);
    padding: 0;
    border-bottom: none;
  }

  .table > tbody > tr > td::before {
    content: attr(data-label);
    flex: none;
    color: var(--slate);
    font-size: var(--fs-small);
  }

  /* A cell that belongs to no column (a spanning cell, the assessment's
     detail slot) says nothing rather than opening an empty label column. */
  .table > tbody > tr > td:not([data-label])::before { content: none; }

  /* A cell with no label is not a `label: value` line, so it is not laid out
     as one: it goes back to being a block, and whatever it holds reads down
     the card from the left. The flex row above would make each child of it a
     flex item shrunk to its own minimum, which on the monitoring findings
     card (three blocks in one cell, and `overflow-wrap: anywhere` over the
     prose) came out as three 30px columns of one character a line. */
  .table > tbody > tr > td:not([data-label]) {
    display: block;
    text-align: left;
  }

  /* A chip is written to hold its own line (style guide 7.4), which is right
     in a table row and wrong in a card: the one long chip in the codebase
     ("Shorter than CRA Art. 13.9 allows", `releases/partials/update_row.html`)
     is what pushed the case record sideways at 390px. In a card it wraps;
     `word-break: keep-all` still keeps CJK off a mid-word break. */
  .table > tbody > tr > td .chip {
    white-space: normal;
  }

  /* The first cell is the card's title, and the status chip sits at its
     right on the same line. */
  .table > tbody > tr > td:first-child {
    grid-column: 1;
    color: var(--ink);
    font-weight: var(--fw-medium);
  }

  .table > tbody > tr > td:first-child::before { content: none; }

  .table > tbody > tr > td.table__status {
    grid-column: 2;
    grid-row: 1;
    justify-content: flex-end;
  }

  .table > tbody > tr > td.table__status::before { content: none; }

  /* Long text reads under its label, not squeezed beside it. The chips that
     follow it keep their own width: `stretch` would draw each one as a full
     line, and a chip that fills the card is not a chip. */
  .table > tbody > tr > td.table__prose {
    flex-direction: column;
    align-items: flex-start;
    gap: 2px;
    max-width: none;
  }

  /* The actions are the quiet row at the bottom of the card. */
  .table > tbody > tr > td.table__actions {
    justify-content: flex-start;
    width: auto;
    white-space: normal;
    text-align: left;
    padding-top: var(--sp-4);
  }

  /* The detail keeps its own card, joined to the row above it. The padding
     is on the cell, so a closed slot takes no room at all: an empty card
     between every two rows is what a padded row would draw. */
  .table > tbody > tr.table__detail {
    display: block;
    padding: 0;
    border-top: none;
  }

  .table > tbody > tr.table__detail > td {
    padding: 0 var(--sp-12) var(--sp-12);
    background: none;
  }

  .table > tbody > tr.table__detail > td:empty { padding: 0; }
}
