/* azapptoolkit Leptos+Thaw UI styles.
 *
 * Token system follows a Refined Fluent 2 palette: surface scale, 4-step
 * elevation, motion + easing tokens, and a typography ramp.
 */

:root {
  /* ---- Color: neutrals & accents ---- */
  --border: #e3e3e3;
  --border-strong: #cfcfcf;
  --canvas: #f4f6f8;
  --bg-subtle: #f4f6f8;
  --surface: #ffffff;
  --surface-raised: #ffffff;
  --acrylic: rgba(255, 255, 255, 0.72);
  --scrim: rgba(0, 0, 0, 0.32);
  --text: #1f1f1f;
  --text-muted: #5b5b5b;
  /* 4.6:1 on --surface (#fff). #8a8a8a was ~3.0:1 — below WCAG AA 4.5:1 for
     the body text this backs (muted labels, saved-view remove). */
  --text-faint: #6e6e6e;

  --accent: #0f6cbd;
  --accent-hover: #115ea3;
  --accent-soft: rgba(15, 108, 189, 0.12);
  --accent-ent: #8a3ffc;
  --accent-ent-soft: rgba(138, 63, 252, 0.12);
  --accent-mi: #0f803c;
  --accent-mi-soft: rgba(15, 128, 60, 0.12);
  --accent-mi-user: #007a99;
  --accent-mi-user-soft: rgba(0, 122, 153, 0.12);
  --danger: #b10e1c;
  --danger-soft: rgba(177, 14, 28, 0.12);
  /* 4.5:1 on --surface. This is used as a TEXT colour (badge labels, callout
     copy), not just a fill, so it has to clear AA like any other body text. */
  --warning: #a35c00;
  --warning-soft: rgba(201, 114, 0, 0.12);
  --ok: #0f803c;
  --ok-soft: rgba(15, 128, 60, 0.12);

  /* ---- Spacing (4px grid) ---- */
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 24px;
  --space-6: 32px;

  /* ---- Radii ---- */
  --radius-sm: 4px;
  --radius-md: 6px;
  --radius-lg: 8px;
  --radius-xl: 12px;
  --radius-pill: 999px;

  /* ---- Elevation (Fluent 2 depth tokens) ---- */
  --shadow-2: 0 1px 2px rgba(0, 0, 0, 0.06);
  --shadow-4: 0 2px 4px rgba(0, 0, 0, 0.06), 0 1px 2px rgba(0, 0, 0, 0.04);
  --shadow-8: 0 4px 8px rgba(0, 0, 0, 0.08), 0 1px 2px rgba(0, 0, 0, 0.04);
  --shadow-16: 0 8px 16px rgba(0, 0, 0, 0.10), 0 2px 4px rgba(0, 0, 0, 0.06);

  /* ---- Typography ---- */
  --font-sans: "Segoe UI Variable", "Segoe UI", -apple-system, BlinkMacSystemFont,
    "Helvetica Neue", Arial, sans-serif;
  --font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
  --text-caption: 11px;
  --text-xs: 12px;
  --text-sm: 13px;
  --text-base: 14px;
  --text-md: 16px;
  --text-lg: 18px;
  --text-xl: 22px;
  --weight-regular: 400;
  --weight-medium: 500;
  --weight-semibold: 600;

  /* ---- Motion ---- */
  --motion-fast: 100ms;
  --motion-base: 150ms;
  --motion-slow: 220ms;
  --ease-standard: cubic-bezier(0.33, 0, 0.67, 1);
  --ease-accel: cubic-bezier(0.7, 0, 1, 0.5);
  --ease-decel: cubic-bezier(0.1, 0.9, 0.2, 1);

  /* ---- Focus ring ---- */
  --focus-ring: 0 0 0 2px var(--surface), 0 0 0 4px var(--accent);

  /* ---- Layout constants ---- */
  --nav-width: 240px;
  --nav-width-collapsed: 56px;
  --topbar-height: 52px;

  /* Tells the engine which palette the NATIVE controls should use. Without it a
     <select>'s popup list, the scrollbars, and any native form widget render in
     light chrome no matter how dark the page is — the one part of the UI CSS
     cannot reach, because the popup is drawn by the OS. Set alongside the
     tokens so it flips with them. */
  color-scheme: light;
}

@media (prefers-color-scheme: dark) {
  :root {
    color-scheme: dark;
    --border: #3b3b3b;
    --border-strong: #4a4a4a;
    --canvas: #1a1a1a;
    --bg-subtle: #242424;
    --surface: #1f1f1f;
    --surface-raised: #2a2a2a;
    --acrylic: rgba(31, 31, 31, 0.72);
    --scrim: rgba(0, 0, 0, 0.55);
    --text: #f3f3f3;
    --text-muted: #b0b0b0;
    --text-faint: #888;
    --accent: #4cc2ff;
    --accent-hover: #6dcdff;
    --accent-soft: rgba(76, 194, 255, 0.18);
    --accent-ent: #b48bff;
    --accent-ent-soft: rgba(180, 139, 255, 0.18);
    --accent-mi: #4cd17e;
    --accent-mi-soft: rgba(76, 209, 126, 0.18);
    --accent-mi-user: #4ec9d6;
    --accent-mi-user-soft: rgba(78, 201, 214, 0.18);
    /* Status colors must lighten too: the light-mode reds/greens land at
     * ~2-3:1 against the dark surfaces, below WCAG AA for text. */
    --danger: #ff6b70;
    --danger-soft: rgba(255, 107, 112, 0.18);
    --warning: #f0ab46;
    --warning-soft: rgba(240, 171, 70, 0.18);
    --ok: #4cd17e;
    --ok-soft: rgba(76, 209, 126, 0.18);
    --shadow-2: 0 1px 2px rgba(0, 0, 0, 0.4);
    --shadow-4: 0 2px 4px rgba(0, 0, 0, 0.5), 0 1px 2px rgba(0, 0, 0, 0.3);
    --shadow-8: 0 4px 8px rgba(0, 0, 0, 0.5), 0 1px 2px rgba(0, 0, 0, 0.3);
    --shadow-16: 0 8px 16px rgba(0, 0, 0, 0.55), 0 2px 4px rgba(0, 0, 0, 0.4);
  }
}

html,
body {
  margin: 0;
  padding: 0;
  height: 100%;
  background: var(--canvas);
  color: var(--text);
  font-family: var(--font-sans);
  font-size: var(--text-base);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/* Thaw's <ConfigProvider> wraps the entire app in this div, and Thaw's own
 * runtime CSS gives it no height — so without this rule every `height: 100%`
 * below it (the root flex div, `.shell`, `.apps-view`/`.mi-view`) resolves to
 * auto and the layout grows to content height: the virtualized lists expand to
 * their full sizer height, the window grows one giant scrollbar, and the
 * detail pane's header scrolls out of view (and stays out across keep-alive
 * view switches, which share that window scroll position). With the chain
 * intact, `.shell__content` and the list/detail panes scroll internally and
 * the detail pane stays on-screen. */
.thaw-config-provider {
  height: 100%;
}

/* Keyboard-focus ring (Fluent-style stacked outline) for interactive rows and
 * nav items. */
.app-list__row:focus-visible,
.nav__item:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
}
/* Global keyboard-focus ring for form fields. Thaw renders bare
 * <input>/<select>/<textarea> elements, so an element selector reaches them.
 * Checkbox/radio keep their native focus indicator (the stacked ring reads
 * poorly on tiny square controls). */
input:not([type="checkbox"]):not([type="radio"]):focus-visible,
select:focus-visible,
textarea:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
}
/* Custom transparent-background buttons (pairing links, saved-view chips,
 * claims-editor row actions) — same ring instead of the UA default outline. */
.saved-views__add:focus-visible,
.saved-views__naming button:focus-visible,
.detail-header__pairing button:focus-visible,
.claims-editor__row > button:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
}

/* Thaw's `<Field label=…>` renders its label at body size, regular weight, and
 * the primary foreground — byte-identical to the value underneath it, so with
 * ~70 Fields across the app a label read as just another line of content and a
 * form had no visual hierarchy at all. (The Access tab's "Role" / "Assign" /
 * "Search by name" stack was the clearest case.) Demote it the way the app
 * already demotes its own hand-rolled `.sso-field__label`: same size, medium
 * weight, muted — the label is the quieter half of a label/value pair.
 * App-side because Thaw offers no token for this; `.thaw-field__label` is a
 * single class, so this rule out-specificities nothing and simply lands later
 * in the cascade than Thaw's runtime-injected `.thaw-label--regular`. */
.thaw-field__label {
  font-weight: var(--weight-medium);
  color: var(--text-muted);
}

/* Thaw <Input> renders a `.thaw-input` wrapper span around the inner
 * `.thaw-input__input`; with no width set, the wrapper collapses to
 * min-content and clips long placeholder hints. Fill the container so the
 * full hint shows. */
.thaw-input {
  width: 100%;
}

/* Destructive-action buttons (Delete / Remove / Revoke). Class sits on a Thaw
 * `.thaw-button` (`.thaw-button.button--danger` out-specificities Thaw's
 * `.thaw-button--<appearance>` colour rules) so it works on Subtle / Secondary
 * / Primary alike — red text on a faint red tint, clearly destructive without
 * painting list-heavy views solid red. Also covers the confirm button inside
 * ConfirmDialog (the commit / point of no return). */
/* Labeled destructive buttons (text: Delete / Remove / Revoke) get the full
 * treatment — red border, red text, faint red fill — so the whole box reads
 * destructive at a glance. */
.thaw-button.button--danger {
  border-color: var(--danger);
  color: var(--danger);
  background: var(--danger-soft);
}
.thaw-button.button--danger:hover {
  border-color: var(--danger);
  color: var(--danger);
  background: var(--danger-soft);
  filter: brightness(0.94);
}
/* Icon-only destructive actions (a row's trash, a saved-view chip's "×") take
 * the red GLYPH and nothing else at rest. These repeat once per row, and a red
 * outline on every row of a long list reads as forty errors rather than forty
 * actions — which is why the box is deliberately withheld until hover, when the
 * pointer is actually on the target. (This rule previously set `border-color`
 * against its own stated intent: `.ui-icon-btn` has a 1px *transparent* border,
 * so colouring it painted exactly the heavy red square the comment disclaimed.)
 * Red is still the signal, so every destructive icon button must carry this
 * class — see the census in the same commit. */
.ui-icon-btn.button--danger,
.saved-view-chip__remove.button--danger {
  color: var(--danger);
}
.ui-icon-btn.button--danger:hover,
.saved-view-chip__remove.button--danger:hover {
  background: var(--danger-soft);
  color: var(--danger);
}

h1,
h2,
h3 {
  margin: 0;
}

.mono {
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
  word-break: break-all;
}

.row {
  display: flex;
  gap: var(--space-2);
  align-items: flex-end;
}

.row-between {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--space-2);
}

.actions-row {
  display: flex;
  gap: var(--space-2);
  align-items: center;
  margin-top: var(--space-2);
}

/* The toolkit-managed Exchange scope group panel and its member list (one row
   per mailbox, with a Remove button right-aligned via `.row-between`). */
.managed-scope-group {
  margin-top: var(--space-2);
}

/* State-aware status header (existence badge + "will be created" callout or the
   live member count) that sits above the add-mailbox field. */
.managed-scope-group__status {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  margin-bottom: var(--space-2);
}

.member-list {
  list-style: none;
  margin: var(--space-2) 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}

.member-list li {
  padding: var(--space-1) 0;
  border-bottom: 1px solid var(--border-subtle, rgba(128, 128, 128, 0.2));
}

/* Icon-button group inside a table cell. The cell itself stays a normal
   top-aligned `.data-table td` (so the buttons line up row-to-row with sibling
   cells); the inner flex row lays the buttons out horizontally without the
   standalone `.actions-row` top margin — putting `display:flex` directly on a
   <td> wraps it in an anonymous cell and breaks the column's vertical-align. */
.cell-actions {
  display: flex;
  gap: var(--space-2);
  align-items: center;
}

/* Vertically center the single-element control columns (Kind / Scope / Status /
   Actions) against the multi-line identity columns (Resource / Permission),
   which stay `vertical-align: top`. Without this the Trash/Scope icons ride the
   top edge of a tall multi-line row and read as belonging to the row above;
   centering lines them up with the Status badge at the row's middle. The `td`
   qualifier outranks the base `.data-table td { vertical-align: top }` rule. */
.data-table td.cell-mid {
  vertical-align: middle;
}

.section-header {
  display: flex;
  gap: var(--space-3);
  align-items: center;
  justify-content: space-between;
}

.form-grid {
  display: grid;
  gap: var(--space-3);
}

.form-error {
  color: var(--danger);
  /* Backend UiErrors append actionable guidance after a blank line (\n\n);
     keep it on its own lines instead of collapsing the whitespace away. */
  white-space: pre-wrap;
  word-break: break-word;
}

