/* ============================================================
   Awall surface stylesheet: overrides.css
   Split from styles.css (F1, issue #186) — NO rule changes.
   Owns: MIXED late-additions tail -> org-switcher (S1), workspace/members/invitations (S9), impersonation banner (S1), owner-picker (S5), logs-owner col (S3), memory dashboard (S12). PRIMARY CONSOLIDATION TARGET.
   Concatenating every surfaces/*.css in base.html <link> order
   reproduces the original styles.css byte-for-byte.
   ============================================================ */
/* ── Admin top strip + org switcher (ORG-04) ─────────────────────────── */
/* Switcher sits at the start (left) so it does not collide with the
   position:fixed theme-toggle pinned to the viewport's top-right corner. */
.admin-topstrip {
  display: flex;
  justify-content: flex-start;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-6);
  background: var(--color-surface);
}

.org-switcher {
  position: relative;
}

.org-switcher__trigger {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: 6px 10px;
  font: inherit;
  font-size: var(--font-size-sm);
  color: var(--color-text-heading);
  background: var(--color-elevated);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-btn);
  cursor: pointer;
  transition: border-color 120ms ease, background-color 120ms ease;
}

.org-switcher__trigger:hover,
.org-switcher__trigger:focus-visible {
  border-color: var(--color-text-muted);
}

.org-switcher__trigger[aria-expanded="true"] {
  border-color: var(--color-text-heading);
}

.org-switcher__label {
  font-size: var(--font-size-xs);
  font-weight: 500;
  color: var(--color-text-muted);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.org-switcher__current {
  font-weight: 600;
  max-width: 24ch;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.org-switcher__chevron {
  color: var(--color-text-muted);
  transition: transform 150ms ease;
}

.org-switcher__trigger[aria-expanded="true"] .org-switcher__chevron {
  transform: rotate(180deg);
}

.org-switcher__menu {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  min-width: 240px;
  max-height: 60vh;
  overflow-y: auto;
  padding: 4px 0;
  background: var(--color-elevated);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-btn);
  box-shadow: var(--shadow-lift);
  z-index: var(--z-dropdown);
}

.org-switcher__menu[hidden] { display: none; }

.org-switcher__item-form {
  margin: 0;
  padding: 0;
}

.org-switcher__item {
  display: block;
  width: 100%;
  padding: 8px 12px;
  font: inherit;
  font-size: var(--font-size-sm);
  text-align: left;
  color: var(--color-text-body);
  background: transparent;
  border: 0;
  cursor: pointer;
  text-decoration: none;
}

.org-switcher__item:hover,
.org-switcher__item:focus-visible {
  background: var(--color-border-soft);
  color: var(--color-text-heading);
}

.org-switcher__item.is-active {
  color: var(--color-text-heading);
  font-weight: 600;
}

.org-switcher__item--all {
  font-style: italic;
}

.org-switcher__item--create {
  color: var(--color-text-muted);
  font-weight: 500;
}

.org-switcher__divider {
  height: 1px;
  margin: 4px 0;
  background: var(--color-border-soft);
}

/* Mobile variant — compact, no uppercase label. */
/* Mobile: hide the "Organization" word visually but keep it in the a11y
   tree so the trigger's accessible name stays "Organization <current>". */
.org-switcher--compact .org-switcher__label {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}
.org-switcher--compact .org-switcher__current { max-width: 16ch; }

/* The compact trigger sits mid-topbar, so a left-anchored menu pushes off
   the right edge on narrow screens (#208). Center the panel on its trigger
   and cap its width to the viewport so it can never overflow. */
.org-switcher--compact .org-switcher__menu {
  left: 50%;
  right: auto;
  transform: translateX(-50%);
  max-width: calc(100vw - var(--space-4));
}

/* ---------------------------------------------------------
   Workspace page — manager-only /workspace/ surface.
   Four .card.settings-card sections stacked with shared
   vertical rhythm. Sub-sections live inside a single card
   so we never nest cards.
   --------------------------------------------------------- */
.workspace-sections {
  display: flex;
  flex-direction: column;
  gap: var(--space-6);
}

.workspace-sections > .settings-card {
  max-width: none;
  scroll-margin-top: var(--space-6);
}

.workspace-reveal-card {
  margin-bottom: var(--space-6);
}

/* Sub-section inside a workspace card (e.g. "Pending invitations" below
   the create-invitation form). Hairline divider keeps the boundary
   visible without nested cards. */
.workspace-subsection {
  margin-top: var(--space-8);
  padding-top: var(--space-6);
  border-top: 1px solid var(--color-border);
}

.workspace-subsection-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  margin-bottom: var(--space-4);
}

