/* ============================================================================
 * Table — .ui-table  (hairline rows, opaque base surface)
 * Row modifiers: .is-dead (revoked, shown by its muted ink and a word), .is-target (landed on), right-aligned .ui-table__act
 * ========================================================================== */

.ui-table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--text-base);
}
/* Fit cards keep short tables close to their labels. Other cards keep full-width tables. */
:where(.ui-card--fit) .ui-table {
  width: auto;
  max-width: 100%;
}
.ui-table th {
  text-align: left;
  /* rank: label */
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  color: var(--text);
  padding: 0 var(--space-4) var(--space-3) 0;
  border-bottom: 1px solid var(--border);
}
/* A row header is a body cell that happens to name its row, so it takes the body cell's
 * padding. `.ui-table th` pads for the head, where the label sits above the rule and
 * wants no space over it; inside the body or the footer that left the name sitting low
 * against the values beside it. `:is()` here is only for specificity — two type
 * selectors outrank `.ui-table th`, which states the head's padding after this. */
.ui-table td,
.ui-table :is(tbody, tfoot) th {
  padding: var(--space-4) var(--space-4) var(--space-4) 0;
  border-bottom: 1px solid var(--border);
  color: var(--text);
  vertical-align: middle;
  white-space: nowrap;
}
/* The last row of the last section, so a final body row keeps its separator when a
 * footer follows it. `tr:last-child td` closed the wrong edge: it stripped the border
 * from the last row of every section, leaving items and totals with nothing between
 * them. why: docs/foundations.md#spacing-and-rhythm */
.ui-table > :last-child > tr:last-child > :is(th, td) { border-bottom: 0; }
/* Totals open with the 2px rule the zebra header already uses, so a reader can see
 * where items end and totals begin; five identical hairlines told them nothing.
 * Collapsed borders paint one edge, so this meets the last body row's hairline and the
 * wider of the two wins — no doubled line.
 * A footer label is a row header for the figure beside it, so it sits against that
 * figure rather than against the first column it spans. */
.ui-table tfoot tr:first-child > :is(th, td) { border-top: 2px solid var(--border-strong); }
.ui-table tfoot th { text-align: right; }
.ui-table td.ui-table__title { color: var(--strong); font-weight: var(--weight-medium); width: 99%; white-space: normal; }
.ui-table th:last-child { padding-right: 0; }
/* The last body cell ends where its header and the table end. A right-aligned amount in the
   last column stood 16px in from both, because only the header and the action cell dropped
   the cell gap. The variants below state their own end padding. why: docs/foundations.md#spacing-and-rhythm */
.ui-table td:last-child { padding-right: 0; }
.ui-table td.ui-table__act { padding-right: 0; text-align: right; }
.ui-table tr.is-dead td { /* muted-ink: state — revoked row */ color: var(--muted); }
.ui-table tbody tr { transition: background var(--dur-fast) var(--ease); }

/* Row hover: an inset, rounded fill so the highlight never sits flush against a
 * container's border (#71). The separate border model with zero spacing keeps the row
 * separators continuous while letting the row ends round, and table padding — which
 * only applies in that model — insets the rows. Zebra keeps the original full-bleed
 * tint (finance ledger) and is excluded here; its hover rule is below. */
.ui-table--hover:not(.ui-table--zebra) {
  border-collapse: separate;
  border-spacing: 0;
  padding: 0 var(--space-2);
}
.ui-table--hover:not(.ui-table--zebra) tbody tr:hover td:first-child {
  border-top-left-radius: var(--radius-sm); border-bottom-left-radius: var(--radius-sm); }
.ui-table--hover:not(.ui-table--zebra) tbody tr:hover td:last-child {
  border-top-right-radius: var(--radius-sm); border-bottom-right-radius: var(--radius-sm); }
/* The hover band is the last cell, which ends where the figures end, so a hovered row's fill
   stopped at the last glyph. The last column of a hover table keeps one cell gap of room
   inside the band, header and body alike, so the figures and their header still share one
   right edge. The dense and compact variants state their own end padding below, and an
   action cell keeps none. */
:where(.ui-table--hover:not(.ui-table--zebra)) :is(th, td):not(.ui-table__act):last-child { padding-right: var(--space-4); }

/* Data-table modifiers, composable: .ui-table--dense --zebra --hover.
 *   --dense  --space-3 across, --space-2 down — one step in from the base table
 *   --zebra  legacy spacing and 2px header rule; the base-surface rule below removes stripes
 * Cell helpers: .ui-table__num (right, tabular), .ui-table__code, .ui-table__pair.
 * why: docs/foundations.md#spacing-and-rhythm
 * held by: stories/table-rhythm.test.js */