.read-field strong {
  display: block;
  margin-bottom: 2px;
}
/* A <dl> used as a read-only label/value pair. Without this the UA's default
   `margin-inline-start: 40px` on <dd> indents every value away from its own
   label, which read as an accident on the SSO tab. */
.read-field dt {
  font-size: var(--text-xs);
  color: var(--text-muted);
}
.read-field dd {
  margin: 0;
}

.alert {
  border-radius: var(--radius-md);
  padding: 10px var(--space-3);
  margin-top: var(--space-2);
  /* Preserve the \n\n actionable-guidance breaks the backend attaches. */
  white-space: pre-wrap;
  word-break: break-word;
}
.alert--ok {
  background: var(--ok-soft);
  border: 1px solid var(--ok);
}
.alert--warn {
  background: var(--warning-soft);
  border: 1px solid var(--warning);
}
.alert--danger {
  background: var(--danger-soft);
  border: 1px solid var(--danger);
}

.badge {
  display: inline-block;
  padding: 2px var(--space-2);
  border-radius: var(--radius-pill);
  font-size: var(--text-xs);
  background: var(--bg-subtle);
  border: 1px solid var(--border);
  /* Keep verdict/status bubbles on one line: never wrap the label, and never let
   * a flex row (e.g. the readiness axis) squeeze the badge narrower than its
   * text — the sibling detail text wraps instead. */
  white-space: nowrap;
  flex-shrink: 0;
}
.badge--danger {
  background: var(--danger-soft);
  border-color: var(--danger);
  color: var(--danger);
}
/* Critical risk: a solid (filled) red so it's distinct at a glance from the
   soft-outline High badge (badge--danger) when they sit in adjacent rows. */
.badge--critical {
  background: var(--danger);
  border-color: var(--danger);
  color: #fff;
}
.badge--warning {
  background: var(--warning-soft);
  border-color: var(--warning);
  color: var(--warning);
}
.badge--ok {
  background: var(--ok-soft);
  border-color: var(--ok);
  color: var(--ok);
}
/* Indeterminate state ("couldn't determine", e.g. mailbox scoping when the
   Exchange admin API was unavailable). A dashed outline reads as "unresolved /
   needs attention" — distinct from both the bare "—" dash (not applicable) and
   a red error badge. */
.badge--unknown {
  color: var(--text-muted);
  border-style: dashed;
  border-color: var(--warning);
}

/* ---------- Sign-in ---------- */
.signin-shell {
  display: flex;
  flex: 1;
  align-items: center;
  justify-content: center;
  padding: var(--space-6);
  /* `flex: 1` already fills the full-height flex root (main.rs); a `100vh`
     min-height here would force a second, redundant scrollbar on a short
     window. */
  background:
    radial-gradient(at 20% 0%, var(--accent-soft) 0%, transparent 50%),
    radial-gradient(at 90% 100%, var(--accent-ent-soft) 0%, transparent 50%),
    var(--canvas);
}
.signin-card {
  width: min(440px, 92vw);
  padding: var(--space-6);
  gap: var(--space-4);
}
.signin-card__brand {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--text-lg);
  font-weight: var(--weight-semibold);
}
.signin-card__title {
  font-size: var(--text-xl);
  font-weight: var(--weight-semibold);
  margin: 0;
  letter-spacing: -0.01em;
}
.signin-error {
  color: var(--danger);
  /* Keep the message and its recovery hint on separate lines (\n\n). */
  white-space: pre-wrap;
}
.signin-hint {
  color: var(--text-muted);
  font-size: var(--text-sm);
}

/* ---------- App shell ---------- */
.shell {
  display: grid;
  grid-template-columns: var(--nav-width) 1fr;
  height: 100%;
  min-height: 0;
}
.shell__nav {
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border-right: 1px solid var(--border);
  min-height: 0;
}
.shell__brand {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-4) var(--space-4) var(--space-3);
  font-weight: var(--weight-semibold);
  font-size: var(--text-md);
  letter-spacing: 0.2px;
  border-bottom: 1px solid var(--border);
}
.shell__brand-mark {
  width: 24px;
  height: 24px;
  border-radius: var(--radius-md);
  background: linear-gradient(135deg, var(--accent), var(--accent-ent));
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: #fff;
  font-size: var(--text-sm);
  font-weight: 700;
  flex-shrink: 0;
}

/* Changelog splash for a pending app update. */
.update-splash {
  display: grid;
  gap: var(--space-3);
}
.update-splash__meta {
  color: var(--text-muted);
}

/* Rendered changelog notes. Shared by the update splash (a pending release) and
   the account menu's "What's new" (the installed one), so the block is named
   for the content, not for either dialog. */
.changelog {
  margin: 0;
  max-height: 320px;
  overflow: auto;
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--bg-subtle);
  font-size: var(--text-sm);
  line-height: 1.55;
  word-break: break-word;
}
.changelog > :first-child {
  margin-top: 0;
}
.changelog > :last-child {
  margin-bottom: 0;
}
.changelog p {
  margin: var(--space-2) 0;
}
.changelog__heading {
  margin: var(--space-3) 0 var(--space-1);
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-muted);
}
.changelog ul {
  display: grid;
  gap: var(--space-1);
  margin: var(--space-1) 0;
  padding-left: var(--space-4);
}
.changelog li > ul {
  margin-top: var(--space-1);
}
.changelog code {
  padding: 0.1em 0.35em;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--accent-soft);
  font-family: var(--font-mono);
  font-size: 0.92em;
}
.changelog strong {
  font-weight: var(--weight-semibold);
}
.changelog a {
  color: var(--accent);
  text-decoration: underline;
}
/* Reveals the entries the summary condensed away; sits under the notes box, so
   it reads as a footnote to it rather than a dialog action. */
.changelog__toggle {
  justify-self: start;
  margin-top: calc(-1 * var(--space-1));
}
.update-splash__progress {
  display: grid;
  gap: var(--space-1);
}
.shell__nav-list {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: var(--space-2);
  overflow: auto;
  flex: 1;
}
.shell__nav-section-label {
  font-size: var(--text-caption);
  font-weight: var(--weight-semibold);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-muted);
  padding: var(--space-3) var(--space-3) var(--space-1);
}
.shell__main {
  display: grid;
  /* topbar · content (the workspace overlays this row) · open-items dock */
  grid-template-rows: var(--topbar-height) 1fr auto;
  /* ...and ONE column, pinned. `min-width: 0` below stops this box from being
     stretched by its parent's track, but says nothing about the column THIS
     grid creates for its own children: an implicit column is `auto`, which
     sizes to the widest child's min-content. The topbar's search field and
     tenant pill were doing exactly that — the column resolved ~112px wider than
     the box, so every row (topbar, content, dock) rendered over-wide and the
     tenant switcher, the Delete button and the tab strip fell off the right
     edge below ~1000px. The 0 floor lets the column be narrower than its
     content so the inner scroll containers do the work. */
  grid-template-columns: minmax(0, 1fr);
  min-height: 0;
  /* Grid items default to `min-width: auto`, so a wide child (a data table, a
     long unbroken id) can stretch this 1fr track past the viewport and scroll
     the whole page sideways — the #1 "broken on mobile" symptom. Pin it to 0 so
     the column stays within its share and inner panes scroll instead. */
  min-width: 0;
}
.shell__topbar {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: 0 var(--space-5);
  background: var(--acrylic);
  -webkit-backdrop-filter: saturate(180%) blur(20px);
  backdrop-filter: saturate(180%) blur(20px);
  box-shadow: inset 0 -1px 0 var(--border);
  position: relative;
  /* Above the open-items workspace overlay (z 500), below the modal scrim
     (z 1000). The topbar establishes a stacking context, so its account menu
     (`.shell__account-menu`, z 60 *within* this context) is capped at the
     topbar's level relative to siblings of `.shell__main`. The menu opens
     downward into the content row, which the workspace overlays — at z 10 the
     whole topbar (menu included) rendered *behind* the workspace whenever a
     detail item was open, so the settings dropdown looked dead. The topbar is
     row 1 and never geometrically overlaps the row-2 workspace, so lifting it
     only changes paint order for that downward-hanging menu. */
  z-index: 600;
}
@supports not (backdrop-filter: blur(1px)) {
  .shell__topbar {
    background: var(--surface);
  }
}
.shell__topbar-left,
.shell__topbar-right {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  align-items: center;
}
.shell__topbar-center {
  flex: 0 1 auto;
  display: flex;
  align-items: center;
  justify-content: center;
}
.shell__topbar-right {
  justify-content: flex-end;
  gap: var(--space-3);
}
.shell__topbar-right > :last-child {
  flex-shrink: 0;
}
/* Left third: the persistent page identity (nav-group crumb + view title). */
.shell__topbar-title {
  display: flex;
  flex-direction: column;
  min-width: 0;
  line-height: 1.15;
}
.shell__topbar-crumb {
  font-size: var(--text-caption);
  font-weight: var(--weight-semibold);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-muted);
}
.shell__topbar-view {
  font-size: var(--text-md);
  font-weight: var(--weight-semibold);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* Right third: signed-in tenant chip (org name + primary domain) + the
   refresh-token affordance. */
/* The tenant pill doubles as the account-menu trigger; `.shell__account` is the
   positioning context for the dropdown, which opens downward from the pill. */
.shell__account {
  position: relative;
  display: inline-flex;
  min-width: 0;
}
.shell__tenant-chip {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  min-width: 0;
  max-width: 240px;
  padding: var(--space-1) 10px;
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  background: var(--bg-subtle);
  /* It's a <button> now: reset the UA styles and add the interactive affordance. */
  font: inherit;
  color: inherit;
  text-align: left;
  cursor: pointer;
  transition: background var(--motion-base) var(--ease-standard);
}
.shell__tenant-chip:hover {
  background: var(--surface);
}
.shell__tenant-chip:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
}
.shell__tenant-chip-icon {
  display: inline-flex;
  color: var(--text-muted);
  flex-shrink: 0;
}
.shell__tenant-chip-text {
  display: flex;
  flex-direction: column;
  min-width: 0;
  line-height: 1.15;
}
.shell__tenant-chip-name {
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.shell__tenant-chip-domain {
  font-size: var(--text-caption);
  color: var(--text-muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.shell__tenant-chip-caret {
  display: inline-flex;
  color: var(--text-muted);
  flex-shrink: 0;
}

/* Account dropdown — the operator/tenant cluster relocated off the left rail
   (identity, Access Readiness, Settings, cache, updates, Sign Out, version).
   Opens downward, right-aligned to the pill; toggled/closed in shell.rs. */
.shell__account-menu {
  position: absolute;
  top: calc(100% + var(--space-1));
  right: 0;
  min-width: 240px;
  z-index: 60;
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: var(--space-1);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-4);
}
.shell__account-menu-header {
  display: flex;
  flex-direction: column;
  gap: 1px;
  padding: var(--space-2) var(--space-3);
}
.shell__account-menu-label {
  font-size: var(--text-caption);
  color: var(--text-muted);
}
.shell__account-menu-user {
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.shell__account-item {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  border: none;
  background: transparent;
  border-radius: var(--radius-sm);
  color: inherit;
  font: inherit;
  font-size: var(--text-base);
  text-align: left;
  cursor: pointer;
  width: 100%;
  /* Fills its container, then adds padding — and this sheet has no global
     `* { box-sizing: border-box }`, so without this the row renders wider
     than the box it was meant to fill by exactly its horizontal padding. */
  box-sizing: border-box;
}
.shell__account-item:hover {
  background: var(--bg-subtle);
}
.shell__account-item:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
}
.shell__account-item:disabled {
  opacity: 0.6;
  cursor: default;
}
.shell__account-item--selected {
  color: var(--accent);
  font-weight: var(--weight-semibold);
}
.shell__account-item--selected .nav__icon {
  color: var(--accent);
}
.shell__account-divider {
  height: 1px;
  margin: var(--space-1) 0;
  background: var(--border);
}
.shell__account-version {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-2);
  padding: var(--space-1) var(--space-3);
  font-size: var(--text-xs);
  color: var(--text-muted);
}
.shell__topbar-refresh {
  flex-shrink: 0;
}
.shell__content-wrap {
  /* Positioning context for the workspace overlay; takes the `1fr` row of
     `.shell__main` and lets the scrollable content fill it. */
  position: relative;
  min-height: 0;
  min-width: 0;
  display: flex;
}
.shell__content {
  flex: 1 1 auto;
  min-height: 0;
  min-width: 0;
  overflow: auto;
  padding: var(--space-4) var(--space-5);
}

/* ---------- Open-items dock + workspace ---------- */
/* The dock is the bottom row of `.shell__main`; the workspace is an overlay that
   covers the content area when 1–2 items are shown — above page dropdowns
   (z 50) but below modal dialogs (z 1000), so a pane's ConfirmDialog still wins.
   NOTE: the top-bar account menu is deliberately ABOVE this (`.shell__topbar`
   z 600) — it's chrome in row 1, not page content, so the overlay must not
   swallow it. Don't raise the workspace past the topbar. */
.open-dock {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  border-top: 1px solid var(--border);
  background: var(--surface);
  animation: ui-fade-in var(--motion-base) var(--ease-decel);
}
.open-dock__chips {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  /* The chips scroll; the "Close all" button (a flex sibling) stays pinned. */
  flex: 1 1 auto;
  min-width: 0;
  overflow-x: auto;
  scrollbar-width: thin;
}
.open-dock__clear {
  flex: 0 0 auto;
  padding: var(--space-1) 10px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--surface-raised);
  color: var(--text-muted);
  font: inherit;
  font-size: var(--text-sm);
  cursor: pointer;
}
.open-dock__clear:hover {
  color: var(--danger);
  border-color: var(--danger);
}
.open-dock__chip {
  display: inline-flex;
  align-items: center;
  flex: 0 0 auto;
  max-width: 220px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--surface-raised);
  overflow: hidden;
}
.open-dock__chip--active {
  border-color: var(--accent);
  box-shadow: inset 0 0 0 1px var(--accent);
}
.open-dock__chip-main {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  min-width: 0;
  padding: var(--space-1) var(--space-2);
  border: none;
  background: transparent;
  color: inherit;
  font: inherit;
  cursor: pointer;
}
.open-dock__chip-label {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.open-dock__close {
  flex: 0 0 auto;
  padding: var(--space-1) var(--space-2);
  border: none;
  border-left: 1px solid var(--border);
  background: transparent;
  color: var(--text-muted);
  font-size: var(--text-lg);
  line-height: 1;
  cursor: pointer;
}
.open-dock__close:hover {
  background: var(--surface);
  color: var(--danger);
}
.workspace {
  position: absolute;
  inset: 0;
  z-index: 500;
  padding: var(--space-3);
  background: var(--canvas);
  animation: ui-pop-in var(--motion-slow) var(--ease-decel);
}
.workspace__panes {
  display: grid;
  /* `minmax(0, 1fr)`, not a bare `1fr`: `1fr` means `minmax(auto, 1fr)`, whose
     auto floor is the pane content's min-content — so one wide detail pane
     widened the track and spilled the pane past the workspace. */
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-3);
  height: 100%;
  min-height: 0;
}
.workspace__panes--two {
  /* Same reasoning, doubled: in 2-up compare either pane could otherwise push
     the other off-screen instead of both scrolling inside their own half. */
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
}
.workspace__pane {
  display: flex;
  flex-direction: column;
  min-height: 0;
  min-width: 0;
}
.workspace__pane-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  margin-bottom: var(--space-1);
}
/* Kind glyph + live name on the left (echoes the dock chip); the Full/close
   icon buttons stay pinned on the right so a 2-up compare labels its panes. */