.card-subsection-title {
  font-size: var(--font-size-sm);
  font-weight: 600;
  color: var(--color-text-heading);
  margin: 0;
}

/* Danger-zone modifier: hairline danger-tinted border + danger-toned
   section title. Stays inside the Hairline Rule (1px). */
.settings-card--danger {
  border-color: var(--color-danger-border-soft);
}

.settings-card--danger > .card-section-title {
  color: var(--color-danger-strong);
}

.danger-zone-checklist {
  margin: calc(-1 * var(--space-2)) 0 var(--space-6) var(--space-4);
  padding-left: var(--space-3);
  font-size: var(--font-size-sm);
  color: var(--color-text-muted);
  line-height: 1.6;
  list-style: disc outside;
}

.danger-zone-checklist li + li {
  margin-top: var(--space-1);
}

/* Role cell (S9 #105): the role chip plus a one-line capability hint so
   "who can do what" reads at a glance, scoped to the org in the page title.
   The auto-width name column absorbs the wider role column. */
.member-role {
  display: inline-flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-1);
}

.member-role-hint {
  font-size: var(--font-size-xs);
  color: var(--color-text-muted);
  line-height: 1.3;
}

/* Members table — column widths sized for the manager workspace surface
   (no Actions header label; the column is rightmost and width-capped). */
.data-table--workspace-members col.col-name      { width: auto; }
.data-table--workspace-members col.col-role      { width: 16ch; }
.data-table--workspace-members col.col-status    { width: 11ch; }
.data-table--workspace-members col.col-joined    { width: 14ch; }
.data-table--workspace-members col.col-last      { width: 17ch; }
.data-table--workspace-members col.col-actions   { width: 64px; }

/* Invitations table — column widths. */
.data-table--invitations col.col-token     { width: 16ch; }
.data-table--invitations col.col-uses      { width: 9ch; }
.data-table--invitations col.col-expires   { width: 17ch; }
.data-table--invitations col.col-creator   { width: 16ch; }
.data-table--invitations col.col-actions   { width: 64px; }

/* Right-align the row-actions trigger inside its cell so the dropdown
   anchors to the table's right edge. Shared by both workspace tables. */
.row-actions-cell {
  text-align: right;
}

.row-actions-cell .row-actions {
  display: inline-flex;
}

/* Visual stand-in for the owner row, where no action menu is shown.
   Matches the .log-time-empty muted vocabulary. */