.ui-table--dense th { padding: 0 var(--space-3) var(--space-2); }
.ui-table--dense td,
.ui-table--dense :is(tbody, tfoot) th { padding: var(--space-2) var(--space-3); font-size: var(--text-sm); white-space: nowrap; }
.ui-table--dense th:first-child,
.ui-table--dense td:first-child { padding-left: var(--space-3); }
.ui-table--dense th:last-child,
.ui-table--dense td:last-child { padding-right: var(--space-3); }

.ui-table--zebra thead th { border-bottom-width: 2px; }
.ui-table--zebra td,
.ui-table--zebra :is(tbody, tfoot) th { border-bottom: 0; }
.ui-table--zebra tbody tr:nth-child(even) td { background: var(--surface-2); }
/* The stripe stays full-bleed (the #71 inset above is hover only), but it only reads right
 * if the end cells are inset from the row's own edge, and `.ui-table td` sets
 * `padding-left: 0`. Only `--dense` supplied that inset, so `--zebra` without `--dense` —
 * `DataTable`'s composition — sat its checkboxes at x=0 of the row. Head and body are
 * inset together, or the columns stop lining up. Held by src/styles/table.test.js, and
 * kept off the card's text edge by the bleed rule at the end of this file. */
.ui-table--zebra th:first-child,
.ui-table--zebra td:first-child { padding-left: var(--space-3); }
.ui-table--zebra th:last-child,
.ui-table--zebra td:last-child { padding-right: var(--space-3); }

/* A link in a cell is a value that happens to open something: the row's ink, underlined
   on hover — what .ui-identity below has always done. Without it, base.css's bare
   `a { color: var(--accent) }` reached the ledger's IDs.
   why: guidelines/density-and-accents.md#give-accents-a-job */
.ui-table :where(td, th) a:not(.ui-btn):not(.ui-identity) {
  color: inherit;
  text-decoration: none;
}
.ui-table :where(td, th) a:not(.ui-btn):not(.ui-identity):hover {
  color: var(--strong);
  text-decoration: underline;
}
/* One exception, and it is the way through: a reference that opens another screen at
   this row. The rule above was written to keep a LEDGER's identifiers out of the accent
   — a whole column of them is an accent with no job (guidelines/density-and-accents.md,
   give-accents-a-job) — but a dashboard's exceptions are three rows, and there the link
   is how a reader reaches the row's own report. Left in the row's ink it was the plain
   cell beside it to the pixel, resolving only on hover, which a phone does not have.
   .ui-table__pair is the cell that carries a reference and its state, so the exception is
   as narrow as that cell. The ink is base.css's own `a { color: var(--accent) }`, at
   7.34:1 in light and 5.53:1 in dark on the table's ground.
   why: Artur, round r34; guidelines/dashboards-and-reports.md#link-each-reference-to-its-row
   held by: src/styles/table.test.js */
.ui-table :where(td, th) .ui-table__pair a:not(.ui-btn):not(.ui-identity) { color: var(--accent); }
.ui-table :where(td, th) .ui-table__pair a:not(.ui-btn):not(.ui-identity):hover {
  color: var(--accent);
  text-decoration: underline;
}
/* A plain link — one carrying no class — is the link these rules are about. An inline-block
   box, so a title link that wraps paints one ring instead of one per line, and the kit's small
   corner for that ring to follow. Anchors the kit already styles (`.ui-btn`, `.ui-identity`,
   `.ui-dropdown__item`, `.ui-nav__item`) keep the box and the corner their own component sets;
   a denylist of them went stale twice before this said what it meant (#510).
   held by: src/styles/table-focus.test.js */
.ui-table :where(td, th, caption) a:not([class]) {
  display: inline-block;
  border-radius: var(--radius-xs);
  position: relative;
}
/* A bare link in a cell is only as tall as its line box — 21px in a dense table,
   under the 24px pointer floor. This layer gives a pointer the floor without
   moving anything: growing the link's own box would grow every dense row holding
   one. Written one cell kind per line because the measuring gate splits a
   selector list on commas, and `:where(td, th, caption)` carries two of its own.
   why: guidelines/accessibility-floor.md#minimum-target-size
   held by: stories/guidelines/accessibility-floor.test.js */