.workspace__pane-title {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-width: 0;
  flex: 1 1 auto;
}
.workspace__pane-name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-weight: var(--weight-semibold);
}
.workspace__pane-actions {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  flex: 0 0 auto;
}
.workspace__pane-bar button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--text-muted);
  font: inherit;
  font-size: var(--text-sm);
  padding: var(--space-1) 6px;
  cursor: pointer;
}
.workspace__pane-bar button:hover {
  color: var(--text);
  border-color: var(--accent);
}

/* ---------- Nav items ---------- */
.nav__item {
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  border: none;
  background: transparent;
  border-radius: var(--radius-md);
  color: inherit;
  font: inherit;
  font-size: var(--text-base);
  cursor: pointer;
  text-align: left;
  width: 100%;
  /* Fills its container, then adds padding — and this sheet has no global
     `* { box-sizing: border-box }`, so without this the row renders wider
     than the box it was meant to fill by exactly its horizontal padding. */
  box-sizing: border-box;
  transition: background-color var(--motion-base) var(--ease-standard),
    color var(--motion-base) var(--ease-standard);
}
.nav__item:hover {
  background: var(--bg-subtle);
}
.nav__item--selected {
  background: var(--accent-soft);
  color: var(--accent);
  font-weight: var(--weight-semibold);
}
.nav__item--selected::before {
  content: "";
  position: absolute;
  left: -2px;
  top: 6px;
  bottom: 6px;
  width: 3px;
  border-radius: var(--radius-pill);
  background: var(--accent);
}
.nav__item:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
}
.nav__icon {
  width: 20px;
  height: 20px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  opacity: 0.9;
  flex-shrink: 0;
}
.nav__label {
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ---------- Apps view ---------- */
.apps-view {
  display: grid;
  grid-template-rows: auto 1fr;
  height: 100%;
  gap: var(--space-3);
  min-height: 0;
}
.apps-view__body {
  /* Full-width list — a selected item opens in the shell's workspace overlay,
     not a side detail pane. */
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-3);
  min-height: 0;
}

/* ---------- App list ---------- */
.app-list {
  /* Flex column (not a fixed-track grid) so the row count of filter controls
     above the list — search, saved views, the facet chip bar, the date field —
     can vary without shifting which child gets the flexible height. The
     virtualized `.app-list__scroller` carries `flex: 1 1 auto; min-height: 0`
     and fills the remaining space, matching the Managed Identities list. */
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  min-height: 0;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: var(--space-3);
  background: var(--surface);
  box-shadow: var(--shadow-2);
}
/* Right-aligned action cluster in a list/section header (export + refresh). */
.list-header-actions {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}
.app-list__scroller {
  overflow: auto;
  position: relative;
  border-radius: var(--radius-md);
  /* Fill the remaining height of its flex-column parent — all three lists
     (App Reg, Enterprise, Managed Identities) are flex columns. */
  flex: 1 1 auto;
  min-height: 0;
}
.app-list__sizer {
  width: 100%;
  position: relative;
}
.app-list__row {
  position: absolute;
  left: 0;
  width: 100%;
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: var(--space-2);
  padding: 0 10px 0 var(--space-2);
  box-sizing: border-box;
  border-bottom: 1px solid var(--border);
  transition: background-color var(--motion-fast) var(--ease-standard);
}
.app-list__row:hover {
  background: var(--bg-subtle);
}
.app-list__row--selected {
  background: var(--accent-soft);
  box-shadow: inset 3px 0 0 var(--accent);
}
.app-list__check {
  flex-shrink: 0;
  cursor: pointer;
}
.app-list__row-btn {
  flex: 1 1 auto;
  min-width: 0;
  height: 100%;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 6px 2px;
  background: transparent;
  border: none;
  text-align: left;
  cursor: pointer;
  color: inherit;
  font: inherit;
}
.app-list__row-btn:focus-visible {
  outline: none;
  box-shadow: inset 0 0 0 2px var(--accent);
  border-radius: var(--radius-sm);
}
.app-list__row-title {
  font-weight: 600;
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.app-list__row .row-meta {
  display: flex;
  width: 100%;
}
.app-list__row .row-meta > .badge,
.app-list__row .row-meta > .pair-arrow,
.app-list__row .row-meta > .type-chip {
  flex-shrink: 0;
}
.app-list__row-appid {
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
  font-size: var(--text-xs);
  color: var(--text-muted);
}
.app-list__error {
  color: var(--danger);
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-2);
  padding: var(--space-3);
}
/* Total app-registration count line above the virtualized rows. */
.app-list__count {
  margin: var(--space-1) var(--space-2);
  font-size: var(--text-xs);
  color: var(--text-muted);
}
/* Compact "first N shown" notice that sits above the virtualized rows. */
.app-list__cap-notice {
  margin: var(--space-1) var(--space-2);
  padding: var(--space-1) var(--space-2);
  font-size: var(--text-xs);
  color: var(--text-muted);
}
/* Header bar above the virtualized rows: tri-state select-all + count on the
   left, Clear on the right. */
.app-list__selectbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  padding: var(--space-1) var(--space-2);
}
.app-list__selectall {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  cursor: pointer;
}
.app-list__selectall .app-list__count {
  margin: 0;
}
.link-btn {
  background: none;
  border: none;
  padding: 0;
  font: inherit;
  font-size: var(--text-xs);
  color: var(--accent);
  cursor: pointer;
}
.link-btn:hover {
  text-decoration: underline;
}
.link-btn:focus-visible {
  outline: none;
  box-shadow: 0 0 0 2px var(--accent);
  border-radius: var(--radius-sm);
}

/* ---------- App detail ---------- */
/* Scoped one level deeper than the bare class so these rules beat Thaw's
   `.thaw-card` defaults. Thaw injects `.thaw-card` into <head> at runtime
   (after our static stylesheet), so at equal specificity its `width: 720px`
   and `margin: auto` would win — capping the pane width and vertically
   centering it, leaving the details floating low in the grid cell. The
   descendant selector raises specificity to 0-2-0 so we deterministically win. */
.workspace__pane .app-detail {
  /* Fills the pane below its control bar. */
  flex: 1 1 auto;
  border-radius: var(--radius-lg);
  padding: var(--space-4);
  background: var(--surface);
  display: flex;
  flex-direction: column;
  min-height: 0;
  width: 100%;
  max-width: 100%;
  margin: 0;
  overflow-x: hidden;
  box-sizing: border-box;
  /* Deeper elevation in the overlay layer — the pane floats above the
     (now full-width) list, formalizing the workspace as its own surface. */
  box-shadow: var(--shadow-16);
  border: 1px solid var(--border);
}
.app-detail__body {
  display: grid;
  grid-template-rows: auto auto 1fr;
  gap: var(--space-3);
  min-height: 0;
  max-width: 100%;
}
.app-detail__title {
  font-size: var(--text-xl);
  font-weight: var(--weight-semibold);
  line-height: 1.25;
  margin: 0;
}
.app-detail__pane {
  overflow: auto;
  padding-top: var(--space-2);
}

.app-detail__error {
  color: var(--danger);
  padding: var(--space-4);
}

/* ---------- Managed identities view ---------- */
.mi-view {
  display: grid;
  grid-template-rows: auto 1fr;
  gap: var(--space-3);
  height: 100%;
  min-height: 0;
}
.mi-view__intro {
  color: var(--text-muted);
}
.mi-view__body {
  /* Full-width list — a selected identity opens in the shell's workspace
     overlay (a self-contained ManagedIdentityDetailWindow), not a side pane. */
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-3);
  min-height: 0;
}
.mi-view__list {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--surface);
  box-shadow: var(--shadow-2);
  /* Scrolling lives in the inner virtualized `.app-list__scroller`, so the
     search/type filters stay pinned (matching the other two lists). */
  min-height: 0;
  padding: var(--space-2);
}
/* The managed-identity detail window in the workspace pane. Mirrors the old
   `.mi-view__detail` card (whole-card scroll), filling the pane below its bar. */
.workspace__pane .mi-window {
  flex: 1 1 auto;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--surface);
  box-shadow: var(--shadow-16);
  overflow: auto;
  min-height: 0;
  padding: var(--space-4);
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}
/* One tab body in the managed-identity detail pane — vertical rhythm between
   its stacked sections (held panel, grant picker, Azure RBAC). */
.mi-tab {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  margin-top: var(--space-3);
}
.mi-properties {
  display: grid;
  grid-template-columns: max-content 1fr;
  gap: var(--space-1) var(--space-3);
  align-items: baseline;
  padding: var(--space-3);
  background: var(--bg-subtle);
  border-radius: var(--radius-md);
}
.mi-properties dt {
  font-size: var(--text-xs);
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.mi-properties dd {
  margin: 0;
}
.mi-grant {
  display: grid;
  gap: var(--space-2);
}
.mi-scope-panel {
  display: grid;
  gap: var(--space-2);
  padding: var(--space-3);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--surface);
}
/* Collapsible scoping sections under the permissions table (Exchange /
   SharePoint) — bordered so they read as tools, not more table rows. */
.detail-section {
  display: grid;
  gap: var(--space-2);
  padding: var(--space-3);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--surface);
}
.detail-section__controls {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}
.hint {
  color: var(--text-muted);
  font-size: var(--text-xs);
}
.hint--field {
  display: block;
  margin-top: var(--space-1);
}
/* Inline validation hint under a filter input (e.g. an unparseable date). */
.filter-hint {
  font-size: var(--text-xs);
  margin-top: var(--space-1);
}
.filter-hint--warn {
  color: var(--warning);
}

/* ---------- Tables ---------- */
.data-table {
  width: 100%;
  border-collapse: collapse;
  margin-top: var(--space-2);
}
/* DataTable's no-rows placeholder — muted so it reads as state, not content. */
.data-table__empty {
  display: block;
  color: var(--text-muted);
  padding: var(--space-3) 0;
}
/* Wrapping row of permission-scope chips (consent-grant audit). */
.scope-chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-1);
}
/* Enterprise-app owners list: name over UPN. */
.owner-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}
.owner-list li {
  display: flex;
  flex-direction: column;
}
/* List filter chips — the shared facet bar on the App Reg / Enterprise / MI
   lists (replaces the old hidden Select dropdowns). Each chip is a plain button
   (FilterChip) carrying a label + live count; the active one is accented and a
   zero-count chip mutes + disables. */