.row-actions-placeholder {
  font-family: var(--font-mono);
  font-size: var(--font-size-xs);
  color: var(--color-text-muted);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

/* The Actions column has no visible header label (the action UI is
   self-explanatory). Keep the th present for a11y, hide the text. */
.col-actions-th {
  width: 64px;
}

/* === Impersonation banner (IMP-05) =============================
   Fixed security strip shown when ``request.user.is_hijacked``.
   Slot rendered inside ``.app-layout`` above the page content.

   Position model: ``.app-layout`` is a flex row whose sidebar and
   mobile-topbar are ``position: fixed`` (out of flow). Pinning the
   banner with ``position: fixed`` keeps it on top of the scroll,
   independent of the main-content scroll position, and dodges the
   sidebar offset cleanly across viewport widths.

   Desktop (≥ 768px): pinned to ``top: 0`` and offset by the current
   sidebar width via ``--sidebar-width-current`` (the same token the
   main-content margin uses, so the banner tracks collapse/expand).
   Mobile (< 768px): the ``.mobile-topbar`` already owns ``top: 0``;
   the banner stacks directly below it.

   Tokens:
     surface  — ``--color-danger-bg``
     ink      — ``--color-danger-strong`` (Strong-Semantic Rule)
     border   — ``--color-danger-border-soft`` (Hairline Rule)
     button   — Block Wash → Block Red invert on hover
   Calm-over-Alarm (PRODUCT.md): one calm strip, no animation
   beyond a short opacity fade-in for first paint.
   ================================================================ */

.imp-banner {
  position: fixed;
  top: 0;
  left: var(--sidebar-width-current);
  right: 0;
  z-index: 70;
  background: var(--color-danger-bg);
  color: var(--color-danger-strong);
  border-bottom: 1px solid var(--color-danger-border-soft);
  box-shadow: var(--shadow-card);
  padding-top: env(safe-area-inset-top, 0);
  animation: imp-banner-fade-in 180ms var(--ease-out, ease-out) both;
}

/* Mobile: the ``.mobile-topbar`` (height 56px, z-index 90) sits at
   ``top: 0``; the banner slips below it and the main-content's
   existing 56px top padding extends to clear both. */
@media (max-width: 768px) {
  .imp-banner {
    top: 56px;
    left: 0;
    right: 0;
  }
}

/* When the banner is rendered, push the main-content down so the
   first row of page content is not occluded. Uses ``:has()`` which
   is universally supported on the modern Chromium / WebKit / Gecko
   versions Awall targets. The 52px figure is the banner's resting
   single-row height (12px padding + 28px inner + 12px padding). */
.app-layout:has(.imp-banner) .main-content {
  padding-top: 52px;
}

@media (max-width: 768px) {
  .app-layout:has(.imp-banner) .main-content {
    padding-top: calc(56px + 52px);
  }
  /* Push the sidebar drawer below the banner on mobile so the dot
     and the timer remain visible when the drawer is open. */
  .app-layout:has(.imp-banner) .sidebar {
    padding-top: 52px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .imp-banner { animation: none; }
}

@keyframes imp-banner-fade-in {
  from { opacity: 0; transform: translateY(-2px); }
  to   { opacity: 1; transform: none; }
}

.imp-banner__inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-6);
  /* Reserve right-edge room for the fixed ``.theme-toggle`` (top: 16px,
     right: 24px, ~40px wide) that floats above every page. The toggle
     lives outside the banner DOM and at z-index 200 (banner is 70), so
     without this clearance it covers the *Stop impersonating* button on
     viewports where the banner shares its top stripe. The mobile
     ``@media (max-width: 640px)`` rule below resets the padding shorthand
     and drops this reservation — on mobile the banner sits below the
     ``.mobile-topbar`` and the toggle is the topbar's overlap, not the
     banner's. */
  padding-right: calc(var(--space-6) + var(--touch-target-min) + var(--space-3));
  max-width: 100%;
}

.imp-banner__dot {
  flex: 0 0 auto;
  width: 8px;
  height: 8px;
  border-radius: var(--radius-pill);
  background: var(--color-danger);
  box-shadow: 0 0 0 3px var(--color-danger-soft);
}

.imp-banner__eyebrow {
  flex: 0 0 auto;
  font-family: var(--font-mono);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--color-danger-strong);
}

.imp-banner__body {
  display: inline-flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-1);
  min-width: 0;
  font-size: var(--font-size-sm, 14px);
  line-height: 1.5;
  color: var(--color-danger-strong);
}

.imp-banner__name {
  font-family: var(--font-mono);
  font-weight: 700;
  max-width: 22ch;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  vertical-align: bottom;
}

.imp-banner__role {
  font-family: var(--font-mono);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.02em;
  opacity: 0.85;
}