.ui-table td a:not([class])::after,
.ui-table th a:not([class])::after,
.ui-table caption a:not([class])::after {
  content: '';
  position: absolute;
  height: 24px;
  left: 0;
  right: 0;
  top: 50%;
  translate: 0 -50%;
}
/* No generic focus rule here. #510 gave a cell link the ring because `base.css`
   reached no bare `a`; #587 put `a` on that shared list, so this file only keeps
   the filled-cell override below. why: guidelines/state-set.md#focus-rings */
/* The handle: a cell MARKED `.ui-table__linked` holds one link and nothing else, so the
   link fills the cell and its ring outlines the cell rather than the words. The cell hands
   its padding over and nothing moves. `height: 1px` is the cell stating no height of its
   own, which a percentage height on the link can resolve against; a cell is stretched to
   its row either way, so no row changes.
   The mark is the consumer's because a selector counts elements and not words: `:only-child`
   reads `<td>Invoice <a>1162</a></td>` as a lone link too. The link is named rather than
   denied — a denylist of the anchors that own their box went stale twice (#510).
   why: docs/components.md#dense-financial-tables, #500
   held by: src/styles/table-focus.test.js */
.ui-table td.ui-table__linked:has(> :is(a:not([class]), a.ui-identity):only-child) { padding: 0; height: 1px; }
.ui-table td.ui-table__linked > :is(a:not([class]), a.ui-identity):only-child {
  box-sizing: border-box;
  display: flex;
  align-items: center;
  width: 100%;
  height: 100%;
  padding: var(--space-4) var(--space-4) var(--space-4) 0;
  border-radius: var(--radius-xs);
}
/* The last cell gave up its end gap above, so the link it holds gives up the same. */
.ui-table td.ui-table__linked:where(:last-child) > :is(a:not([class]), a.ui-identity):only-child { padding-right: 0; }
:where(.ui-table--hover:not(.ui-table--zebra)) td.ui-table__linked:last-child > :is(a:not([class]), a.ui-identity):only-child { padding-right: var(--space-4); }
.ui-table--dense td.ui-table__linked > :is(a:not([class]), a.ui-identity):only-child { padding: var(--space-2) var(--space-3); }
.ui-table--compact td.ui-table__linked > :is(a:not([class]), a.ui-identity):only-child { padding: var(--space-1) var(--space-3); }
/* Zebra insets the row's END cells only, so the fill does too: a marked identity behind a
   selection column is a middle cell, and a step it never gave up would move its name. */
.ui-table--zebra td.ui-table__linked:first-child > :is(a:not([class]), a.ui-identity):only-child { padding-left: var(--space-3); }
.ui-table--zebra td.ui-table__linked:last-child > :is(a:not([class]), a.ui-identity):only-child { padding-right: var(--space-3); }
/* The inward band, the one a scroll region takes: a filled cell's edges are the
   table's, where the pinned column's border and the scroller's 4px side padding
   cut an outset ring away. Its 1px gap is unpainted, and the ring is the outline. */
.ui-table td.ui-table__linked > :is(a:not([class]), a.ui-identity):only-child:focus-visible {
  outline: var(--ring-scroll);
  outline-offset: var(--ring-scroll-offset);
}

.ui-table__num { text-align: right; font-variant-numeric: tabular-nums; }
/* A numeric column is sized to its content while .ui-table__title claims the rest,
 * so a two-word numeric header wraps where none of its values ever do. */
.ui-table th.ui-table__num { text-align: right; white-space: nowrap; }
.ui-table__num--strong { color: var(--strong); font-weight: var(--weight-semibold); }
/* `.ui-table th` and `.ui-table td` each state their own ink, and `th` its weight too,
 * so both outranked the helper: a totals row marked strong came out in body ink, and
 * bold only in the figure. Scoped to the table, the helper wins on either cell and the
 * row reads as one row. */
.ui-table :is(th, td).ui-table__num--strong { color: var(--strong); font-weight: var(--weight-semibold); }
.ui-table__code { font-size: var(--text-sm); color: var(--text); }
/* Two things in one cell — a row's own name and the state of it — side by side
 * while the column has room and stacked when it does not. The wrap comes from flex
 * because a dense cell is nowrap, and the column is then only as wide as the wider
 * of the two: a status that had a column of its own was the first thing a phone cut
 * off, and in here it is the last. The class goes on a span inside the cell, never
 * on the cell, which would leave the table box model. A row carrying a paragraph takes
 * .ui-table--stack below instead, which drops the head; a pair keeps every head at every
 * width, which is what a three-value glance row is read by. why: #505 */
.ui-table__pair { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1) var(--space-2); }

/* The empty state (.ui-empty) — shown when a table/list has no rows — now
   lives in styles/empty.css as a standalone component (illustration support). */

