/* app/set-people.css — page-local styles for Users + Teams + Security.
   Prefix every selector `.e8-set-people-`. Shared grammar lives in app/set-core.css and must not
   be duplicated here; if a page needs a new shared primitive, that is a core change, not a
   local override. Tokens only — no hex, no raw font sizes.

   WHAT THIS FILE IS ACTUALLY FOR: the Users table. Teams and Security are pure primitive
   compositions and contribute four small rules between them (the chips, the empty-state height and
   the inline error). Everything below the table section is that.

   THE ONE STRUCTURAL DECISION — WHY THE TABLE SITS INSIDE A PADDED WRAPPER.
   A card's row dividers must be INSET to the card padding; an edge-to-edge hairline is a named
   failure mode in docs/SETTINGS-REFERENCE.md. In a <table> that is awkward: `border-top` on a cell
   spans the whole cell, and the first cell starts at the card's left edge, so the line reaches the
   edge no matter what padding the cell carries.

   So the padding lives on the WRAPPER (`padding: 0 var(--set-card-pad-x)`), which makes the table's
   content box start and end exactly at the card's padding — and every `border-top` inside it is
   then inset for free, with no pseudo-elements and no `position: relative` on a <tr> (which is not
   reliably a containing block).

   That leaves one thing the wrapper padding gets WRONG: the collapsible group header must be a
   FULL-BLEED tinted strip, and inside the padded wrapper it would be inset with white gutters. It
   is fixed with two zero-blur, zero-spread offset shadows (`±var(--set-card-pad-x) 0 0`) which
   paint copies of the cell into the two gutters. A `spread` would have done it in one declaration
   and bled vertically into the rows above and below; offsets cannot.

   Keeping the padding on the wrapper rather than the cells is also what lets the whole table
   restack into one block per person below 640px without a single padding number changing.

   Every dimension is read from set-core's own custom properties (`--set-row-pad-y`,
   `--set-card-pad-x`, `--set-line`, `--set-tint`), declared once on `.e8-set`. A table row here is
   therefore the same 16px/20px box as a `.e8-set-row` on any other Settings page, and it cannot
   drift without set-core drifting first. */

/* ---- the roster table ------------------------------------------------------------------------ */
.e8-set-people-tablewrap {
  padding: 0 var(--set-card-pad-x);
  overflow-x: auto;
}

/* `table-layout: fixed` so the four right-hand columns are the same width on every row regardless
   of content, and the name column absorbs the remainder. `min-width` is what makes the wrapper
   scroll instead of crushing the roles select, in the band between 641px and roughly 700px where
   the table is still a table but the column is wider than the card. Below 640 the table stops
   being a table entirely and there is nothing left to scroll — see the narrow block at the foot of
   this file. */
.e8-set-people-table {
  width: 100%;
  min-width: 660px;
  border-collapse: collapse;
  table-layout: fixed;
}
.e8-set-people-table th,
.e8-set-people-table td {
  padding: var(--set-row-pad-y) var(--ui-space-4) var(--set-row-pad-y) 0;
  text-align: left;
  vertical-align: middle;
}
.e8-set-people-table th:last-child,
.e8-set-people-table td:last-child {
  padding-right: 0;
  text-align: right;
}
.e8-set-people-table thead th {
  padding-top: var(--ui-space-3);
  padding-bottom: var(--ui-space-3);
  border-bottom: 1px solid var(--set-line);
  font-size: var(--ui-text-sm);
  font-weight: 500;
  color: var(--ui-text-tertiary);
  white-space: nowrap;
}
/* No line above the first body row and none below the last — the same `+` mechanism set-core uses
   for its own inset dividers, so the two agree by construction. */
.e8-set-people-table tbody tr + tr td {
  border-top: 1px solid var(--set-line);
}
.e8-set-people-table tbody tr:hover {
  background: color-mix(in srgb, var(--ui-fill) 45%, transparent);
}

/* Column widths. Only the name column is unspecified, so it takes what is left. */
.e8-set-people-c-status { width: 116px; }
.e8-set-people-c-roles { width: 208px; }
.e8-set-people-c-joined { width: 104px; }
.e8-set-people-c-act { width: 52px; }