.app-list__filters,
.filter-chips {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-1);
}
/* One bound of the created-on range filter: a label over a native
   `<input type="date">` plus a clear button. The X resets the bound to "unset";
   a native date input honors an empty controlled value, so this turns a bound
   back off. */
.date-range-field {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.date-range-field__label {
  font-size: var(--text-xs);
  color: var(--text-muted);
}
.date-range-field__input {
  display: flex;
  align-items: center;
  gap: var(--space-1);
}
.date-range-field__native {
  font: inherit;
  color: var(--text);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: var(--space-1) var(--space-2);
}
.date-range-field__clear {
  flex: none;
}

/* Collapsible-filters toggle: a compact button that expands/collapses the
   advanced filter drawer (saved views, created-on range, facet chips), badging
   the active-filter count so a collapsed filter stays discoverable. */
.filter-toggle {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  align-self: flex-start;
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  background: var(--surface);
  color: var(--text);
  font: inherit;
  font-size: var(--text-sm);
  padding: 2px 10px;
  cursor: pointer;
}
.filter-toggle:hover {
  background: var(--surface-hover, var(--surface));
}
.filter-toggle__badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 16px;
  height: 16px;
  padding: 0 var(--space-1);
  border-radius: var(--radius-pill);
  background: var(--accent, var(--danger));
  color: #fff;
  font-size: var(--text-xs);
}
.filter-toggle__chevron {
  display: inline-flex;
  color: var(--text-muted);
}
.filter-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  background: var(--surface);
  color: var(--text);
  cursor: pointer;
  font: inherit;
  font-size: var(--text-xs);
  line-height: 1.6;
  padding: 1px var(--space-2);
  white-space: nowrap;
  transition: background-color var(--motion-fast) var(--ease-standard),
    border-color var(--motion-fast) var(--ease-standard);
}
.filter-chip:hover:not(:disabled) {
  border-color: var(--border-strong);
  background: var(--bg-subtle);
}
.filter-chip--active {
  background: var(--accent-soft);
  border-color: var(--accent);
  color: var(--accent);
  font-weight: var(--weight-semibold);
}
.filter-chip:disabled {
  /* Mute via colour, not opacity: 0.4 opacity over already-muted text landed
     well under 3:1, making a zero-count facet effectively unreadable rather
     than merely de-emphasised. */
  color: var(--text-faint);
  cursor: default;
}
.filter-chip__count {
  font-size: var(--text-caption);
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}
.filter-chip--active .filter-chip__count {
  color: var(--accent);
}

/* Saved filter views — a row of pinnable facet+search chips. */
.saved-views {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  margin: var(--space-2) 0;
}
.saved-view-chip {
  display: inline-flex;
  align-items: center;
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  background: var(--surface);
  overflow: hidden;
  white-space: nowrap;
}
.saved-view-chip__apply {
  border: none;
  background: transparent;
  color: var(--text);
  cursor: pointer;
  padding: 2px var(--space-2);
  font-size: var(--text-xs);
}
.saved-view-chip__apply:hover {
  color: var(--accent);
}
.saved-view-chip__remove {
  border: none;
  background: transparent;
  color: var(--text-faint);
  cursor: pointer;
  padding: 2px var(--space-2);
  border-left: 1px solid var(--border);
}
.saved-view-chip__remove:hover {
  color: var(--danger);
}
.saved-views__add,
.saved-views__naming button {
  border: 1px dashed var(--border-strong);
  background: transparent;
  color: var(--text-muted);
  cursor: pointer;
  padding: 2px var(--space-2);
  border-radius: var(--radius-pill);
  font-size: var(--text-xs);
}
.saved-views__naming {
  display: inline-flex;
  gap: var(--space-1);
  align-items: center;
}
.saved-views__input {
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 2px var(--space-2);
  font-size: var(--text-xs);
}

/* Enterprise-app provisioning job card. */
.prov-job {
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: var(--space-3);
  margin-top: var(--space-2);
}

/* Home dashboard */
.dashboard {
  padding: var(--space-5);
}
.dash-grid {
  display: grid;
  /* `min(100%, 280px)` keeps the track from ever exceeding its column, so on a
     phone the cards drop to one column instead of forcing horizontal overflow. */
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 280px), 1fr));
  gap: var(--space-4);
  margin-top: var(--space-4);
}
.dash-card {
  background: var(--surface-raised);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: var(--space-4);
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  box-shadow: var(--shadow-2);
}
.dash-card__title {
  margin: 0;
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--text-md);
  font-weight: var(--weight-semibold);
}
/* Hero total on the inventory tiles, larger than the breakdown sub-metrics. */
.dash-card__count {
  font-size: 32px;
  font-weight: var(--weight-semibold);
  line-height: 1;
}
/* Card action row. `margin-top: auto` pins it to the bottom of the flex-column
   card so every card's buttons align to a common baseline across the row,
   regardless of how much content (counts / metrics / findings) sits above. */
.dash-card__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-top: auto;
}
.dash-metrics {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4);
}
.dash-metric {
  display: flex;
  flex-direction: column;
}
.dash-metric__num {
  font-size: var(--text-xl);
  font-weight: var(--weight-semibold);
  color: var(--text-muted);
  line-height: 1.1;
}
.dash-metric__num--danger {
  color: var(--danger);
}
.dash-metric__num--warning {
  color: var(--warning);
}
.dash-metric__num--muted {
  color: var(--text-muted);
}
.dash-metric__label {
  font-size: var(--text-xs);
  color: var(--text-muted);
}
/* Dashboard metric box. `--box` is the shared geometry — used by zero-count,
   non-interactive metrics so they line up with their clickable siblings in the
   same row (and by the Security workbench's read-only posture strip); `--link`
   adds the clickable affordance. */
.dash-metric--box,
.dash-metric--link {
  align-items: flex-start;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--surface);
  padding: var(--space-2) 14px;
  text-align: left;
  font: inherit;
}
.dash-metric--link {
  cursor: pointer;
}
.dash-metric--link:hover {
  border-color: var(--text-muted);
}
.dash-metric--link:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
}
.dash-links {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}
.dash-link {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2);
  border: none;
  background: transparent;
  color: var(--text);
  border-radius: var(--radius-md);
  cursor: pointer;
  font-size: var(--text-base);
  text-align: left;
}
.dash-link:hover {
  background: var(--accent-soft);
  color: var(--accent);
}
/* Home Security Posture card: a severity row (large drill boxes) above a ranked
   "Top findings" list that rhymes with the Security workbench's Findings pane
   (tone dot · title · count · chevron). Same drill targets, scannable order. */
.posture-severities {
  gap: var(--space-2);
}
.posture-severities .dash-metric {
  flex: 1 1 0;
}
.posture-severities .dash-metric__num {
  font-size: 28px;
}
.posture-findings {
  display: grid;
  /* `minmax(0, 1fr)`, never the implicit `auto` track: a row's min-content
     contribution includes its `white-space: nowrap` title in full, so an `auto`
     track grows to the longest finding name ("Legacy Application Access Policy
     scoping") and the count + chevron get pushed outside the card's border. The
     0 floor lets the track be narrower than its content so the title's own
     ellipsis does the work instead. */
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-1);
}
.posture-finding {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  width: 100%;
  /* There is no global `* { box-sizing: border-box }` in this sheet, so
     `width: 100%` + padding would otherwise measure 100% PLUS 16px and spill
     past the track this row was just constrained to. */
  box-sizing: border-box;
  /* A flex container's automatic minimum size is its content's; without this
     the row refuses to shrink below the full title width and overflows. */
  min-width: 0;
  padding: var(--space-2);
  border: none;
  border-radius: var(--radius-md);
  background: transparent;
  color: var(--text);
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.posture-finding:hover {
  background: var(--accent-soft);
}
.posture-finding:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
}
.posture-finding__title {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.posture-finding__count {
  /* Never shrink: the title is the flexible element, and a squeezed count
     would wrap or clip the very number the row exists to show. */
  flex: none;
  font-weight: var(--weight-semibold);
  font-variant-numeric: tabular-nums;
}
.posture-finding__count--critical,
.posture-finding__count--danger {
  color: var(--danger);
}
.posture-finding__count--warning {
  color: var(--warning);
}
.posture-finding__count--ok {
  color: var(--text-muted);
}
.posture-finding__chevron {
  flex: none;
  color: var(--text-muted);
}
.data-table th,
.data-table td {
  text-align: left;
  padding: 6px var(--space-2);
  border-bottom: 1px solid var(--border);
  vertical-align: top;
}
.data-table th {
  font-weight: 600;
  background: var(--bg-subtle);
}
/* Keyboard navigation: rows are focusable via a roving tabindex (see
   hooks/use_grid_keynav). Arrow keys move focus; the focused row gets a clear
   ring + tint, and Enter opens it. */
.data-table tbody tr[tabindex] {
  cursor: default;
}
.data-table tbody tr:focus {
  outline: none;
}
.data-table tbody tr:focus-visible {
  outline: none;
  box-shadow: inset var(--focus-ring);
  background: var(--accent-soft);
}

/* ---------- Tabs (Owners / Permissions / Credentials) ---------- */
.owners-tab,
.permissions-tab,
.credentials-tab,
.overview-tab,
.activity-tab,
.authentication-tab,
.conditional-access-tab,
.audit-view {
  display: grid;
  gap: var(--space-4);
}
/* The enterprise pane's own tab roots. These classes existed in the markup but
   had NO rule at all, so those tabs had no vertical rhythm of their own — the
   spacing between "Assigned users & groups", "Grant access" and "Group
   memberships" was whatever the UA's <h4> margins collapsed to, while every
   sibling tab above is a grid with a token gap. */
.ent-access,
.ent-owners {
  display: grid;
  gap: var(--space-4);
}
/* Zero the UA <h4> margin once the grid gap owns the rhythm — keeping both
   doubles the space above every section. (`.sso-tab h4` keeps its own margin
   because that root is a flex column with a smaller gap.) */
.ent-access h4,
.ent-owners h4 {
  margin: 0;
}
/* Per-app sign-in summary above the change log (Activity tab). */
.signin-summary {
  display: grid;
  gap: var(--space-2);
  padding-bottom: var(--space-3);
  border-bottom: 1px solid var(--border);
}
.signin-summary .alert {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
}
.tool-page {
  display: grid;
  gap: var(--space-3);
  max-width: 960px;
}
.candidates {
  list-style: none;
  padding: 0;
  margin: 0;
  display: grid;
  gap: var(--space-1);
}
.candidates li {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 6px var(--space-2);
  border-radius: var(--radius-sm);
  background: var(--bg-subtle);
}
.small {
  font-size: var(--text-xs);
}
.vault-picker {
  margin-top: var(--space-1);
}
.vault-picker__count {
  margin-bottom: var(--space-1);
}
.vault-picker__list {
  list-style: none;
  padding: 2px;
  margin: 0;
  display: grid;
  gap: 2px;
  max-height: 200px;
  overflow-y: auto;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
}
.vault-picker__option {
  display: block;
  width: 100%;
  /* Fills its container, then adds padding — and this sheet has no global
     `* { box-sizing: border-box }`, so without this the row renders wider
     than the box it was meant to fill by exactly its horizontal padding. */
  box-sizing: border-box;
  text-align: left;
  padding: 6px var(--space-2);
  background: transparent;
  border: none;
  border-radius: var(--radius-sm);
  color: inherit;
  font: inherit;
  cursor: pointer;
}
.vault-picker__option:hover {
  background: var(--bg-subtle);
}
.vault-picker__option--selected {
  background: var(--accent-soft);
  font-weight: 600;
}
.checkbox-row {
  display: flex;
  gap: 6px;
  align-items: center;
}
.checkbox-list {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  margin: var(--space-2) 0;
}
.radio-row {
  display: flex;
  gap: var(--space-2);
  align-items: flex-start;
  padding: var(--space-1) 0;
}

/* ---------- Modal ---------- */
.modal-backdrop {
  position: fixed;
  inset: 0;
  background: var(--scrim);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 1000;
  animation: ui-fade-in var(--motion-base) var(--ease-decel);
}
.modal {
  background: var(--surface-raised);
  color: var(--text);
  padding: var(--space-5);
  border-radius: var(--radius-xl);
  width: min(720px, 92vw);
  max-height: 88vh;
  display: grid;
  gap: var(--space-3);
  box-shadow: var(--shadow-16);
  border: 1px solid var(--border);
  animation: ui-pop-in var(--motion-slow) var(--ease-decel);
  overflow: auto;
}
.modal--wide {
  width: min(880px, 92vw);
}

/* Command palette (Cmd/Ctrl-K). Reuses .modal-backdrop for the scrim but
   anchors the box near the top like VS Code / Linear. */
.cmd-palette__backdrop {
  align-items: flex-start;
}
.cmd-palette {
  margin-top: 12vh;
  width: min(560px, 92vw);
  background: var(--surface-raised);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-16);
  overflow: hidden;
  animation: ui-pop-in var(--motion-base) var(--ease-decel);
}
.cmd-palette__input {
  width: 100%;
  box-sizing: border-box;
  border: none;
  outline: none;
  background: transparent;
  color: var(--text);
  font-size: var(--text-md);
  padding: var(--space-4);
  border-bottom: 1px solid var(--border);
}
.cmd-palette__list {
  list-style: none;
  margin: 0;
  padding: var(--space-1);
  max-height: 46vh;
  overflow: auto;
}
.cmd-palette__item {
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-md);
  cursor: pointer;
  font-size: var(--text-base);
}
.cmd-palette__item--active {
  background: var(--accent-soft);
  color: var(--accent);
}
.cmd-palette__empty {
  padding: var(--space-3);
  color: var(--text-muted);
  font-size: var(--text-sm);
}
@keyframes ui-fade-in {
  from { opacity: 0; }
  to { opacity: 1; }
}
@keyframes ui-pop-in {
  from { opacity: 0; transform: translateY(8px) scale(0.98); }
  to { opacity: 1; transform: translateY(0) scale(1); }
}
.secret-reveal {
  background: var(--bg-subtle);
  padding: var(--space-2);
  border-radius: var(--radius-sm);
  word-break: break-all;
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
  white-space: pre-wrap;
}