.imp-banner__sep {
  opacity: 0.55;
  padding: 0 var(--space-1);
}

.imp-banner__on-behalf {
  opacity: 0.85;
}

.imp-banner__timer {
  flex: 0 0 auto;
  margin-left: auto;
  font-family: var(--font-mono);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  padding: 4px 10px;
  border-radius: var(--radius-pill);
  background: var(--color-danger-soft);
  color: var(--color-danger-strong);
  white-space: nowrap;
}

.imp-banner__form {
  margin: 0;
  flex: 0 0 auto;
}

.imp-banner__stop {
  font: inherit;
  font-size: var(--font-size-sm, 14px);
  font-weight: 600;
  line-height: 1;
  padding: 8px 16px;
  border-radius: var(--radius-btn);
  background: var(--color-danger-bg);
  color: var(--color-danger-strong);
  border: 1px solid var(--color-danger-border-soft);
  cursor: pointer;
  transition: background-color var(--transition-fast, 120ms ease),
              color var(--transition-fast, 120ms ease),
              border-color var(--transition-fast, 120ms ease);
}

.imp-banner__stop:hover {
  background: var(--color-danger);
  color: #ffffff;
  border-color: var(--color-danger);
}

.imp-banner__stop:focus-visible {
  outline: none;
  border-color: var(--color-danger);
  box-shadow: 0 0 0 3px var(--color-danger-border-soft);
}

.imp-banner__stop:active {
  transform: translateY(1px);
}

@media (max-width: 640px) {
  .imp-banner__inner {
    gap: var(--space-2);
    padding: var(--space-3) var(--space-4);
  }
  .imp-banner__timer {
    margin-left: 0;
  }
  .imp-banner__name {
    max-width: 14ch;
  }
}

@media (max-width: 360px) {
  .imp-banner__sep,
  .imp-banner__on-behalf {
    display: none;
  }
}

/* ── Owner picker (#145): avatar combobox with server-side member search ── */
.owner-picker { position: relative; }

.owner-picker__trigger {
  width: 100%;
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-3);
  background: var(--color-bg);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-input);
  cursor: pointer;
  text-align: left;
  transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
}
.owner-picker__trigger:hover { border-color: var(--color-border); }
.owner-picker__trigger:focus-visible,
.owner-picker__trigger[aria-expanded="true"] {
  outline: none;
  border-color: var(--color-primary);
  box-shadow: 0 0 0 3px var(--color-primary-focus-ring);
}

.owner-picker__avatar {
  flex: 0 0 auto;
  width: 30px;
  height: 30px;
  border-radius: var(--radius-pill);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--color-primary-soft);
  color: var(--color-primary);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.02em;
}

.owner-picker__chosen {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  line-height: 1.3;
}
.owner-picker__name {
  color: var(--color-text-heading);
  font-weight: 500;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.owner-picker__email {
  color: var(--color-text-muted);
  font-size: 12px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.owner-picker__you { color: var(--color-text-muted); font-weight: 400; }
.owner-picker__caret {
  flex: 0 0 auto;
  color: var(--color-text-muted);
  transition: transform var(--transition-fast);
}
.owner-picker__trigger[aria-expanded="true"] .owner-picker__caret { transform: rotate(180deg); }

.owner-picker__popover {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  right: 0;
  background: var(--color-bg);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-input);
  box-shadow: var(--shadow-modal);
  z-index: 100;
  overflow: hidden;
  animation: owner-picker-pop 140ms var(--ease-out) both;
}
@keyframes owner-picker-pop {
  from { opacity: 0; transform: translateY(-4px); }
  to   { opacity: 1; transform: translateY(0); }
}

.owner-picker__search {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  border-bottom: 1px solid var(--color-border);
  color: var(--color-text-muted);
}
.owner-picker__search-input {
  flex: 1 1 auto;
  border: none;
  background: transparent;
  outline: none;
  font-size: var(--font-size-base);
  font-family: var(--font-sans);
  color: var(--color-text-heading);
}
.owner-picker__search-input::placeholder { color: var(--color-text-muted); }

.owner-picker__results {
  list-style: none;
  margin: 0;
  padding: var(--space-1);
  max-height: 264px;
  overflow-y: auto;
}
.owner-picker__option {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-2);
  border-radius: var(--radius-btn);
  cursor: pointer;
}
.owner-picker__option.is-active { background: var(--color-primary-light); }