/* ---- the collapsible group header -------------------------------------------------------------- */
.e8-set-people-grouprow td {
  padding: 0;
  background: var(--set-tint);
  /* full-bleed: two offset copies fill the wrapper's left and right padding. */
  box-shadow: calc(-1 * var(--set-card-pad-x)) 0 0 var(--set-tint),
              var(--set-card-pad-x) 0 0 var(--set-tint);
}
.e8-set-people-grouptog {
  display: flex;
  align-items: center;
  gap: var(--ui-space-2);
  width: 100%;
  padding: var(--ui-space-3) 0;
  border: 0;
  background: transparent;
  font: inherit;
  font-size: var(--ui-text-base);
  color: var(--ui-text);
  text-align: left;
  cursor: pointer;
}
.e8-set-people-caret {
  font-size: var(--ui-icon-sm);
  color: var(--ui-text-tertiary);
  transition: transform 140ms cubic-bezier(0.2, 0, 0, 1);
}
.e8-set-people-grouptog[aria-expanded="false"] .e8-set-people-caret {
  transform: rotate(-90deg);
}
.e8-set-people-groupname {
  font-weight: 600;
}

/* ---- the name cell ------------------------------------------------------------------------------
   One line, never two: a wrapping email would make row heights uneven down the table, which reads
   as the rhythm drift this surface is judged on. The address ellipsizes and keeps its full value in
   a title attribute instead. */