/* ---------- Bulk actions ---------- */
.selection-bar {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  margin-right: var(--space-2);
}
.selection-bar__count {
  font-size: var(--text-base);
  font-weight: var(--weight-medium);
  color: var(--text-muted);
}
.bulk-tab {
  display: grid;
  gap: var(--space-3);
  min-height: 120px;
}
.bulk-action {
  display: grid;
  gap: var(--space-3);
}
.bulk-action__danger {
  color: var(--danger);
}
/* Per-item failure list under a bulk-run summary — names which apps failed and
   why, instead of leaving the reasons buried in an aggregate count. */
.bulk-failures {
  display: grid;
  gap: var(--space-2);
  padding: var(--space-3);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--bg-subtle);
}
.bulk-failures__title {
  font-weight: 600;
  color: var(--danger);
}
.bulk-failures__list {
  margin: 0;
  padding-left: 20px;
  display: grid;
  gap: var(--space-1);
  font-size: var(--text-sm);
}
/* Type-to-confirm gate for irreversible bulk actions. The user must reproduce
   the literal keyword (REMOVE / DELETE) shown in the label. */
.confirm-gate {
  display: grid;
  gap: var(--space-2);
  padding: var(--space-3);
  border: 1px solid var(--danger);
  border-radius: var(--radius-md);
  background: var(--danger-soft);
}
.confirm-gate__label {
  color: var(--danger);
}
.confirm-gate__label strong {
  font-family: var(--font-mono);
  letter-spacing: 0.04em;
}

/* Inline bulk-action bar (shared by the Security Audit table, the App
   Registrations list, and the Bulk Actions page). Appears when ≥1 row is
   checked; the destructive-action confirm gate expands inline beneath it. */
.bulk-action-bar {
  display: grid;
  gap: var(--space-3);
  padding: var(--space-3);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--bg-subtle);
}
.bulk-action-bar__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
}
.bulk-action-bar__count {
  font-weight: var(--weight-medium);
  color: var(--text-muted);
  margin-right: auto;
}
.bulk-action-bar__confirm {
  display: grid;
  gap: var(--space-2);
}
.bulk-action-bar__scope-form {
  display: grid;
  gap: var(--space-2);
}
.bulk-action-bar__check {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--text-sm);
  color: var(--text-muted);
}

/* ---------- Audit view ---------- */
.audit-view {
  padding: 0;
}
.audit-progress {
  display: grid;
  gap: var(--space-2);
}
.issues {
  list-style: disc;
  padding-left: 20px;
  margin: 0;
}
/* Collapsed-tail hint for rows with more issues than ISSUES_INLINE. */
.issues__more {
  list-style: none;
  margin-left: -20px;
  color: var(--text-muted);
  font-size: var(--text-xs);
}
/* Clickable sort affordance in a table header — looks like the header text,
   not a button, until hovered. */
.th-sort {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  background: none;
  border: none;
  padding: 0;
  margin: 0;
  font: inherit;
  color: inherit;
  cursor: pointer;
  white-space: nowrap;
}
.th-sort:hover {
  color: var(--accent);
}
.th-sort:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
  border-radius: var(--radius-sm);
}
.audit-actions {
  display: grid;
  gap: var(--space-1);
  min-width: 12rem;
}
/* Stacks multiple remediation buttons (remove-expired + scope fixes) per row. */
.audit-actions-stack {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  min-width: 12rem;
}
.audit-actions__preview {
  color: var(--text-muted);
  font-size: var(--text-xs);
}
/* "Show more" footer under the windowed audit table. */
.show-more {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3) 0;
  color: var(--text-muted);
}
.muted {
  color: var(--text-muted);
}

.centered-pad {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-6);
}

/* ---------- Type chip (identity / permission kind) ---------- */
.type-chip {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  padding: 2px var(--space-2);
  border-radius: var(--radius-pill);
  font-size: var(--text-xs);
  line-height: 1.4;
  border: 1px solid var(--border);
  background: var(--bg-subtle);
  white-space: nowrap;
}
.type-chip__icon {
  width: 12px;
  height: 12px;
  flex-shrink: 0;
}
.type-chip__label {
  font-weight: 500;
}
.type-chip--app {
  background: var(--accent-soft);
  border-color: var(--accent);
  color: var(--accent);
}
.type-chip--ent {
  background: var(--accent-ent-soft);
  border-color: var(--accent-ent);
  color: var(--accent-ent);
}
.type-chip--mi {
  background: var(--accent-mi-soft);
  border-color: var(--accent-mi);
  color: var(--accent-mi);
}
.type-chip--mi-user {
  background: var(--accent-mi-user-soft);
  border-color: var(--accent-mi-user);
  color: var(--accent-mi-user);
}
.type-chip--perm-app {
  background: var(--accent-ent-soft);
  border-color: var(--accent-ent);
  color: var(--accent-ent);
}
.type-chip--perm-deleg {
  background: var(--accent-soft);
  border-color: var(--accent);
  color: var(--accent);
}
.type-chip--perm-unknown {
  background: var(--bg-subtle);
  border-color: var(--border);
  color: var(--text-muted);
}

/* ---------- Detail-pane header strip ---------- */
.detail-header {
  display: flex;
  gap: var(--space-2);
  align-items: center;
  flex-wrap: wrap;
}
.detail-header__pairing {
  margin-left: auto;
  font-size: var(--text-sm);
  color: var(--text-muted);
  display: flex;
  gap: var(--space-1);
  align-items: center;
}
.detail-header__pairing button {
  background: transparent;
  border: none;
  color: var(--accent);
  cursor: pointer;
  font: inherit;
  padding: 0;
  text-decoration: underline;
}

/* ---------- Row pairing arrow ---------- */
.pair-arrow {
  background: transparent;
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  color: var(--accent);
  cursor: pointer;
  font: inherit;
  font-size: var(--text-xs);
  line-height: 1;
  padding: 2px var(--space-2);
}
.pair-arrow:hover {
  background: var(--accent-soft);
}

/* ---------- Row meta (chips on a row) ---------- */
.row-meta {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

/* ---------- Global search (topbar) ---------- */
.global-search {
  position: relative;
  width: min(520px, 60vw);
}
.global-search__input {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: 5px 10px;
  transition: border-color var(--motion-base) var(--ease-standard),
    box-shadow var(--motion-base) var(--ease-standard);
}
.global-search__input:hover {
  border-color: var(--border-strong);
}
.global-search__input:focus-within {
  border-color: var(--accent);
  background: var(--surface);
  box-shadow: 0 0 0 3px var(--accent-soft);
}
.global-search__icon {
  width: 14px;
  height: 14px;
  color: var(--text-muted);
  flex-shrink: 0;
}
.global-search__field {
  background: transparent;
  border: none;
  outline: none;
  font: inherit;
  color: inherit;
  flex: 1;
  min-width: 0;
  padding: var(--space-1) 0;
}
.global-search__clear {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  padding: 0;
  flex-shrink: 0;
  background: transparent;
  border: none;
  border-radius: var(--radius-sm);
  color: var(--text-muted);
  cursor: pointer;
  transition: background-color var(--motion-fast) var(--ease-standard),
    color var(--motion-fast) var(--ease-standard);
}
.global-search__clear:hover {
  background: var(--bg-subtle);
  color: var(--text);
}
.global-search__clear:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
}
.global-search__results {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  right: 0;
  background: var(--surface-raised);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-16);
  max-height: 60vh;
  overflow: auto;
  z-index: 50;
  animation: ui-fade-in var(--motion-fast) var(--ease-decel);
}
.global-search__group-label {
  font-size: var(--text-caption);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-muted);
  padding: var(--space-2) var(--space-3) var(--space-1);
}
.global-search__row {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  cursor: pointer;
  background: transparent;
  border: none;
  width: 100%;
  /* Fills its container, then adds padding — and this sheet has no global
     `* { box-sizing: border-box }`, so without this the row renders wider
     than the box it was meant to fill by exactly its horizontal padding. */
  box-sizing: border-box;
  text-align: left;
  font: inherit;
  color: inherit;
  transition: background-color var(--motion-fast) var(--ease-standard);
}
.global-search__row:hover,
.global-search__row--active {
  background: var(--bg-subtle);
}
.global-search__row-title {
  font-size: var(--text-base);
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.global-search__row-appid {
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
  font-size: var(--text-caption);
  color: var(--text-muted);
}
.global-search__empty {
  padding: var(--space-3) var(--space-4);
  color: var(--text-muted);
  font-size: var(--text-sm);
}

/* ---------- Permissions tab (humanized) ---------- */
.permissions-tab .data-table td.permission-cell {
  vertical-align: top;
}
.permissions-cell__primary {
  font-weight: 500;
}
.permissions-cell__secondary {
  font-size: var(--text-caption);
  color: var(--text-muted);
}
.permissions-tab__filters {
  display: flex;
  gap: var(--space-2);
  margin-bottom: var(--space-2);
}
.permissions-tab__filter-chip {
  background: var(--bg-subtle);
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  padding: 2px 10px;
  font-size: var(--text-xs);
  cursor: pointer;
  font: inherit;
  white-space: nowrap;
}
.permissions-tab__filter-chip--on {
  background: var(--accent-soft);
  border-color: var(--accent);
  color: var(--accent);
}

/* ---------- Permission picker ---------- */
.permission-picker {
  margin: var(--space-3) 0;
  gap: var(--space-3);
}
.permission-picker__row {
  display: flex;
  gap: var(--space-3);
  flex-wrap: wrap;
  align-items: end;
}
.permission-picker__field {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  /* Shrinks below 220px on a very narrow detail pane instead of forcing
     horizontal overflow inside the wrapped picker row. */
  min-width: min(220px, 100%);
}
.permission-picker__field--grow { flex: 1 1 200px; }
.permission-picker__label {
  font-size: var(--text-xs);
  color: var(--text-muted);
}
.permission-picker__select {
  padding: 6px 10px;
  border-radius: var(--radius-md);
  border: 1px solid var(--border);
  background: var(--surface);
  font: inherit;
}
.permission-picker__list {
  list-style: none;
  padding: 0;
  margin: 0;
  max-height: 320px;
  overflow-y: auto;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--surface);
}
.permission-picker .permission-picker__row {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: var(--space-2);
  padding: 6px 10px;
  border-bottom: 1px solid var(--border);
}
.permission-picker .permission-picker__row:last-child { border-bottom: none; }
.permission-picker__row-chip { display: inline-flex; }
.permission-picker__row-text {
  display: flex;
  flex-direction: column;
  min-width: 0;
}
.permission-picker__row-sub {
  font-size: var(--text-xs);
  color: var(--text-muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* Grant-time least-privilege hints: a risk badge beside the value and a
   contextual scope note below it. */
.permission-picker__row-head {
  display: flex;
  align-items: center;
  gap: var(--space-1);
  min-width: 0;
}
.permission-picker__row-head > strong {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.permission-picker__row-note {
  font-size: var(--text-xs);
  margin-top: 2px;
}
.permission-picker__row-note--warn { color: var(--danger); }
.permission-picker__row-note--ok { color: var(--ok); }
/* The row's cart checkbox sits in the grid's trailing column (where the Grant
   button used to). */
.permission-picker__check {
  width: 16px;
  height: 16px;
  cursor: pointer;
}

/* The "Grant access" wizard's selection cart: removable chips above the picker. */
.scope-wizard__cart {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  margin: var(--space-2) 0;
}
.scope-wizard__chip {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  padding: 2px var(--space-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-pill, 999px);
  background: var(--surface);
  color: var(--text);
  font: inherit;
  font-size: var(--text-xs);
  cursor: pointer;
}
.scope-wizard__chip:hover { border-color: var(--danger); }

/* =====================================================================
 * UI primitives (.ui-*) — used by src/components/ui/*
 * =====================================================================*/

/* ---- Button ladder ----------------------------------------------------
 * One emphasis level per role, so every surface reads the same way:
 *   Primary   (ButtonAppearance::Primary)   — the ONE advancing action per
 *              surface (Run audit, New app, New SSO). At most one per group.
 *   Secondary (ButtonAppearance::Secondary) — alternatives / sibling actions
 *              (View all, Cancel, Show more).
 *   Subtle    (ButtonAppearance::Subtle)    — chrome (Export, dock/pane close,
 *              Full) and the .ui-icon-btn icon buttons.
 *   --danger  (.button--danger)             — destructive (Delete, Remove).
 * Catalog <Icon>s ride inside these — never a second glyph set — so the same
 * action shows the same icon everywhere (Plus = create, Close = dismiss). */

/* A Primary/Subtle text button that leads or trails a catalog <Icon>: thaw's
   .thaw-button is inline-flex but sets no gap, so add one. */
.btn-icon-label {
  gap: var(--space-1);
}

/* ---- Export disclosure (Security tab) ----
   A plain-DOM dropdown (mirrors `.shell__account-menu`), NOT a Thaw `Menu`:
   the export opens the native save dialog, and triggering that from inside a
   teleported Thaw overlay froze the webview on WebView2 as the overlay tore
   down. `.export-menu` is the positioning context; the panel opens downward,
   right-aligned to the trigger. */
.export-menu {
  position: relative;
  display: inline-flex;
}
.export-menu__panel {
  position: absolute;
  top: calc(100% + var(--space-1));
  right: 0;
  min-width: 200px;
  z-index: 60;
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: var(--space-1);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-4);
}
.export-menu__item {
  display: flex;
  align-items: center;
  padding: var(--space-2) var(--space-3);
  border: none;
  background: transparent;
  border-radius: var(--radius-sm);
  color: inherit;
  font: inherit;
  font-size: var(--text-base);
  text-align: left;
  white-space: nowrap;
  cursor: pointer;
}
.export-menu__item:hover {
  background: var(--bg-subtle);
}
.export-menu__item:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
}

/* ---- Card ---- */
.ui-card {
  background: var(--surface-raised);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: var(--space-4);
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}
.ui-card--e1 { box-shadow: var(--shadow-2); }
.ui-card--e2 { box-shadow: var(--shadow-4); }
.ui-card--e3 { box-shadow: var(--shadow-8); }
.ui-card--padless { padding: 0; }

/* ---- Certificate file picker ---- */
.file-input {
  color: var(--text);
  font: inherit;
}
.file-input::file-selector-button {
  background: var(--surface-raised);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: var(--space-1) var(--space-3);
  margin-right: var(--space-2);
  cursor: pointer;
}

/* ---- CopyableId ---- */
.copyable-id {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  white-space: nowrap;
}

.copyable-id__copied {
  color: var(--ok);
  font-size: var(--text-xs);
}

.open-dock__hint {
  color: var(--text-muted);
  font-size: var(--text-xs);
  white-space: nowrap;
}

/* ---- IconButton ---- */
.ui-icon-btn {
  width: 32px;
  height: 32px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: 1px solid transparent;
  border-radius: var(--radius-md);
  color: var(--text-muted);
  cursor: pointer;
  padding: 0;
  transition: background-color var(--motion-fast) var(--ease-standard),
    color var(--motion-fast) var(--ease-standard),
    border-color var(--motion-fast) var(--ease-standard);
}
.ui-icon-btn:hover {
  background: var(--bg-subtle);
  color: var(--text);
}
.ui-icon-btn:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
}
.ui-icon-btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}
/* While busy the spinner should stay crisp (not dimmed) and signal progress. */
.ui-icon-btn--busy:disabled {
  opacity: 1;
  cursor: progress;
}
.ui-icon-btn--subtle-border {
  border-color: var(--border);
}