.owner-picker__empty {
  margin: 0;
  padding: var(--space-3);
  color: var(--color-text-muted);
  font-size: 13px;
  text-align: center;
}

/* Logs table: owner shown under the key name (#42). */
.log-key-name { display: block; }
.log-key-owner {
  display: block;
  color: var(--color-text-muted);
  font-size: 12px;
}


/* ---------------------------------------------------------
   22. Memory dashboard (#137)
   --------------------------------------------------------- */
.memory-markdown { line-height: 1.55; }
.memory-markdown h1, .memory-markdown h2, .memory-markdown h3 { margin-top: var(--space-4); }
.memory-markdown pre,
.memory-markdown code {
  background: var(--color-surface-soft);
  border-radius: 4px;
  padding: 0 4px;
  font-family: "JetBrains Mono", monospace;
  font-size: 0.92em;
}
.memory-markdown pre { padding: 12px; overflow-x: auto; }

.memory-fact-list { list-style: none; padding: 0; margin: 0; }
.memory-fact-list li { padding: var(--space-3) 0; border-bottom: 1px solid var(--color-border-soft); }
.memory-fact-list li:last-child { border-bottom: 0; }
.memory-fact-row { display: flex; justify-content: space-between; align-items: center; gap: var(--space-3); }
.memory-fact-label { font-weight: 600; }
.memory-fact-label--retracted { text-decoration: line-through; opacity: 0.6; }
.memory-fact-desc { color: var(--color-text-muted); font-size: var(--font-size-sm); margin: 4px 0 0; }
.memory-fact-meta { color: var(--color-text-muted); font-size: var(--font-size-xs); margin: 4px 0 0; }

.memory-fact-group + .memory-fact-group { margin-top: var(--space-4); }

.toggle { display: inline-flex; align-items: center; gap: 6px; font-size: var(--font-size-sm); }

.dl-grid { display: grid; grid-template-columns: max-content 1fr; gap: 4px var(--space-4); margin: 0; }
.dl-grid dt { color: var(--color-text-muted); font-size: var(--font-size-sm); }
.dl-grid dd { margin: 0; font-size: var(--font-size-sm); }

.code-block {
  /* Override the global dark `pre` (light --color-pre-text on dark
     --color-pre-bg): use a defined surface + body-text pair so the block
     stays readable in light AND dark mode. The old --color-surface-soft was
     undefined, so the background fell back to transparent and the inherited
     near-white pre text rendered on the light card. */
  background: var(--color-surface);
  color: var(--color-text-body);
  border: 1px solid var(--color-border-soft);
  border-radius: 4px;
  padding: 12px;
  overflow-x: auto;
  font-family: "JetBrains Mono", monospace;
  font-size: 0.85em;
}

.pager { display: flex; gap: var(--space-3); justify-content: center; padding: var(--space-3) 0; font-size: var(--font-size-sm); }

/* ---------------------------------------------------------
   23. Audit log (S11, #202)
   Owns the audit-log surface: retention card, filter bar, event
   table readability, action category tags, expand-detail rows.
   Tokens only — calm-over-alarm (color marks destructive/security
   events only, the rest stay neutral).
   --------------------------------------------------------- */

/* ── Retention card ──────────────────────────────────────── */
/* The .card already carries --space-6 padding; the control row is the only
   extra structure needed. Number + unit + Save read as one inline line. */
.audit-retention-card {
  margin-bottom: var(--space-6);
}