/* Tables share their containing card’s reading surface, including pinned cells. The code
   chip's hand-off travels with it, so an identifier in a cell keeps the page rather than
   the card the cell is now painted with. why: src/tokens/tokens.css */
.ui-card { --table-bg: var(--surface); --table-code-bg: var(--bg); }

/* White in light, base canvas in dark; never a grey or tinted data surface. */
.ui-table { background: var(--table-bg); }
.ui-table--zebra tbody tr:nth-child(even) td { background: var(--table-bg); }
/* A row hover is a quiet neutral step. The row paints under transparent cells in a
   scroll region, while ordinary cells cover the row without breaking its fill. */
.ui-table--hover tbody tr:hover:not(.is-target),
.ui-table--hover tbody tr:hover:not(.is-target) > :is(td, th) {
  background: var(--surface-2);
}

/* The row a reference landed a reader on. The mark is a GROUND, not a line: an outline
   says the keyboard is here (Artur, r34), and this one persists — it answers which row the
   reader came for, so it stays until the next arrival and must not wear the picture focus
   draws. It took --ring-scroll until #505's review found a landed row still outlined in the
   accent after focus had moved on, with a second row beside it wearing the same box.
   The ground and the ring paint together on arrival: `landOnRow()` focuses the row, so a
   reader must see both at once, not the ring now and the ground only after they tab away.

   The wash is the accent over the table's own ground: the family `tbody tr:hover` already
   uses for "this row", one step up from its 8% so the two are told apart. 12% is the
   strongest step that keeps an accent link inside the row above 4.5:1 — 4.60:1 at the worst
   of the eight accent/theme cells, against 4.45:1 at 14%. It paints cells rather than the
   row, because the hover and zebra rules paint cells and would otherwise cover it; the two
   hover selectors are repeated with .is-target so a pointer passing over the row does not
   take its mark off.
   why: Artur, round r34; guidelines/dashboards-and-reports.md#link-each-reference-to-its-row
   held by: stories/dashboard-report-refs.test.js, for landOnRow() marking the right row and
   only the right row; stories/contrast.test.js, for the wash's contrast, now that
   stories/components/Table.stories.js:FinanceData renders a row wearing the mark at rest.
   Neither gate reads paint against focus: the ground and the ring share no selector and no
   condition, which is why one cannot switch the other off, and that is proved by the PR's
   browser captures rather than by a gate. PR #552 code review, finding F6. */
.ui-table tbody tr.is-target > :is(td, th),
.ui-table--hover tbody tr.is-target:hover > :is(td, th),
.ui-table--zebra.ui-table--hover tbody tr.is-target:hover > :is(td, th) {
  background: color-mix(in srgb, var(--accent) 12%, transparent); /* code-bg: inherit — this translucent wash leaves the chip on its opaque ground. */
}

/* A focused row draws the shared ring inward, like its containing scroll region.
   why: docs/foundations.md#the-focus-ring */
.ui-table tbody tr:focus-visible {
  outline: var(--ring-scroll);
  outline-offset: var(--ring-scroll-offset);
}

/* The end-cell inset above gives a row's highlight room; the bleed is what stops the grid
   paying for it. The table hangs out by the same --space-3, into the card's 20-24px
   padding and never past it, so the columns start on the card's own text edge and the
   scroll region stays empty at rest. why: docs/foundations.md#spacing-and-rhythm */
.ui-card > :where(.ui-table--dense, .ui-table--zebra) {
  width: calc(100% + 2 * var(--space-3));
  margin-inline: calc(-1 * var(--space-3));
}
.ui-card--fit > :where(.ui-table--dense, .ui-table--zebra) {
  width: auto;
  max-width: calc(100% + 2 * var(--space-3));
}
/* A scroll wrapper owns the bleed for a nested dense table: 4px of focus
   clearance plus the 12px end-cell inset. */
.ui-card > .ui-table-scroll:has(> .ui-table--dense) {
  margin-inline: calc(-1 * var(--space-4));
}
.ui-card > .ui-table-scroll > .ui-table--dense {
  padding-inline: 0;
}
.ui-table td.ui-table__num { text-align: right; }
.ui-table--compact td,
.ui-table--compact :is(tbody, tfoot) th { padding: var(--space-1) var(--space-3); font-size: var(--text-sm); line-height: var(--leading-snug); height: 33px; }
.ui-table--compact th { padding: var(--space-2) var(--space-3); }
.ui-table--compact th:last-child,
.ui-table--compact td:last-child { padding-right: var(--space-3); }
/* Columns past the box's edge, said in paint. Two shades, one per side, under two
   cover layers that ride the content: `local` moves a cover with the scroll, so
   reaching an end slides that cover over its shade. A cover is solid for its first
   half, so at 24px it hides a 12px shade outright — which is why the two sizes are
   not one. why: guidelines/dense-tables.md */