/* ---- Select (dropdown) ---- */
/* The app had NO select styling at all: both the Access tab's "Role" picker and
   the SSO tab's "Set sign-on method" rendered as raw native <select>s — browser
   grey 1px border, square corners, zero padding, and a font the UA picked
   (Arial), so they didn't even inherit the app's typeface. Next to the app's
   rounded, padded inputs and buttons they read as someone else's control.
   Metrics deliberately match `.thaw-input` / `.ui-icon-btn` (32px box,
   --radius-md) so a select can sit beside either without a seam.
   Applied via `.ui-select`; `.thaw-select` is swept in too so thaw's own Select
   (claims editor) lands in the same language instead of thaw's separate token
   set. */
.ui-select,
.thaw-select {
  -webkit-appearance: none;
  appearance: none;
  box-sizing: border-box;
  width: 100%;
  min-height: 32px;
  /* Right padding leaves room for the chevron; without it a long option label
     runs underneath the arrow. */
  padding: 0 calc(var(--space-5) + var(--space-1)) 0 var(--space-2);
  border: 1px solid var(--border);
  /* --radius-sm, not --radius-md: these sit inline with thaw `Input`s in the
     same form (Access tab: Role above the directory search), and thaw's
     `--borderRadiusMedium` resolves to 4px. 6px here left a visible seam. */
  border-radius: var(--radius-sm);
  background-color: var(--surface);
  color: var(--text);
  font-family: inherit;
  font-size: var(--text-base);
  line-height: 30px;
  cursor: pointer;
  transition: border-color var(--motion-fast) var(--ease-standard),
    background-color var(--motion-fast) var(--ease-standard);

  /* Chevron. `appearance: none` removes the native arrow, so one is drawn here
     as an inline SVG data URI — no network request (the CSP forbids one) and no
     extra wrapper element to hang a pseudo-element on, since these are bare
     <select>s inside a thaw Field. The stroke is baked into the URI and so
     cannot use a CSS variable; the dark-mode override below swaps the whole
     image. Keep the two in sync. */
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%235b5b5b' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right var(--space-2) center;
  background-size: 16px 16px;
}
.ui-select:hover,
.thaw-select:hover {
  border-color: var(--border-strong);
  background-color: var(--bg-subtle);
}
.ui-select:focus-visible,
.thaw-select:focus-visible {
  outline: none;
  border-color: var(--accent);
  box-shadow: var(--focus-ring);
}
.ui-select:disabled,
.thaw-select:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}
/* The popup list is drawn by the OS; `color-scheme` on :root does the heavy
   lifting, but naming the colours keeps Linux/Chrome from falling back to white
   rows on a dark page. */
.ui-select option,
.thaw-select option {
  background-color: var(--surface);
  color: var(--text);
}
@media (prefers-color-scheme: dark) {
  .ui-select,
  .thaw-select {
    background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23b0b0b0' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  }
}

/* ---- SearchInput clear (×) ---- */
/* Sits in the Thaw input suffix slot; appears only when the field is non-empty
   (the component gates the render). Sized to match the suffix icon row. */
.search-input__clear {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  padding: 0;
  margin: 0;
  background: transparent;
  border: none;
  border-radius: var(--radius-sm);
  color: var(--text-muted);
  cursor: pointer;
  transition: background-color var(--motion-fast) var(--ease-standard),
    color var(--motion-fast) var(--ease-standard);
}
.search-input__clear:hover {
  background: var(--bg-subtle);
  color: var(--text);
}
.search-input__clear:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
}

/* ---- EmptyState ---- */
.ui-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-3);
  padding: var(--space-6);
  text-align: center;
  color: var(--text-muted);
  border-radius: var(--radius-lg);
  background: var(--surface);
  border: 1px dashed var(--border);
  min-height: 200px;
}
.ui-empty__icon {
  width: 40px;
  height: 40px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--radius-pill);
  background: var(--bg-subtle);
  color: var(--text-muted);
}
.ui-empty__title {
  font-size: var(--text-md);
  font-weight: var(--weight-semibold);
  color: var(--text);
  margin: 0;
}
.ui-empty__body {
  font-size: var(--text-sm);
  max-width: 360px;
  line-height: 1.5;
}

/* ---- Load-error (DetailLoadError): the one "section failed → Retry" block ---- */
.ui-load-error {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-2);
  color: var(--danger);
}
.ui-load-error__code {
  opacity: 0.6;
  font-size: 0.85em;
}

/* ---- Skeleton ---- */
.ui-skel {
  display: block;
  border-radius: var(--radius-sm);
  background: linear-gradient(
    90deg,
    var(--bg-subtle) 0%,
    rgba(0, 0, 0, 0.06) 50%,
    var(--bg-subtle) 100%
  );
  background-size: 200% 100%;
  animation: ui-skel-shimmer 1.4s linear infinite;
}
@media (prefers-color-scheme: dark) {
  .ui-skel {
    background: linear-gradient(
      90deg,
      var(--bg-subtle) 0%,
      rgba(255, 255, 255, 0.08) 50%,
      var(--bg-subtle) 100%
    );
    background-size: 200% 100%;
  }
}
@keyframes ui-skel-shimmer {
  0% { background-position: 100% 0; }
  100% { background-position: -100% 0; }
}
.ui-skel-list {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  padding: var(--space-1);
}
.ui-skel-row {
  height: 52px;
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: 0 var(--space-2);
}
.ui-skel-row__chip { width: 56px; height: 18px; border-radius: var(--radius-pill); }
.ui-skel-row__title { flex: 1; height: 12px; max-width: 60%; }

/* ---- Kbd ---- */
.ui-kbd {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  font-family: var(--font-mono);
  font-size: var(--text-caption);
  background: var(--bg-subtle);
  border: 1px solid var(--border);
  border-bottom-width: 2px;
  border-radius: var(--radius-sm);
  padding: 1px 5px;
  color: var(--text-muted);
  line-height: 1.2;
}


/* ---- TabBar (underline) ---- */
.ui-tabs {
  display: flex;
  gap: var(--space-1);
  border-bottom: 1px solid var(--border);
  margin-bottom: var(--space-3);
  overflow-x: auto;
  scrollbar-width: thin;
}
.ui-tabs__btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  background: transparent;
  border: none;
  font: inherit;
  font-size: var(--text-base);
  font-weight: var(--weight-medium);
  color: var(--text-muted);
  padding: 10px var(--space-3);
  cursor: pointer;
  white-space: nowrap;
  transition: color var(--motion-base) var(--ease-standard);
}
.ui-tabs__btn:hover {
  color: var(--text);
}
.ui-tabs__btn--active {
  color: var(--accent);
  font-weight: var(--weight-semibold);
}
.ui-tabs__btn--active::after {
  content: "";
  position: absolute;
  left: 12px;
  right: 12px;
  bottom: -1px;
  height: 2px;
  background: var(--accent);
  border-radius: var(--radius-pill);
  animation: ui-tab-slide var(--motion-base) var(--ease-decel);
}
.ui-tabs__btn:focus-visible {
  outline: none;
  box-shadow: inset 0 0 0 2px var(--accent);
  border-radius: var(--radius-sm);
}
@keyframes ui-tab-slide {
  from { transform: scaleX(0.4); opacity: 0; }
  to { transform: scaleX(1); opacity: 1; }
}

/* Settings — per-tenant operator defaults, grouped into tabbed panes
   (App Registration / Enterprise Application / Naming). Constrain the form
   width for readability; the active pane and its sections stack with even
   vertical rhythm. */
.settings-view { max-width: 760px; }
.settings-editor {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}
.settings-tab {
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
}
.settings-section {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}
.settings-section h3 {
  margin: 0;
  font-size: var(--text-base);
  font-weight: var(--weight-semibold);
}

/* "New application" chooser — two large option buttons (Browse gallery / Create
   your own) in the New-application flow. */
.new-app-choices {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  margin: var(--space-2) 0;
}
.new-app-choice {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  padding: var(--space-3);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--surface);
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
  transition: border-color var(--motion-base) var(--ease-standard);
}
.new-app-choice:hover {
  border-color: var(--accent);
  background: var(--accent-soft);
}
.new-app-choice:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
}
.new-app-choice__icon {
  display: inline-flex;
  color: var(--accent);
  flex-shrink: 0;
  margin-top: 2px;
}
.new-app-choice__body {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
.new-app-choice__title {
  font-weight: var(--weight-semibold);
}
.new-app-choice__desc {
  font-size: var(--text-sm);
  color: var(--text-muted);
}

/* Gallery-browse modal — search + a picker list of application templates. */
.gallery-browse,
.gallery-confirm {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}
.gallery-results {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: var(--space-1);
  max-height: 320px;
  overflow-y: auto;
}
.gallery-result {
  display: flex;
  flex-direction: column;
  gap: 2px;
  width: 100%;
  /* Fills its container, then adds padding — and this sheet has no global
     `* { box-sizing: border-box }`, so without this the row renders wider
     than the box it was meant to fill by exactly its horizontal padding. */
  box-sizing: border-box;
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--surface);
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.gallery-result:hover {
  border-color: var(--accent);
  background: var(--accent-soft);
}
.gallery-result:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
}
.gallery-result--selected {
  cursor: default;
  border-color: var(--accent);
}
.gallery-result__name {
  font-weight: var(--weight-semibold);
}
.gallery-result__publisher {
  font-size: var(--text-sm);
  color: var(--text-muted);
}
.gallery-result__modes {
  font-size: var(--text-xs);
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.03em;
}