.audit-retention-control {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-3);
}

.audit-retention-control .form-input {
  width: auto;
  max-width: 7rem;
  font-variant-numeric: tabular-nums;
}

.audit-retention-unit {
  font-size: var(--font-size-sm);
  color: var(--color-text-muted);
}

/* ── Filter bar ──────────────────────────────────────────── */
/* Replaces the borrowed (undefined) .impersonations-filters + the
   .settings-form column stack. Labeled fields in a wrapping row that
   bottom-align; actions trail to the end. Uses plain .form-input — NOT
   .form-input--inline, whose uppercase pill styling is for compact status
   selects, not a free-text filter bar. */
.audit-filters {
  /* One shared control height across every field + button so the flex-end row
     lines up cleanly (mirrors the User Analysis report toolbar's --control-h).
     The native inputs otherwise render at 39-43px each — uneven on their own. */
  --audit-ctl-h: 40px;
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: var(--space-3) var(--space-4);
  margin-bottom: var(--space-6);
}

.audit-filters .form-group {
  flex: 1 1 11rem;
  min-width: 0;
  gap: var(--space-1);
}

.audit-filters .form-group--search {
  flex: 2 1 16rem;
}

.audit-filters .form-input {
  height: var(--audit-ctl-h);
  box-sizing: border-box;
}

/* Plain button group — NOT the settings-form footer the base .form-actions
   styles (its border-top + padding-top drew a stray rule and pushed the
   buttons below the input baseline). Buttons share the field height so they
   align with the inputs / date pickers on the same row. */
.audit-filters .form-actions {
  display: flex;
  align-items: flex-end;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin: 0;
  padding: 0;
  border-top: 0;
}

.audit-filters .form-actions .btn {
  height: var(--audit-ctl-h);
}

/* Date inputs adopt the report's calendar affordance: the whole field opens
   the picker (showPicker() on click — see the page script), and the native
   popup follows the theme (light by default, dark under [data-theme]). */
.audit-filters input[type="date"] {
  cursor: pointer;
  color-scheme: light;
}

.audit-filters input[type="date"]::-webkit-calendar-picker-indicator {
  cursor: pointer;
}

[data-theme="dark"] .audit-filters input[type="date"] {
  color-scheme: dark;
}

/* ── Event table ─────────────────────────────────────────── */
/* The shared .data-table--auto rule wraps every cell (overflow-wrap:anywhere)
   so long target reprs wrap and the table keeps fitting its card. Keep that
   fit-to-container behaviour; only stop the atomic-token columns — the actor
   username and the IP — from breaking mid-character ("quicki|um", "172.|26").
   The timestamp breaks only at its space (date / time), never mid-number. */
.audit-table tbody tr.audit-row .user-name,
.audit-table tbody tr.audit-row td.audit-col-ip {
  white-space: nowrap;
}

.audit-table tbody tr.audit-row .log-time {
  overflow-wrap: normal;
}

.audit-table tbody tr.audit-row td.audit-col-target {
  overflow-wrap: anywhere;
}

/* ── Action category tag ─────────────────────────────────── */
/* Neutral by default. Color is reserved for events that matter on a scan:
   destructive removals (danger) and auth anomalies (warning). Everything
   else (logins, creates, updates, config changes) stays calm/neutral. */
.audit-action {
  background: var(--color-surface);
  color: var(--color-text-body);
  border: 1px solid var(--color-border);
}

.audit-action[data-action*="deleted"],
.audit-action[data-action*="revoked"],
.audit-action[data-action="org.member_left"] {
  background: var(--color-danger-bg);
  color: var(--color-danger-strong);
  border-color: var(--color-danger-border-soft);
}

.audit-action[data-action="auth.login_failure"],
.audit-action[data-action="auth.login_lockout"] {
  background: var(--color-warning-bg);
  color: var(--color-warning-strong);
  border-color: var(--color-warning-border-soft);
}