.ui-table-scroll {
  overflow: auto; max-height: var(--ui-table-height, 70vh);
  /* A transparent border, not padding: positioned cells cover an outline on the scrollport's
     padding. The side and bottom bands draw in the border at the visible edge at every scroll
     position. why: docs/foundations.md#the-focus-ring */
  border: 0 solid transparent; border-inline-width: var(--space-1); border-bottom-width: var(--space-1); background-origin: border-box;
  background-color: var(--table-bg);
  background-image:
    linear-gradient(to right, var(--table-bg) 50%, transparent),
    linear-gradient(to left, var(--table-bg) 50%, transparent),
    radial-gradient(farthest-side at 0 50%, var(--table-edge), transparent),
    radial-gradient(farthest-side at 100% 50%, var(--table-edge), transparent);
  background-position: 0 0, 100% 0, 0 0, 100% 0;
  background-size: var(--space-6) 100%, var(--space-6) 100%, var(--space-3) 100%, var(--space-3) 100%;
  background-repeat: no-repeat;
  background-attachment: local, local, scroll, scroll;
}
/* The edge darkens on a light ground and lightens on a dark one: ink has nowhere to
   go on a near-black page, which is why --elev-drop splits its spend and a raised
   dark surface takes a light --elev-edge. */
.ui-table-scroll { --table-edge: color-mix(in srgb, var(--sheen) 12%, transparent); }
:root[data-theme="light"] .ui-table-scroll { --table-edge: color-mix(in srgb, var(--shadow-ink) 13%, transparent); }
/* The surface belongs to the box that scrolls, so the shades land under the cells
   rather than behind them; the row fills repeat that same surface and step aside.
   The sticky header and pinned column keep their paint: they hide what scrolls
   beneath them. */
.ui-table-scroll > .ui-table,
.ui-table-scroll > .ui-table tbody td:not(.ui-table__identity, .ui-table__selection) { background-color: transparent; }
.ui-table-scroll > .ui-table--hover tbody tr:hover:not(.is-target) > :is(td, th) {
  background: var(--surface-2);
}
/* The kit's first ringed scroller, and a scroll region inside a card like the rest, so
   it draws the band inward too rather than spending a halo across the card around it.
   It had no room of its own to draw in — the border above is horizontal — which is the
   second reason the band is an outline: it is painted over the rows, in the cell padding
   of the first and last, rather than under them. #531
   why: docs/foundations.md#the-focus-ring */
.ui-table-scroll:focus-visible { outline: var(--ring-scroll); outline-offset: var(--ring-scroll-offset); }
@media (forced-colors: active) {
  .ui-table-scroll { border-color: Canvas; }
}
.ui-table--sticky { border-collapse: separate; border-spacing: 0; }
.ui-table--sticky thead th { position: sticky; top: 0; z-index: var(--z-sticky); background: var(--table-bg); padding-top: var(--space-2); }
/* The header sticks at the region's top edge, which is where the inward band draws, and a
   positioned cell paints over an outline. While the region holds the ring, the header
   gives up the band's own 3px, so the ring is whole on the top side. The side bands lie in
   the region's border, which no cell reaches.
   why: docs/foundations.md#the-focus-ring */
.ui-table-scroll:focus-visible .ui-table--sticky thead th { clip-path: inset(calc(var(--ring-gap-width) + var(--ring-width)) 0 0 0); }
.ui-table--pinned .ui-table__identity, .ui-table--pinned .ui-table__selection { position: sticky; left: 0; z-index: var(--z-base); background: var(--table-bg); border-right: 1px solid var(--border); }
.ui-table--pinned thead .ui-table__identity, .ui-table--pinned thead .ui-table__selection { z-index: calc(var(--z-sticky) + 1); }
/* The divider is the pin's edge: it says the column stayed while the rest moved under it.
   Columns that all fit never move, so the line divides nothing and reads as an arbitrary
   rule. The resting rule keeps it, so an engine that cannot answer the query is unchanged;
   scroll-state makes a query container, not a size one. why: guidelines/dense-tables.md */
.ui-table-scroll { container-type: scroll-state; }
/* A shared grid cell puts the edge shade over the opaque sticky header, on both
   sides: the radial-gradient shades below answer only the table's own background
   and fall to nothing where the sticky header paints over them, so an engine that
   can ask whether the scrollport still has room sticks a shade of its own above
   it instead and the base radial pair is sized to 0 here. #434 review round 2 */