.e8-set-people-person {
  display: flex;
  align-items: center;
  gap: var(--ui-space-3);
  min-width: 0;
}
.e8-set-people-ident {
  display: flex;
  align-items: baseline;
  gap: var(--ui-space-2);
  min-width: 0;
  flex-wrap: nowrap;
}
.e8-set-people-nm {
  flex: none;
  font-size: var(--ui-text-md);
  font-weight: 500;
  color: var(--ui-text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.e8-set-people-em {
  min-width: 0;
  font-size: var(--ui-text-base);
  color: var(--ui-text-secondary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.e8-set-people-you {
  flex: none;
  padding: 1px var(--ui-space-2);
  border-radius: var(--ui-radius-pill);
  background: var(--ui-wash);
  color: var(--ui-daybreak-text);
  font-size: var(--ui-text-xs);
  font-weight: 600;
}

/* The avatar is a 30px sibling of set-core's 36px `.e8-set-glyph` — same family, one step down,
   because it sits in a table cell rather than leading a card row. The eight tints are the shared
   `--ui-cat-*` pairs, chosen by a hash of the person's name, so they invert with the theme and no
   colour is written here at all. */
.e8-set-people-avatar {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  border-radius: var(--ui-radius-md);
  background: var(--ui-fill);
  color: var(--ui-text-secondary);
  font-size: var(--ui-text-sm);
  font-weight: 600;
  letter-spacing: 0.01em;
}
.e8-set-people-avatar.is-c1 { background: var(--ui-cat-1-bg); color: var(--ui-cat-1-text); }
.e8-set-people-avatar.is-c2 { background: var(--ui-cat-2-bg); color: var(--ui-cat-2-text); }
.e8-set-people-avatar.is-c3 { background: var(--ui-cat-3-bg); color: var(--ui-cat-3-text); }
.e8-set-people-avatar.is-c4 { background: var(--ui-cat-4-bg); color: var(--ui-cat-4-text); }
.e8-set-people-avatar.is-c5 { background: var(--ui-cat-5-bg); color: var(--ui-cat-5-text); }
.e8-set-people-avatar.is-c6 { background: var(--ui-cat-6-bg); color: var(--ui-cat-6-text); }
.e8-set-people-avatar.is-c7 { background: var(--ui-cat-7-bg); color: var(--ui-cat-7-text); }
.e8-set-people-avatar.is-c8 { background: var(--ui-cat-8-bg); color: var(--ui-cat-8-text); }

/* ---- the roles cell ------------------------------------------------------------------------------
   The control is set-core's Select, untouched, and it SIZES TO ITS CONTENT like every other select
   on this surface.

   It used to be `width: 100%`, which stretched it to a flat 192px in every row — a fixed control
   width is a named failure mode in docs/SETTINGS-REFERENCE.md (§4.4), and the cost was visible:
   an unassigned row read as an empty 192px box with "Select roles" adrift at its left edge.
   `max-width` instead of `width` lets the native <select> take its intrinsic width — the widest
   option plus the chevron — while still being unable to escape the column. Every row lands on the
   same width anyway, because every row carries the same option list; that uniformity is now a
   property of the DATA rather than a number typed into this file, so a longer custom role widens
   the column's controls together instead of ellipsing inside a box that will not grow.

   Deliberately NOT `overflow: hidden` on the cell to contain a long role: the focus ring is a
   box-shadow, and clipping it would trade a fixed width for a missing focus state. The select's own
   `max-width` + `text-overflow: ellipsis` (both set-core's) already keep it inside the column.

   The only other local rule is the placeholder tone the reference asks for: tertiary ink while
   nothing is assigned, primary once a role is. */
.e8-set-people-roles .e8-set-select { max-width: 100%; }
.e8-set-people-roles.is-empty .e8-set-select select { color: var(--ui-text-tertiary); }

/* The per-cell column name. Off at full width — where the <thead> is on screen and the <th>→<td>
   association is intact — and therefore out of the accessibility tree too, so nothing is announced
   twice. The narrow block at the foot of this file turns it on. */
.e8-set-people-cellab { display: none; }

.e8-set-people-joined {
  font-size: var(--ui-text-base);
  color: var(--ui-text-secondary);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* ---- the hover-revealed delete --------------------------------------------------------------------
   Hidden by OPACITY, never by `display`, `visibility` or `pointer-events`: all three would take the
   button out of the tab order or out of hit testing, and the reference requires this action to be
   keyboard-complete. It is in the DOM and focusable at all times; `:focus-within` on the row paints
   it the instant focus lands anywhere in that row, including on the role select on the way to it.
   A pointer-less device never fires :hover, so it is simply always visible there. */
.e8-set-people-del {
  display: inline-flex;
  opacity: 0;
  transition: opacity 120ms ease;
}
.e8-set-people-table tbody tr:hover .e8-set-people-del,
.e8-set-people-table tbody tr:focus-within .e8-set-people-del {
  opacity: 1;
}
/* Tertiary at rest per the reference; the danger tone is the hover/focus answer, not the default. */
.e8-set-people-del .e8-set-btn.is-danger {
  width: 34px;
  padding: 0;
  color: var(--ui-text-tertiary);
}
.e8-set-people-del .e8-set-btn.is-danger:hover:not(:disabled),
.e8-set-people-del .e8-set-btn.is-danger:focus-visible {
  color: var(--ui-danger);
}

.e8-set-people-note {
  margin: var(--ui-space-4) 0 0;
  font-size: var(--ui-text-sm);
  line-height: 1.5;
  color: var(--ui-text-tertiary);
}
.e8-set-people-note strong { font-weight: 600; color: var(--ui-text-secondary); }

/* ---- composers (invite / new team / new role) ----------------------------------------------------
   Each composer is a card head carrying its two buttons plus one labelled row per field, so no
   control is left to be explained by the field next to it. `.e8-set-cardhead-act` is a plain
   `flex: none` box, so the button pair needs its own gap; nothing else about the head changes. */
.e8-set-people-acts {
  display: inline-flex;
  align-items: center;
  gap: var(--ui-space-2);
}

/* A row's right slot is `flex: none`, so a control set wider than the space beside its label pushes
   the row into overflow instead of shrinking. Only the Security role row still has three controls
   in one slot; letting the slot wrap is the whole fix. */
.e8-set-people-invite .e8-set-row-ctl,
.e8-set-people-teamform .e8-set-row-ctl,
.e8-set-people-roleform .e8-set-row-ctl {
  flex-wrap: wrap;
  justify-content: flex-end;
  row-gap: var(--ui-space-2);
}
.e8-set-people-err {
  display: block;
  margin-top: var(--ui-space-2);
  font-size: var(--ui-text-base);
  color: var(--ui-danger);
}

/* ---- teams -------------------------------------------------------------------------------------- */
.e8-set-people-emptycard {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 420px;
}
.e8-set-people-chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--ui-space-2);
  margin-top: var(--ui-space-3);
}
.e8-set-people-chip {
  display: inline-flex;
  align-items: center;
  gap: var(--ui-space-1);
  padding: 2px var(--ui-space-2) 2px var(--ui-space-3);
  border: 1px solid var(--set-line);
  border-radius: var(--ui-radius-pill);
  background: var(--ui-surface);
  font: inherit;
  font-size: var(--ui-text-sm);
  color: var(--ui-text-secondary);
  cursor: pointer;
}
.e8-set-people-chip .material-symbols-outlined {
  font-size: var(--ui-icon-xs);
  color: var(--ui-text-tertiary);
}
.e8-set-people-chip:hover {
  border-color: color-mix(in srgb, var(--ui-danger) 40%, transparent);
  color: var(--ui-danger);
}
.e8-set-people-chip:hover .material-symbols-outlined { color: var(--ui-danger); }

/* ---- narrow --------------------------------------------------------------------------------------
   AFTER every rule these override, per CLAUDE.md: a conditional at-rule adds no specificity, so a
   @media block written above its own base rule is dead in every state.

   AT 390 THE TABLE STOPS BEING A TABLE. Five columns do not fit 346px of card interior, and the
   previous answer — keep all five and scroll the wrapper — measured badly: the wrapper was 346px
   around a 560px table, so rows were cut mid-word at the card border with no fade, shadow or hint
   that a swipe existed, and both the Joined column and the delete button sat entirely off-screen.
   Reference failure mode 11 asks for rows that stack label-over-control at this width and for
   controls not to overflow, so that is what this does: one block per person, five facts visible,
   and no horizontal scroll anywhere on the page.

   THE TRADE, STATED. Only `display` changes — the <table>/<tr>/<td> markup is the same at every
   width — which means the table's own semantics (the <th>→<td> association) are dropped here along
   with the header row. Each cell therefore carries its column name as REAL TEXT in
   `.e8-set-people-cellab`, switched on only here, so both a sighted reader and a screen reader get
   the pairing the <thead> used to supply. Generated content from a `data-label` would have looked
   identical and been announced by roughly half of screen readers, which at the one width where
   nothing else names these values is the wrong half to bet on.

   The card padding stays on the WRAPPER, so the tinted group header keeps its full-bleed strip
   (the two offset shadows still land in the wrapper's gutters) and every stacked cell is still
   inset to exactly the card padding, unchanged from the desktop layout. */
@media (max-width: 640px) {
  .e8-set-people-tablewrap { overflow-x: visible; }
  .e8-set-people-table { display: block; min-width: 0; table-layout: auto; }
  .e8-set-people-table thead { display: none; }
  .e8-set-people-table tbody,
  .e8-set-people-table tbody tr { display: block; }
  .e8-set-people-table td { display: block; width: auto; padding: 0; }

  /* The hairline moves from the cells to the block, so one person reads as one unit rather than as
     four stacked rules. Same `+` mechanism, so still none above the first and none below the last. */
  .e8-set-people-table tbody tr + tr td { border-top: 0; }
  .e8-set-people-table tbody tr + tr { border-top: 1px solid var(--set-line); }
  .e8-set-people-row { position: relative; padding: var(--set-row-pad-y) 0; }

  /* The person keeps the first line to themselves and the delete parks at its right, which is the
     only cell that has to leave the flow — stacking it would give every person a spare line for one
     glyph. `position: relative` is safe on a <tr> ONLY because it is a block box here; on a real
     table row it is not reliably a containing block, which is why the desktop layout never uses it.
     Hover-reveal is dropped at this width: there is no hover on the devices that get it, and a
     hover-capable 390px window would otherwise hide the row's only action. */
  .e8-set-people-row .e8-set-people-c-name { padding-right: 40px; }
  .e8-set-people-row .e8-set-people-c-act { position: absolute; top: var(--set-row-pad-y); right: 0; }
  .e8-set-people-del { opacity: 1; }

  /* Status and Joined are one short value each, so they read label-left/value-right. Roles cannot:
     set-core takes every select to 100% width below 640, so its label has to sit ABOVE the control
     — which is the label-over-control shape the reference asks for in the first place. */
  .e8-set-people-cellab {
    display: block;
    font-size: var(--ui-text-base);
    color: var(--ui-text-secondary);
  }
  .e8-set-people-row .e8-set-people-c-status,
  .e8-set-people-row .e8-set-people-c-joined {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--ui-space-3);
    margin-top: var(--ui-space-3);
  }
  .e8-set-people-row .e8-set-people-c-roles { margin-top: var(--ui-space-3); }
  .e8-set-people-row .e8-set-people-c-roles .e8-set-people-cellab { margin-bottom: var(--ui-space-2); }

  /* set-core stacks a row's control under its text below 640px, which already gives the composers
     a full-width slot; the wrap rule above then has nothing left to do. */
  .e8-set-people-invite .e8-set-row-ctl,
  .e8-set-people-teamform .e8-set-row-ctl,
  .e8-set-people-roleform .e8-set-row-ctl {
    justify-content: flex-start;
  }
  /* set-core's card head does not stack, so a title plus two buttons squeezes at 390. Wrapping the
     head is not enough on its own — `.e8-set-cardhead-txt` is `flex: 1; min-width: 0`, so it
     shrinks to nothing rather than pushing the buttons down. Giving the action box a full-width
     basis is what actually forces the break. */
  .e8-set-people-invite .e8-set-cardhead,
  .e8-set-people-teamform .e8-set-cardhead {
    flex-wrap: wrap;
    row-gap: var(--ui-space-3);
  }
  .e8-set-people-invite .e8-set-cardhead-act,
  .e8-set-people-teamform .e8-set-cardhead-act { width: 100%; }
  .e8-set-people-emptycard { min-height: 340px; }
}

/* A device with no pointer never fires :hover, so a hover-revealed control would be permanently
   invisible there. */
@media (hover: none) {
  .e8-set-people-del { opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  .e8-set-people-del,
  .e8-set-people-caret { transition: none; }
}