/* ── Expand control ──────────────────────────────────────── */
.audit-expand-cell {
  width: 1%;
  text-align: right;
}

.audit-expand {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  padding: 0;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-btn);
  background: var(--color-elevated);
  color: var(--color-text-muted);
  cursor: pointer;
  transition: background var(--transition-fast), color var(--transition-fast),
    border-color var(--transition-fast);
}

.audit-expand:hover {
  background: var(--color-surface);
  color: var(--color-text-heading);
}

.audit-expand:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
  border-color: var(--color-primary);
}

.audit-expand svg {
  width: 16px;
  height: 16px;
  transition: transform var(--transition-fast) var(--ease-out);
}

.audit-expand[aria-expanded="true"] svg {
  transform: rotate(90deg);
}

/* Touch devices: meet the 44x44 tap-target floor without inflating the
   compact desktop control. Matches the 44px coarse-pointer floor the
   sibling .btn-sm / .pagination-btn rules use in responsive.css (F5). */
@media (pointer: coarse) {
  .audit-expand {
    width: 44px;
    height: 44px;
  }
}

/* ── Expanded detail row ─────────────────────────────────── */
.audit-detail > td {
  background: var(--color-surface);
  padding: var(--space-4);
}

.audit-detail-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: var(--space-4);
}

.audit-detail-field {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  min-width: 0;
}

.audit-detail-label {
  font-size: var(--font-size-xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--color-text-muted);
}

.audit-detail-field pre {
  margin: 0;
}

/* ── Footer meta line ────────────────────────────────────── */
.audit-meta {
  margin-top: var(--space-4);
  font-size: var(--font-size-sm);
  color: var(--color-text-muted);
}

/* ── Mobile (F5, #190): table scrolls within its card; detail grid and
   retention control stack; filter fields go full-width. ──────────────── */
@media (max-width: 768px) {
  .audit-filters .form-group,
  .audit-filters .form-group--search {
    flex: 1 1 100%;
  }
}

/* =========================================================================
   S10 — Admin people pages (#201): /users/, /invitations/,
   /impersonations/, /password-resets/. Polish only; reuses shared tokens
   and the data-table / status-tag / role-chip / filter-bar vocabulary.
   Consolidation note: .impersonations-filters mirrors .audit-filters above
   and the .status-tag--revoked / --role-salesperson variants extend the
   shared status-tag family in components.css — fold in when convenient.
   ========================================================================= */

/* Wide audit tables (Invitations, Password resets) carry more columns than fit
   the content width even after auto-sizing. Wrapping the table in a plain
   block scroll container keeps the page itself free of a horizontal scrollbar
   (the sidebar/header stay put) and confines the scroll to the table — the
   DESIGN §9 F5 horizontal-scroll strategy at every width. A <table> set to
   display:block does NOT collapse its own min-content, so the flex main column
   can't shrink; a plain <div> does, which is why the wrapper is a div. */
.table-scroll {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}
/* The inner .data-table keeps width:100% (fills when narrow); auto-layout grows
   it past 100% and the wrapper scrolls when columns need more room. Do NOT add
   min-width:100% here: a percentage min-width ties the table's min-content to
   the auto-width wrapper, so the wrapper can't collapse and the page overflows. */

/* Let the main column shrink below its content's intrinsic width at every
   width, not just on mobile. responsive.css already sets this under ≤768px
   (so a wide non-wrapping row scrolls instead of forcing whole-page overflow);
   the over-wide audit tables above need the same release on desktop, otherwise
   .main-content (a flex item, default min-width:auto = min-content) refuses to
   shrink and the page gains a horizontal scrollbar. A scroll container alone
   does not release the flex floor. Promoting the F5 rule app-wide is safe:
   content-wrapper still caps at --content-max-width and centres. */
.main-content {
  min-width: 0;
}

/* Inside a scrolling wide table the column doesn't need to shrink to zero, so
   relax .data-table--auto's `overflow-wrap: anywhere` (which breaks every cell
   mid-character) to `break-word`: long unbroken strings (emails) still wrap,
   but usernames and labels keep their word boundaries instead of fracturing. */