/* ---- SectionHeader ---- */
.ui-section-header {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--space-3);
  margin-bottom: var(--space-4);
  flex-wrap: wrap;
}
.ui-section-header__group {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  min-width: 0;
}
.ui-section-header__crumb {
  font-size: var(--text-xs);
  color: var(--text-muted);
  letter-spacing: 0.02em;
  text-transform: uppercase;
}
.ui-section-header__title {
  font-size: var(--text-xl);
  font-weight: var(--weight-semibold);
  margin: 0;
  letter-spacing: -0.01em;
}
.ui-section-header__actions {
  display: flex;
  gap: var(--space-2);
  flex-wrap: wrap;
}

/* =====================================================================
 * Responsive breakpoints
 * ===================================================================== */

/* Below 1024px: collapse sidebar to icons-only */
@media (max-width: 1024px) {
  :root {
    --nav-width: var(--nav-width-collapsed);
  }
  .shell__brand {
    justify-content: center;
    padding: var(--space-3) var(--space-2);
  }
  .shell__brand-text { display: none; }
  .shell__nav-section-label { display: none; }
  .nav__item .nav__label { display: none; }
  .nav__item {
    justify-content: center;
    padding: 10px var(--space-2);
  }
  .nav__item--selected::before { left: 0; }
  /* The centred search is capped at `min(520px, 60vw)` — but 60vw measures the
     whole window, not the space left beside the tenant chip, so once the nav
     collapses the field kept its full width and the topbar's right third was
     squeezed until "Contoso Ltd" rendered as "C..". Make the search yield
     first: a shorter search field still works, a tenant name cut to an initial
     does not. */
  .global-search { width: min(520px, 38vw); }
}

/* Below 740px: tighten topbar; collapse side-by-side compare to one pane.
   (All three lists are full-width now — detail opens in the workspace overlay.) */
@media (max-width: 740px) {
  /* One pane at a time on narrow screens — side-by-side compare needs width.
     Still `minmax(0, ...)`: this is the width-starved case, so the pane must be
     allowed to be narrower than its content and scroll inside itself. */
  .workspace__panes--two {
    grid-template-columns: minmax(0, 1fr);
  }
  .shell__topbar {
    padding: 0 var(--space-3);
  }
  .shell__topbar-left { display: none; }
  /* Compact the tenant chip to just the org name (drop the domain line). */
  .shell__tenant-chip-domain { display: none; }
  .shell__content { padding: var(--space-3); }
  .global-search { width: 100%; }
  .dashboard { padding: var(--space-4); }
}

/* Phones: narrow the icon rail further, drop cards to one column, near-full-bleed
   dialogs, and let dense editor grids / action clusters stack instead of
   overflowing the row. */
@media (max-width: 560px) {
  :root {
    --nav-width: 48px;
  }
  /* The pill is now the ONLY path to the account menu (Settings, Sign Out, …),
     so keep it reachable — collapse it to the icon + chevron instead of hiding
     the whole chip. */
  .shell__tenant-chip-text { display: none; }
  .nav__item {
    padding: 10px 6px;
  }
  .shell__content {
    padding: var(--space-2);
  }
  .dashboard {
    padding: var(--space-3);
  }
  .dash-grid {
    grid-template-columns: 1fr;
    gap: var(--space-3);
    margin-top: var(--space-3);
  }
  .ui-section-header__title {
    font-size: var(--text-md);
  }
  .selection-bar,
  .list-header-actions {
    flex-wrap: wrap;
  }
  /* Dialogs take nearly the full width with tighter padding so their content
     isn't boxed into a sliver. */
  .modal,
  .modal--wide {
    width: 96vw;
    padding: var(--space-4);
    max-height: 92vh;
  }
  /* Multi-column editor rows collapse to a single stacked column. */
  .sso-claims__row,
  .claims-editor__basic-ref-grid {
    grid-template-columns: 1fr;
  }
  /* Denser table cells so more columns fit before the text squeezes. */
  .data-table th,
  .data-table td {
    padding: 5px 6px;
    font-size: var(--text-xs);
  }
  .demo-banner {
    padding: var(--space-2) var(--space-3);
    font-size: var(--text-xs);
  }
}

/* =====================================================================
 * Toasts
 * ===================================================================== */
/* Fixed bottom-right stack, above dialogs (the modal scrim is z-index:1000). */
.toast-host {
  position: fixed;
  right: var(--space-4);
  bottom: var(--space-4);
  z-index: 1100;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  max-width: min(420px, calc(100vw - var(--space-6)));
  pointer-events: none; /* let clicks through gaps; toasts re-enable below */
}
.toast {
  pointer-events: auto;
  display: flex;
  align-items: flex-start;
  gap: var(--space-2);
  padding: 10px var(--space-3);
  border-radius: var(--radius-md);
  background: var(--surface-raised);
  border: 1px solid var(--border);
  box-shadow: var(--shadow-16);
  color: var(--text);
  font-size: var(--text-sm);
  animation: ui-fade-in var(--motion-base) var(--ease-decel);
}
.toast--ok {
  border-color: var(--ok);
  background: var(--ok-soft);
}
.toast--error {
  border-color: var(--danger);
  background: var(--danger-soft);
}
.toast--info {
  border-color: var(--accent);
  background: var(--accent-soft);
}
.toast__icon {
  display: inline-flex;
  flex: 0 0 auto;
  margin-top: 1px;
}
.toast__message {
  flex: 1 1 auto;
  min-width: 0;
  word-break: break-word;
}
.toast__action {
  flex: 0 0 auto;
  background: transparent;
  border: 1px solid var(--accent);
  color: var(--accent);
  border-radius: var(--radius-sm);
  padding: 2px var(--space-2);
  font-size: var(--text-xs);
  cursor: pointer;
}
.toast__action:hover {
  background: var(--accent-soft);
}
.toast__action:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
}
.toast__close {
  flex: 0 0 auto;
  background: transparent;
  border: none;
  color: var(--text-muted);
  cursor: pointer;
  font-size: var(--text-md);
  line-height: 1;
  padding: 0 2px;
}
.toast__close:hover {
  color: var(--text);
}
.toast__close:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
}

/* =====================================================================
 * SSO setup (wizard + detail tab)
 * ===================================================================== */
.sso-wizard__steps {
  margin-bottom: var(--space-2);
}
.sso-summary,
.sso-tab {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}
.sso-tab h4 {
  margin: var(--space-3, 12px) 0 0;
  /* Match the "Secrets (2)" section titles on the sibling tabs, which are a
     plain bold <strong> at body size — an <h4> defaults smaller, so the SSO
     tab's sections read as a different rank of heading than everyone else's. */
  font-size: var(--text-base);
}
/* `.sso-tab` is a stretch flex column, so every direct child filled the pane —
   including the buttons, which rendered as full-width bars. Nothing else in the
   app does that: an action sits at its natural width. */
.sso-tab > .thaw-button {
  align-self: flex-start;
}
.sso-field {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.sso-field__label {
  font-size: var(--text-base);
  font-weight: var(--weight-medium);
  color: var(--text-muted);
}
.sso-field__value {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  word-break: break-all;
}
.sso-block {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}
/* "Copy all details" sits between the lede and the fields it copies, so the
   affordance is visible before the operator starts copying values one at a
   time. Left-aligned and not stretched: it is one action, not a form row. */
.sso-summary__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-bottom: var(--space-1);
}
.sso-claims {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: var(--space-2);
}
.sso-claims__row {
  display: grid;
  grid-template-columns: 1fr 1fr auto;
  align-items: center;
  gap: var(--space-2);
}

/* Full attributes & claims editor (ClaimsEditor component). */
.claims-editor {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}
.claims-editor__basic,
.claims-editor__multi {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  font-size: var(--text-base);
}
.claims-editor__multi {
  font-size: var(--text-sm);
  color: var(--text-muted);
  white-space: nowrap;
}
.claims-editor__row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: var(--space-2);
}
.claims-editor__row > * {
  flex: 1 1 150px;
  min-width: 0;
}
.claims-editor__row > button {
  flex: 0 0 auto;
}
.claims-editor__transforms-head {
  margin-top: var(--space-2);
}
.claims-editor__transform {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: var(--space-2);
}
.claims-editor__transform-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
}
.claims-editor__transform-head > *:not(button) {
  flex: 1 1 160px;
  min-width: 0;
}
.claims-editor__sub {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  border-left: 2px solid var(--border);
  padding-left: var(--space-2);
  margin-left: var(--space-1);
}
.claims-editor__sub-label {
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  color: var(--text-muted);
}
.claims-editor__sub-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
}
.claims-editor__sub-row > *:not(button):not(label) {
  flex: 1 1 140px;
  min-width: 0;
}
.claims-editor__preserved {
  font-style: italic;
}

/* Read-only reference: the default SAML claims the "basic claim set" emits. */
.claims-editor__basic-ref {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: var(--space-2);
  font-size: var(--text-sm);
  color: var(--text-muted);
}
.claims-editor__basic-ref-caption {
  font-weight: var(--weight-medium);
}
.claims-editor__basic-ref-grid {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto auto;
  gap: var(--space-1) var(--space-3);
  align-items: baseline;
}
.claims-editor__basic-ref-actions {
  justify-self: end;
}
.claims-editor__basic-ref-head {
  font-weight: var(--weight-medium);
  color: var(--text);
}
.claims-editor__basic-ref-name {
  color: var(--text);
  white-space: nowrap;
}
.claims-editor__basic-ref-uri {
  font-family: var(--font-mono, monospace);
  word-break: break-all;
}
.claims-editor__basic-ref-src {
  font-family: var(--font-mono, monospace);
  white-space: nowrap;
}
.claims-editor__basic-ref-note {
  font-style: italic;
}

/* =====================================================================
 * Reduced motion
 * ===================================================================== */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ---------------- Permission tester ---------------- */
.permission-tester {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  max-width: 760px;
}
.permission-tester .input {
  width: 100%;
  /* Fills its container, then adds padding — and this sheet has no global
     `* { box-sizing: border-box }`, so without this the row renders wider
     than the box it was meant to fill by exactly its horizontal padding. */
  box-sizing: border-box;
  padding: 6px 10px;
  border-radius: var(--radius-md);
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text);
}
/* Application typeahead picker. */
.tester-picker {
  position: relative;
}
.tester-picker__results {
  position: absolute;
  top: calc(100% + 2px);
  left: 0;
  right: 0;
  z-index: 20;
  max-height: 280px;
  overflow-y: auto;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-2, 0 4px 16px rgba(0, 0, 0, 0.18));
}
.tester-picker__item {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 2px;
  width: 100%;
  /* Fills its container, then adds padding — and this sheet has no global
     `* { box-sizing: border-box }`, so without this the row renders wider
     than the box it was meant to fill by exactly its horizontal padding. */
  box-sizing: border-box;
  padding: 6px 10px;
  border: 0;
  background: transparent;
  color: var(--text);
  text-align: left;
  cursor: pointer;
}
.tester-picker__item:hover,
.tester-picker__item--active {
  background: var(--bg-subtle);
}
.tester-picker__name {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: var(--text-sm, 13px);
}
.tester-picker__empty {
  padding: var(--space-2) 10px;
  color: var(--text-muted);
}
.permission-tester__result {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: var(--space-3);
  margin-top: var(--space-2);
}

/* Posture strip — the workbench header's read-only severity summary. */
.posture-strip__counts {
  margin-top: var(--space-2);
  margin-bottom: var(--space-2);
}