@supports (container-type: scroll-state) {
  .ui-table-scroll {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    background-size: var(--space-6) 100%, var(--space-6) 100%, 0 100%, 0 100%;
  }
  .ui-table-scroll > .ui-table { grid-area: 1 / 1; }
  .ui-table-scroll::before,
  .ui-table-scroll::after {
    content: '';
    grid-area: 1 / 1;
    position: sticky;
    top: 0;
    width: var(--space-3);
    z-index: calc(var(--z-sticky) + 2);
    pointer-events: none;
  }
  .ui-table-scroll::before { left: 0; right: calc(100% - var(--space-3)); justify-self: start; }
  .ui-table-scroll::after { left: calc(100% - var(--space-3)); right: 0; justify-self: end; }
  @container scroll-state(scrollable: left) {
    .ui-table-scroll::before { background: linear-gradient(to right, var(--table-edge), transparent); }
  }
  @container scroll-state(scrollable: right) {
    .ui-table-scroll::after { background: linear-gradient(to left, var(--table-edge), transparent); }
  }
}
@container not scroll-state(scrollable: x) {
  .ui-table--pinned :is(.ui-table__identity, .ui-table__selection) { border-right-color: transparent; }
}
.ui-value, .ui-delta { white-space: nowrap; font-variant-numeric: tabular-nums; }
.ui-value__unit { margin-left: var(--space-1); font-size: var(--text-xs); color: var(--text); }
.ui-delta--success { color: var(--chip-success-ink); }
.ui-delta--danger { color: var(--chip-danger-ink); }
.ui-identity { min-height: 24px; display: inline-flex; align-items: center; gap: var(--space-2); color: var(--text); text-decoration: none; }
.ui-identity__symbol { font-weight: var(--weight-semibold); }
.ui-identity__name { white-space: normal; max-width: var(--panel-sm); }
.ui-identity__logo { width: 24px; height: 24px; flex: 0 0 24px; position: relative; display: grid; place-items: center; border: 1px solid var(--border); border-radius: var(--radius-xs); font-size: var(--text-xs); }
.ui-identity__logo img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: contain; }
.ui-identity__logo img[hidden] { display: none; /* motion: still — a failed resource is replaced without animating the error. */ }
a.ui-identity:hover { text-decoration: underline; }
.ui-identity:focus-visible { outline: var(--ring); outline-offset: var(--ring-offset); border-radius: var(--radius-xs); }
@media (max-width: 720px) {
  /* One line wide: nothing wraps, and --ui-table-identity-max is the ceiling a consumer
     retunes. The cut takes NO margin — the cell is sticky and the next column scrolls
     under it, so whatever the cut lets out is painted over that column. A child's ring
     needs 3px and the cell's padding is 12px, so the room comes from the padding.
     why: docs/components.md#dense-financial-tables, #500, #513 */
  /* A percentage can stretch an intrinsic table beyond its content. */
  .ui-card--fit .ui-table--pinned .ui-table__identity { width: 1px; }
  .ui-table--pinned .ui-table__identity {
    width: 1%;
    max-width: var(--ui-table-identity-max);
    white-space: nowrap;
    overflow: clip;
    text-overflow: ellipsis;
  }
  /* A sub-line is one line of running text and cuts itself: the cell's ellipsis cannot
     reach into a child block. 4px is a focused link's ring, inside the cell's padding.
     Nothing is capped here — block layout already holds a child to the cell. */
  .ui-table--pinned .ui-table__identity > * {
    overflow: clip;
    overflow-clip-margin: var(--space-1);
    text-overflow: ellipsis;
  }
  /* A picture has no shorter form, so it keeps its intrinsic size and the cell cuts it.
     Nothing caps it, so write neither a cap nor a reset of one here. #513 */
  .ui-table--pinned .ui-table__identity :is(svg, img, canvas, video, picture) {
    overflow: visible;
    text-overflow: clip;
  }
  .ui-table--pinned .ui-table__identity > *:has(:is(svg, img, canvas, video, picture)) {
    text-overflow: clip;
  }
  /* A control's label is text, so it yields: held to the cell and cut at its END. A kit
     control centres its label, and a capped one that centres loses the front of it. #513 */
  .ui-table--pinned .ui-table__identity :is(.ui-btn, .ui-nav__item, .ui-badge, button, input, select, textarea) {
    max-width: 100%;
    min-width: auto;
    overflow: hidden;
    justify-content: flex-start;
    text-align: start;
  }
  /* `a:not([class])` above is an inline-block so a WRAPPING title link paints one ring.
     Nothing wraps here, and an inline-block is atomic: `text-overflow` cannot cut inside
     one, so the link came out cut mid-glyph. Inline, it draws one fragment and one
     ring, and the line's ellipsis reaches it. #513 */
  .ui-table--pinned .ui-table__identity a:not([class]) { display: inline; }
  /* Except where the fill gave the lone link the cell's box: it cuts as a block box. */
  .ui-table--pinned .ui-table__identity.ui-table__linked > a:not([class]):only-child {
    display: block;
    align-content: center;
  }
  /* The ring goes on the LINE: a link longer than the cell runs past the cut, so a ring
     around the link has no surface to draw its right side on. Inward, like every ring
     the kit puts in a clipped region. why: docs/foundations.md#the-focus-ring, #513 */
  .ui-table--pinned .ui-table__identity > *:has(a:focus-visible) {
    outline: var(--ring-scroll);
    outline-offset: var(--ring-scroll-offset);
    border-radius: var(--radius-xs);
  }
  .ui-table--pinned .ui-table__identity > * a:focus-visible { outline: none; }
  .ui-table--pinned .ui-table__identity:not(.ui-table__linked):has(> a:focus-visible) {
    outline: var(--ring-scroll);
    outline-offset: var(--ring-scroll-offset);
    border-radius: var(--radius-xs);
  }
  .ui-table--pinned .ui-table__identity:not(.ui-table__linked) > a:focus-visible { outline: none; }
  .ui-table--pinned .ui-identity__logo { display: none; }
  /* An inline-flex box is the one child block layout does not hold to the cell, so the
     cap belongs on it. The whole name stays in the DOM; only the drawn line is cut. */
  .ui-table--pinned .ui-identity { max-width: 100%; }
  .ui-table--pinned .ui-identity__name { min-width: 0; max-width: 100%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
}

/* Automatic layout hands every column a share of the free width, and a box is not worth one: the selection column takes the width of its box and the gap after it. The pinned table below fixes it instead. */
.ui-table .ui-table__selection { width: 1%; }

/* One width reserves the selection track and offsets the adjacent identity. */
.ui-table--pinned { --ui-table-selection-width: var(--space-12); --ui-table-identity-max: min(var(--panel-sm), 50vw); }
.ui-table--pinned .ui-table__selection { box-sizing: border-box; width: var(--ui-table-selection-width); min-width: var(--ui-table-selection-width); max-width: var(--ui-table-selection-width); padding-inline: 0; text-align: center; }
.ui-table--pinned .ui-table__selection + .ui-table__identity { left: var(--ui-table-selection-width); }

/* ============================================================================
 * Stacked rows at phone width — .ui-table--stack, .ui-table__long
 *
 * The cell rules name both .ui-table and the modifier on purpose: --dense, --compact and
 * __title reach a cell with two classes, and one class would lose to them and leave
 * `nowrap` on a paragraph.
 *
 * The consumer's half — the roles a changed `display` drops — is in docs/components.md.
 * why: docs/components.md#dense-financial-tables
 * held by: src/styles/table-stack.test.js (layout), stories/table-stack.test.js (roles)
 * ========================================================================== */

/* The marked column holds running text at any width. What the modifier adds below the
   phone step is the line of its own. */
.ui-table td.ui-table__long { white-space: normal; }

@media (max-width: 560px) {
  .ui-table.ui-table--stack { display: block; width: 100%; min-width: 0; padding: 0; }
  .ui-table.ui-table--stack > thead {
    position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%);
  }
  .ui-table.ui-table--stack > tbody { display: block; }
  .ui-table.ui-table--stack > tbody > tr {
    display: flex; flex-wrap: wrap; align-items: baseline;
    column-gap: var(--space-3); row-gap: var(--space-1);
    /* The inset is on the row, not the table, so its hover fill and separator keep
       their clearance at the width above this one. */
    padding: var(--space-3); border-bottom: 1px solid var(--border);
  }
  .ui-table.ui-table--stack > tbody > tr:last-child { border-bottom: 0; }
  /* `height` is in this list for the same reason `white-space` is: --compact sets a row
     height for a one-line cell, and a block cell takes it as a fixed height rather than a
     floor, so a wrapped paragraph spills through the separator into the next row. A stacked
     cell is as tall as its text. */
  .ui-table.ui-table--stack > tbody > tr > td {
    display: block; width: auto; min-width: 0; max-width: 100%; height: auto;
    padding: 0; border-bottom: 0; white-space: normal; overflow-wrap: break-word;
  }
  .ui-table.ui-table--stack.ui-table--hover tbody tr:hover:not(.is-target) > :is(td, th) {
    background: transparent;
  }
  .ui-table.ui-table--stack > tbody > tr > td.ui-table__long { flex: 0 0 100%; text-align: left; }
  /* The head is gone, so an amount that names its column in `data-label` says it in front of
     the figure, in the unit's size and body ink. */
  .ui-table.ui-table--stack > tbody > tr > td[data-label]::before {
    content: attr(data-label) / ""; margin-right: var(--space-1); font-size: var(--text-xs);
  }
  /* The cells of a stacked row are separate boxes with gaps between them, so a tint on each
     would paint patches. The row paints one tint and the cells let it through. */
  .ui-table.ui-table--stack tbody tr.is-target:is(*, :hover) {
    background: color-mix(in srgb, var(--accent) 12%, transparent); /* code-bg: inherit — this translucent wash leaves the chip on its opaque ground. */
  }
  .ui-table.ui-table--stack tbody tr.is-target:is(*, :hover) > :is(td, th) { background: transparent; }
  /* A stacked row has no columns left to pin, stick or inset, and the identity's name is
     what the row is about — the fold hides it only because a pinned column is narrow. */
  .ui-table.ui-table--stack.ui-table--pinned > :where(thead, tbody) > tr > :where(.ui-table__identity, .ui-table__selection) {
    position: static; width: auto; min-width: 0; max-width: none;
    padding-inline: 0; border-right: 0; text-align: left;
    /* The cap's cut goes with the cap: a card is as wide as the row, so there is
       nothing to cut, and a clip box here would only reach a focused link's ring. */
    overflow: visible; text-overflow: clip;
  }
  /* The name is what the card is about, and a card has the width to wrap it. #500 put
     `nowrap` on it for the narrow column, so the stacked row takes that off too. */
  .ui-table.ui-table--stack.ui-table--pinned .ui-identity__name {
    position: static; width: auto; height: auto; max-width: none;
    overflow: visible; clip-path: none; white-space: normal; text-overflow: clip;
  }
  .ui-table.ui-table--stack.ui-table--pinned .ui-table__identity > * {
    overflow: visible; text-overflow: clip;
  }
  .ui-table.ui-table--stack.ui-table--pinned .ui-table__identity > * a {
    max-width: none; overflow: visible; text-overflow: clip;
  }
  .ui-table.ui-table--stack.ui-table--pinned .ui-table__identity > a:not([class]) {
    display: inline-block;
  }
  .ui-table.ui-table--stack.ui-table--pinned .ui-table__identity:not(.ui-table__linked):has(> a:focus-visible) {
    outline: none;
  }
  .ui-table.ui-table--stack.ui-table--pinned .ui-table__identity:not(.ui-table__linked) > a:focus-visible {
    outline: var(--ring);
    outline-offset: var(--ring-offset);
  }
  /* A card has no column to fill: every cell is a block on its own line and the ROW pays
     the inset, so the fill's padding would stand the link a step right of the card's text
     edge and the cell's `height: 1px` would hold a block cell to one pixel. Written through
     the row like the resets above it, so it outranks the fill and its density. */
  .ui-table.ui-table--stack > tbody > tr > td.ui-table__linked:has(> :is(a:not([class]), a.ui-identity):only-child) { height: auto; }
  .ui-table.ui-table--stack > tbody > tr > td.ui-table__linked > :is(a:not([class]), a.ui-identity):only-child {
    width: auto; height: auto; padding: 0;
  }
  /* The stacked card gives the link its own box again, so it takes the outset band. */
  .ui-table.ui-table--stack > tbody > tr > td.ui-table__linked > a:only-child:focus-visible {
    outline: var(--ring);
    outline-offset: var(--ring-offset);
  }
  /* The bleed now pays for the row's inset instead of the end cells', so the cells still
     start on the card's own text edge and the outline keeps its room on both sides. Same
     step, so the arithmetic is the one the sheet already does for a dense table above; these
     rules exist because a stacked table that is not dense gets no bleed from that one. A
     scroll wrapper owns the bleed when it is the card's child, and owes one step more than
     the table does because the wrapper keeps its own --space-1 of focus clearance. */
  .ui-card > .ui-table--stack {
    width: calc(100% + 2 * var(--space-3)); margin-inline: calc(-1 * var(--space-3));
  }
  .ui-card > .ui-table-scroll:has(> .ui-table--stack) {
    margin-inline: calc(-1 * var(--space-4));
  }
}