.table-scroll .data-table tbody td {
  overflow-wrap: break-word;
}

/* Token / key prefixes are atomic mono IDs — never fracture them across lines. */
.table-scroll .api-key-prefix {
  white-space: nowrap;
}

/* Usernames are atomic too (Impersonations impersonator/target). Keep them on
   one line; the wrapper scrolls to reveal a long name rather than breaking
   "manager_test" into "manager_te / st". */
.table-scroll .user-name {
  white-space: nowrap;
}

/* Cells inside a horizontal-scroll table need their own containing block so an
   absolutely-positioned .visually-hidden label (e.g. the /users/ inline
   role <select>'s hidden <label>) stays anchored inside the table instead of
   escaping to the viewport and forcing a phantom page-level horizontal scroll
   at narrow widths (same trap fixed for .custom-rules-table in guardrail.css).
   The row-actions dropdown is unaffected: it anchors to .row-actions, a closer
   positioned ancestor. */
.table-scroll .data-table th,
.table-scroll .data-table td {
  position: relative;
}

/* Quiet-danger status variant. A deliberately-closed state (an invitation or
   reset token revoked by an admin, an impersonation force-ended) reads as
   noteworthy without the full Block-Red pill: a low-chroma danger tint keeps
   the audit calm while still separating it from the neutral "expired / used"
   closures and the green "active" rows (Status-Plus-Label, calm-over-alarm). */
.status-tag--revoked {
  background: var(--color-danger-soft);
  color: var(--color-danger-strong);
  border: 1px solid var(--color-danger-border-soft);
}

/* Role chip — salesperson (demo/sales role). The shared chip covers
   user / manager / admin; salesperson can surface on the password-reset
   audit (target_role snapshot), so give it a defined neutral chip rather
   than letting it fall through to a bare, background-less pill. */
.status-tag--role-salesperson {
  background: var(--color-surface);
  color: var(--color-text-body);
  border: 1px solid var(--color-border);
}

/* Inline role <select> on /users/ (.user-role-select, base styles in
   dashboard-extras.css). Keep the browser's native dropdown arrow (one, in the
   right place, in every browser/theme). The only bug was the clip: the shared
   .form-input--inline rule UPPERCASES the value, so the displayed "MANAGER" /
   "SALESPERSON" was wider than the box the browser had sized from the lowercase
   option list, and it truncated to "MANA…". Show the label in its natural case
   (which is what the box is sized from) so it fits, with no custom chevron. */
.user-role-select.form-input--inline {
  text-transform: none;
  letter-spacing: normal;
}

/* Impersonations filter bar. Replaces the borrowed .settings-form column
   stack (which dropped the three filters into a tall vertical form) with the
   same wrapping, bottom-aligned row the audit page uses: labeled fields that
   share one control height so inputs and buttons line up on the baseline. */
.impersonations-filters {
  --filter-ctl-h: 40px;
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: var(--space-3) var(--space-4);
  margin-bottom: var(--space-6);
}

.impersonations-filters .form-group {
  flex: 1 1 12rem;
  min-width: 0;
  gap: var(--space-1);
}

.impersonations-filters .form-input {
  height: var(--filter-ctl-h);
  box-sizing: border-box;
}

/* Plain button group, not the settings-form footer (its border-top + padding
   pushed the buttons below the input baseline). Buttons share the field
   height so they bottom-align with the inputs on the same row. */
.impersonations-filters .form-actions {
  display: flex;
  align-items: flex-end;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin: 0;
  padding: 0;
  border-top: 0;
}

.impersonations-filters .form-actions .btn {
  height: var(--filter-ctl-h);
}

@media (max-width: 768px) {
  /* Filter fields go full-width so they stack cleanly on mobile. */
  .impersonations-filters .form-group {
    flex: 1 1 100%;
  }
}
