/* ── Role editor: the permission matrix ───────────────────────────────────
   Forty-odd checkboxes in eight sections, so a whole role is visible at a
   glance — the question being answered is «what does this role add up to», not
   «what does line 27 say». Each section is its own panel with a select-all in
   its header (see [data-perm-section] in js/forms/permissions.js); the code itself is shown
   beside every entry, because that string is what the views and the docs refer
   to. */
.role-editor { display: flex; flex-direction: column; gap: 14px; }

/* A COLUMN FLOW, not a grid. `repeat(auto-fit, minmax(…, 1fr))` places each
   panel in a grid *cell*, and cells in a row are as tall as the tallest of them
   — with sections of two and of nine entries that left several hundred pixels
   of hole per row, and the page read as scattered rather than as eight lists.
   Multicol has no rows to align to, so the blocks pack tight; `break-inside:
   avoid` keeps a panel whole and `margin-bottom` is the gap (`gap` does not
   apply between multicol items). `.panel-pair` (components/panels.css) keeps the
   grid — two lists that must stay level with each other is the case grid is
   right for. */
.perm-sections {
  columns: 3 var(--panel-col);
  column-gap: 14px;
}
.perm-section {
  margin: 0 0 14px; break-inside: avoid; -webkit-column-break-inside: avoid;
}
.perm-section-head {
  display: flex; align-items: center; gap: 9px;
  padding-bottom: 9px; margin-bottom: 9px; border-bottom: 1px solid var(--border);
}
/* The section's own mark — the same glyph its screen wears in the sidebar, so a
   block is recognised before its label is read (Section.icon in catalog.py). */
.perm-section-head > .icon { width: 16px; height: 16px; flex: none; color: var(--accent-2); }
.perm-section-title { flex: 1 1 auto; min-width: 0; }
.perm-section-title span { font-weight: 600; font-size: 15px; }
.perm-section-count {
  font-family: var(--font-mono); font-size: 13px; font-weight: 700;
  white-space: nowrap; color: var(--text-strong);
}
.perm-section-of { color: var(--muted-2); font-weight: 500; margin-left: 2px; }
.perm-section-desc { font-size: 12.5px; margin: -2px 0 10px; }

.perm-list { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 2px; }
/* A row, not a bare label: the whole strip is the click target and tints when
   granted, so what a role holds is legible from the shape of the block and not
   only from a column of 16px boxes. Drawn by `:has(:checked)` — the same idiom
   the theme picker uses for its selection (see `.theme-tile:has(input:checked)`)
   — so the tint is the checkbox's own state rather than a class the server
   stamps on and JS has to keep in sync. */
.perm-row {
  margin: 0; padding: 6px 8px; border-radius: var(--radius);
  border: 1px solid transparent; transition: background .1s, border-color .1s;
}
.perm-row:hover { background: var(--panel-2); }
.perm-row:has([data-perm]:checked) {
  background: color-mix(in srgb, var(--accent) 10%, transparent);
  border-color: color-mix(in srgb, var(--accent) 26%, transparent);
}
/* Name and code on one line — the code repeats its section's prefix on every
   entry and had no business being a third stacked row of its own. */
.perm-label { display: flex; align-items: baseline; gap: 9px; width: 100%; }
.perm-name { flex: 1 1 auto; min-width: 0; font-size: 14px; }
.perm-code {
  flex: none; font-family: var(--font-mono); font-size: 10.5px;
  color: var(--muted-2); letter-spacing: .2px;
}
.perm-row:has([data-perm]:checked) .perm-code { color: var(--muted); }
.perm-help { font-size: 12px; color: var(--muted); margin: 3px 0 0 25px; line-height: 1.35; }

/* The headline over the matrix: how much of the catalogue this role carries.
   Live, unlike the access-group editor's reach — js/forms/permissions.js re-adds it up on every
   tick, because it counts the very boxes below it. */
.role-total { display: flex; align-items: center; gap: 18px; margin-top: 14px; }
.role-total-num {
  font-family: var(--font-mono); font-weight: 700; font-size: 34px; line-height: 1;
  letter-spacing: -1.5px; color: var(--text-strong); white-space: nowrap;
}
.role-total-of { font-size: 17px; color: var(--muted-2); margin-left: 6px; letter-spacing: 0; }
.role-total-bar { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 8px; }
.role-total-sub { margin: 0; font-size: 12.5px; color: var(--muted); }

/* ── Admin card grid (roles, access groups) ────────────────────────────────
   A card per record, at every width — unlike `.list-cards`, which is the mobile
   fallback under a table. These two lists hold a handful of rows each, and a
   four-column table over three of them was mostly empty header: 700px of blank
   first column, and «41 / 43» as the answer to «how much is this role». The
   card gives the meter room and puts the actions where they can be hit.

   The whole card is clickable via [data-href] (js/lists/rows.js), which skips clicks that
   land on a control — so the delete button inside stays a real button rather
   than a link nested inside a link. */
.admin-grid {
  display: grid; gap: 14px; list-style: none; padding: 0; margin: 0;
  grid-template-columns: repeat(auto-fill, minmax(330px, 1fr));
}
.admin-card {
  display: flex; flex-direction: column; gap: 11px; margin: 0; padding: 15px 16px;
  background: var(--panel); border: 1px solid var(--border);
  border-left: 3px solid var(--accent-2); border-radius: var(--radius);
  transition: border-color .12s, background .12s;
}
.admin-card:hover { background: var(--panel-2); border-color: var(--accent-2); }
/* An empty list is one message, not a card — it spans the whole grid. */
.admin-grid-empty { grid-column: 1 / -1; }

.admin-card-head {
  display: flex; align-items: flex-start; justify-content: space-between;
  flex-wrap: wrap; gap: 6px 10px;
}
.admin-card-ident { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.admin-card-name {
  font-size: 16px; font-weight: 600; color: var(--text-strong); text-decoration: none;
}
.admin-card:hover .admin-card-name { color: var(--accent-2); }
.admin-card-code {
  font-family: var(--font-mono); font-size: 11px; color: var(--muted-2); letter-spacing: .5px;
}
/* Fixed two lines: the descriptions differ in length by a factor of three, and
   cards whose feet sit at four different heights read as an accident. */
.admin-card-desc {
  margin: 0; font-size: 13px; line-height: 1.4; color: var(--muted);
  display: -webkit-box; -webkit-line-clamp: 2; line-clamp: 2;
  -webkit-box-orient: vertical; overflow: hidden; min-height: 2.8em;
}
.admin-card-meter { margin-top: auto; }
/* The access-group card's counts — no «out of how many» to be a share of, so
   plain numbers where the role card has its bar. */
.admin-card-stats { display: flex; gap: 26px; margin-top: auto; }
.admin-card-stat-cell { display: flex; flex-direction: column; gap: 3px; }
.admin-card-num {
  font-family: var(--font-mono); font-weight: 700; font-size: 22px; line-height: 1;
  letter-spacing: -.5px; color: var(--text-strong);
}
.admin-card-num.empty { color: var(--muted-2); }

.admin-card-foot {
  display: flex; align-items: center; justify-content: space-between;
  flex-wrap: wrap; gap: 8px 12px;
  padding-top: 11px; border-top: 1px solid var(--border);
}
.admin-card-stat {
  display: inline-flex; align-items: center; gap: 7px;
  font-size: 12.5px; color: var(--text);
}
.admin-card-stat .icon { width: 14px; height: 14px; flex: none; color: var(--muted-2); }