/* Findings pane — ranked, expandable finding groups. */
.finding-groups {
  display: grid;
  gap: var(--space-2);
}
.finding-group {
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--surface);
}
.finding-group__head {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding-right: var(--space-2);
}
.finding-group__header {
  flex: 1;
  display: flex;
  align-items: center;
  gap: var(--space-2);
  background: transparent;
  border: none;
  font: inherit;
  color: var(--text);
  padding: 10px var(--space-3);
  cursor: pointer;
  text-align: left;
}
.finding-group__header:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
  border-radius: var(--radius-md);
}
.finding-group__header--section {
  color: var(--text-muted);
  font-size: var(--text-sm);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.finding-group__tone {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  flex: none;
}
.finding-group__tone--critical,
.finding-group__tone--danger {
  background: var(--danger);
}
.finding-group__tone--warning {
  background: var(--warning);
}
.finding-group__tone--ok {
  background: var(--ok);
}
.finding-group__title {
  font-weight: var(--weight-semibold);
}
.finding-group__count {
  color: var(--text-muted);
  font-size: var(--text-sm);
}
.finding-group__chevron {
  margin-left: auto;
  color: var(--text-muted);
}
.finding-group__body {
  border-top: 1px solid var(--border);
  padding: var(--space-2) var(--space-3) var(--space-3);
}
.finding-group__blurb {
  margin: 0 0 var(--space-2);
  max-width: 72ch;
}
.finding-group__appid {
  font-size: var(--text-xs);
}
.finding-group--healthy .finding-group__title {
  font-weight: var(--weight-regular);
  color: var(--text-muted);
}
.finding-groups__healthy {
  margin-top: var(--space-3);
  display: grid;
  gap: var(--space-2);
}
.finding-fix-all {
  flex: none;
}
.findings-pane__note {
  margin: var(--space-2) 0;
}

/* Coverage-gap banner: what a degraded audit run could not determine. One
   line per failed tenant-wide read, inside the warn Callout. */
.findings-pane__degraded-lede {
  margin: 0;
}

.findings-pane__degraded-list {
  margin: var(--space-2) 0 0;
  padding-left: var(--space-4);
}

.findings-pane__degraded-list > li + li {
  margin-top: var(--space-1);
}

/* Add-owner candidate list (the audit's guided owner picker + the bulk bar). */
.add-owner-candidates {
  list-style: none;
  margin: var(--space-2) 0 0;
  padding: 0;
  display: grid;
  gap: var(--space-1);
  max-height: 14rem;
  overflow-y: auto;
}
.add-owner-candidates__row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
}
/* Fixed-width checkbox column for the multi-select audit table. */
.data-table__check {
  width: 36px;
  text-align: center;
}

/* Access-readiness checklist (role/scope readiness page). */
.readiness {
  padding: var(--space-3);
  max-width: 920px;
}
.readiness__group {
  margin-top: var(--space-3);
}
.readiness__group-title {
  margin: 0 0 var(--space-1);
  font-size: var(--text-base);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-muted);
}
.readiness__item {
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--surface);
  padding: 10px var(--space-3);
  margin-top: var(--space-2);
}
.readiness__item-head {
  display: flex;
  flex-direction: column;
  gap: 2px;
  margin-bottom: var(--space-2);
}
.readiness__desc {
  color: var(--text-muted);
  font-size: var(--text-sm);
}
.readiness__axis {
  display: flex;
  align-items: baseline;
  gap: var(--space-2);
  padding: 2px 0;
}
.readiness__axis-name {
  flex: 0 0 56px;
  color: var(--text-muted);
  font-size: var(--text-sm);
}
.readiness__axis-detail {
  color: var(--text-muted);
  font-size: var(--text-sm);
}
.readiness__remediation {
  margin-top: var(--space-2);
  color: var(--text-muted);
  font-size: var(--text-sm);
}

/* Proactive "Requires: <role>" advisory label (RequiresRole component). */
.requires-role {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: var(--text-xs);
  color: var(--text-muted);
  border: 1px dashed var(--border);
  border-radius: var(--radius-pill);
  padding: 1px 10px;
  cursor: help;
  white-space: nowrap;
}

/* Disaster Recovery (backup & restore) page */
.dr-view__card-title {
  font-size: var(--text-lg);
  font-weight: 600;
  margin: 0 0 var(--space-2);
}
.dr-view__lead {
  color: var(--text-muted);
  margin: 0 0 var(--space-3);
}
.dr-view__notes {
  margin: 0 0 var(--space-4);
  padding-left: var(--space-4);
  display: grid;
  gap: var(--space-2);
  color: var(--text-muted);
  font-size: var(--text-sm);
}
.dr-view__actions {
  display: flex;
  gap: var(--space-2);
  align-items: center;
}
.dr-view__progress {
  margin: var(--space-3) 0 0;
  color: var(--text-muted);
  font-size: var(--text-sm);
}
.dr-view__error {
  margin: var(--space-3) 0 0;
  color: var(--danger);
  font-size: var(--text-sm);
}
.dr-view__notice,
.audit-progress__notice {
  margin: var(--space-2) 0 0;
  padding: var(--space-2) var(--space-3);
  background: var(--warning-soft);
  border: 1px solid var(--warning);
  border-radius: var(--radius-md);
  color: var(--text);
  font-size: var(--text-sm);
}
.dr-view__result {
  margin-top: var(--space-4);
  padding-top: var(--space-3);
  border-top: 1px solid var(--border);
  display: grid;
  gap: var(--space-3);
  justify-items: start;
}
.dr-view__summary {
  margin: 0;
}

/* DR restore: plan + report */
.dr-view__note {
  margin: var(--space-2) 0 0;
  color: var(--text-muted);
  font-size: var(--text-sm);
}
.dr-view__warn {
  margin: var(--space-3) 0;
  color: var(--danger);
  font-weight: 600;
  font-size: var(--text-sm);
}
.dr-view__plan {
  margin-top: var(--space-3);
}
.dr-view__plan-list {
  margin: var(--space-2) 0 0;
  padding-left: var(--space-4);
  display: grid;
  gap: var(--space-1);
  font-size: var(--text-sm);
}
.dr-view__report-list {
  list-style: none;
  margin: var(--space-4) 0 0;
  padding: 0;
  display: grid;
  gap: var(--space-3);
}
.dr-view__report-app {
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: var(--space-3);
}
.dr-view__report-head {
  display: flex;
  gap: var(--space-2);
  align-items: baseline;
  flex-wrap: wrap;
}
.dr-view__report-id {
  color: var(--text-muted);
  font-size: var(--text-xs);
  font-family: var(--font-mono, monospace);
}
.dr-view__badge {
  font-size: var(--text-xs);
  color: var(--text-muted);
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  padding: 1px var(--space-2);
}
.dr-view__secrets {
  list-style: none;
  margin: var(--space-2) 0 0;
  padding: 0;
  display: grid;
  gap: var(--space-1);
  font-size: var(--text-sm);
}
.dr-view__secret-name {
  color: var(--text-muted);
}
.dr-view__secret-value {
  font-family: var(--font-mono, monospace);
  user-select: all;
  word-break: break-all;
}
.dr-view__report-note {
  margin: var(--space-2) 0 0;
  color: var(--text-muted);
  font-size: var(--text-sm);
}
.dr-view__warnings {
  margin: var(--space-2) 0 0;
  padding-left: var(--space-4);
  color: var(--danger);
  font-size: var(--text-xs);
}
.dr-view__failures {
  margin-top: var(--space-3);
}

.dr-view__subhead {
  margin: var(--space-4) 0 var(--space-2);
  font-size: var(--text-md);
  font-weight: 600;
}

/* GitHub Pages demo banner. The element only exists in the `demo` build, so the
   `:has()` rule that inserts an extra grid row above the top bar is inert in the
   shipped desktop bundle (no `.demo-banner` is ever rendered there). */
.shell__main:has(.demo-banner) {
  grid-template-rows: auto var(--topbar-height) 1fr auto;
}
.demo-banner {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-4);
  background: var(--accent);
  color: #fff;
  font-size: var(--text-sm);
  text-align: center;
  z-index: 11;
}
.demo-banner__link {
  color: #fff;
  font-weight: 600;
  text-decoration: underline;
  white-space: nowrap;
}


/* ---- Keyboard shortcut sheet (?) ---- */
.shortcuts {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  margin: 0;
}
.shortcuts__row {
  display: grid;
  grid-template-columns: minmax(9rem, max-content) 1fr;
  gap: var(--space-3);
  align-items: baseline;
}
.shortcuts__keys {
  margin: 0;
}
.shortcuts__keys kbd {
  display: inline-block;
  padding: 2px 6px;
  border: 1px solid var(--border);
  border-bottom-width: 2px;
  border-radius: var(--radius-sm);
  background: var(--surface-alt);
  font-family: var(--font-mono, ui-monospace, monospace);
  font-size: var(--text-xs);
  white-space: nowrap;
}
.shortcuts__what {
  margin: 0;
  color: var(--text-muted);
}
@media (max-width: 480px) {
  .shortcuts__row {
    grid-template-columns: 1fr;
    gap: var(--space-1);
  }
}

/* The specific object a ConfirmDialog will act on (a credential's display name,
   a federated credential's subject). The dialog body names the KIND of thing;
   this names the instance, so six identical "Remove this client secret?"
   dialogs are no longer indistinguishable. */
.confirm-dialog__subject {
  margin: var(--space-2) 0 0;
  font-weight: 600;
  word-break: break-word;
}

/* Reviewable selection on the Bulk Actions page. The page operates on a
   selection made elsewhere (the App Registrations list), so it has to show what
   that selection actually contains — a bare count is not reviewable. Bounded
   height: the set can be thousands of apps. */
.bulk-selection {
  margin-bottom: var(--space-2);
}
.bulk-selection__list {
  margin: var(--space-1) 0 0;
  padding-left: var(--space-4);
  max-height: 12rem;
  overflow-y: auto;
}

/* ---------- Redirect-URI list editor (components/uri_list_editor.rs) ---------- */
/* One row per URI instead of a newline-separated textarea. An app with forty
   reply URLs was a single scrolling text box in which no line could be removed
   on its own and none could be marked as the one the API was about to reject.
   Styled as a flat, separated list — the same language as `.data-table` rows on
   the sibling tabs — NOT as stacked form fields: forty bordered input boxes read
   as a wall of chrome. The control only draws itself on hover/focus. Bounded
   height so three stacked editors don't push Save off the tab; the bound only
   bites past ~8 rows, which is exactly the case this exists for. */
.uri-list {
  display: grid;
  gap: var(--space-2);
}
.uri-list__label {
  font-size: var(--text-base);
}
.uri-list__rows {
  list-style: none;
  margin: 0;
  /* 2px, not 0: the box scrolls, and a focused row's `--focus-ring` box-shadow
     would otherwise be clipped (and provoke a horizontal scrollbar). */
  padding: 2px;
  max-height: 320px;
  overflow-y: auto;
}
.uri-list__row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: 0 var(--space-1);
  /* Matches `.data-table td`: a hairline between rows, no box around them. */
  border-bottom: 1px solid var(--border);
  /* Transparent by default so a marked row shifts colour, not layout. */
  border-left: 2px solid transparent;
}
.uri-list__row:last-child {
  border-bottom: none;
}
/* The editable value. Reads as table text at rest and only reveals a control on
   hover/focus, which is what keeps a long list flat. `background` and `border`
   are the two properties thaw's input would have set — this owns both. */
.uri-list__input {
  width: 100%;
  min-width: 0;
  box-sizing: border-box;
  /* Same rhythm as `.data-table td`. */
  padding: 6px var(--space-2);
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--text);
  font-family: inherit;
  font-size: var(--text-base);
  line-height: 20px;
  outline: none;
  transition: background-color var(--motion-fast) var(--ease-standard),
    border-color var(--motion-fast) var(--ease-standard);
}
.uri-list__input::placeholder {
  color: var(--text-faint);
}
.uri-list__input:hover {
  background: var(--bg-subtle);
}
.uri-list__input:focus {
  background: var(--bg-subtle);
  border-color: var(--accent);
}
.uri-list__input:focus-visible {
  box-shadow: var(--focus-ring);
}
/* Red trash, via the shared `.button--danger` — destructive actions are red
   app-wide. Icon-only danger is a red glyph with no box (see that rule), which
   is what lets forty of them stack without the list reading as forty errors. */
.uri-list__remove {
  justify-self: end;
}
/* A rejected/duplicate row is marked with a left accent bar rather than by
   recolouring the control's border, which would vanish the moment the operator
   focused the row to fix it. Colour is never the only signal — the row also
   carries `aria-invalid` and a message. */
.uri-list__row--rejected {
  border-left-color: var(--danger);
}
.uri-list__row--duplicate {
  border-left-color: var(--warning);
}
.uri-list__issue {
  grid-column: 1 / -1;
  padding: 0 var(--space-2) 6px;
  font-size: var(--text-xs);
  color: var(--danger);
  word-break: break-word;
}
.uri-list__row--duplicate .uri-list__issue {
  color: var(--warning);
}
/* A live region must be in the DOM before its text changes or the change is
   never announced — hence always rendered, empty at rest, with a reserved line
   so add/remove doesn't jog the layout. */
.uri-list__status {
  margin: 0;
  min-height: 1em;
  font-size: var(--text-xs);
  color: var(--text-muted);
}

/* Objects a backup could not capture, listed under the ready-to-save summary.
   A short manifest restores as if these never existed, so the list is part of
   the artifact's description, not a log detail. */
.dr-view__skipped-list {
  margin: var(--space-2) 0 0;
  padding-left: var(--space-4);
}

.dr-view__skipped-list > li + li {
  margin-top: var(--space-1);
}
