/* ============================================================
   App-specific additions — extensions to the design system that
   are tied to runtime behavior (virtualization, popovers, etc.)
   rather than to the design tokens.
   ============================================================ */

/* ---------- [hidden] attribute must defeat author display: ----
   The design handoff sets `display: grid` on .dialog-backdrop,
   .app, .auth-shell and `display: flex` on .side-panel. The
   user-agent's `[hidden] { display: none }` is the same
   specificity as those class rules, but loses because the author
   rules come later. Without this override the delete-confirm
   backdrop and empty app shell render on top of the auth gate
   before sign-in. */
[hidden] { display: none !important; }

/* ============================================================
   Utility classes (replaces every inline style)
   Tightens CSP from `style-src 'self' 'unsafe-inline'` to
   `style-src 'self'` — no static `style=""` attributes remain
   in the static HTML or in app.js's innerHTML templates.
   JS-set element.style.X assignments still work; they're not
   subject to style-src in current browsers.
   ============================================================ */

.svg-sprite-hidden { position: absolute; width: 0; height: 0; }

.warn-icon   { color: var(--warn-text);   flex-shrink: 0; }
.danger-icon { color: var(--danger-text); flex-shrink: 0; }

/* Inline identity-link status badge in the name cell. */
.link-tag {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  flex-shrink: 0;
  max-width: 180px;
  height: 18px;
  padding: 0 7px;
  border-radius: var(--radius-pill);
  font-size: 10px;
  font-weight: var(--fw-bold);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  white-space: nowrap;
  overflow: hidden;
}
.link-tag svg { width: 11px; height: 11px; flex-shrink: 0; }
.link-tag span, .link-tag { text-overflow: ellipsis; }
.link-tag--ok   { background: var(--success-soft); color: var(--success-text); }
.link-tag--none { background: var(--warn-soft);    color: var(--warn-text); }
.link-tag--id   { background: var(--src-agentid-soft); color: var(--src-agentid-text); }

.icon-tight     { margin-right: 1px; }
.ext-link-icon  { vertical-align: -1px; margin-left: 2px; }

.json__pre { margin: 0; }

.tbl__row--partial { opacity: 0.78; }

.panel-empty__msg--spaced { margin-top: var(--space-1); }

.auth-card__field--tight { margin: 0; }
.auth-input--wide        { min-width: 280px; }

/* Auth gate styles (moved out of index.html's inline <style> block) */
.gate-actions          { display: flex; gap: var(--space-2); margin-top: var(--space-4); }
.gate-actions .btn     { flex: 1; }
.gate-link             { font-size: var(--fs-small); color: var(--text-tertiary); margin-top: var(--space-4); }
.gate-link a           { color: var(--accent-text); }
.auth-error {
  color: var(--danger-text);
  background: var(--danger-soft);
  border-radius: var(--radius-md);
  padding: var(--space-3);
  margin-top: var(--space-3);
  font-size: var(--fs-small);
}
.auth-error__msg { margin-bottom: var(--space-2); line-height: 1.5; }
.auth-error__msg strong { color: inherit; }
.auth-error__detail { font-size: 10px; margin-top: var(--space-2); opacity: 0.75; word-break: break-word; }
.auth-error__fix { font-size: 11px; line-height: 1.5; margin-bottom: var(--space-2); color: var(--text-secondary); }
.auth-error__cmd {
  display: block;
  font-size: 10px;
  background: var(--bg-app);
  color: var(--text-primary);
  border-radius: var(--radius-sm);
  padding: 6px 8px;
  margin: 6px 0;
  white-space: pre-wrap;
  word-break: break-all;
  user-select: all;
}

/* Chained admin-consent progress panel.  Overrides the .auth-error
   danger palette to a neutral/info look since it's a status, not an
   error. */
.consent-progress {
  color: var(--text-primary);
  background: var(--bg-elevated);
  border: 1px solid var(--border-subtle);
}
.consent-progress__title { font-weight: var(--fw-semibold); margin-bottom: var(--space-2); }
.consent-progress__list { list-style: none; margin: 0 0 var(--space-2); padding: 0; }
.consent-step { display: flex; align-items: center; gap: var(--space-2); padding: 2px 0; font-size: 12px; }
.consent-step__mark { width: 16px; text-align: center; font-weight: var(--fw-bold); }
.consent-step--done    { color: var(--success-text); }
.consent-step--active  { color: var(--text-primary); }
.consent-step--pending { color: var(--text-tertiary); }
.consent-progress__foot { font-size: 11px; color: var(--text-tertiary); line-height: 1.5; }

.gate-consent {
  font-size: var(--fs-small);
  color: var(--text-secondary);
  margin-top: var(--space-3);
  line-height: 1.5;
}
.gate-consent--warn {
  background: var(--warn-soft);
  color: var(--warn-text);
  border-radius: var(--radius-md);
  padding: var(--space-2) var(--space-3);
  margin-top: var(--space-2);
}
.gate-consent--warn code { font-size: 10px; background: var(--bg-app); padding: 1px 4px; border-radius: 3px; }
.gate-support {
  font-size: var(--fs-small);
  color: var(--text-tertiary);
  margin-top: var(--space-4);
  text-align: center;
}
.gate-support a { color: var(--accent-text); }
.link-button {
  background: none;
  border: none;
  padding: 0;
  font: inherit;
  color: var(--accent-text);
  text-decoration: underline;
  cursor: pointer;
}
.link-button:hover { opacity: 0.8; }

/* Source-tinted chip swatches */
.chip__swatch--teams      { background: var(--src-teams-text); }
.chip__swatch--pplat      { background: var(--src-pplat-text); }
.chip__swatch--foundry    { background: var(--src-foundry-text); }
.chip__swatch--sharepoint { background: #036c70; }    /* SharePoint teal */
.chip__swatch--agentid    { background: var(--src-agentid-text); }
.chip__swatch--securitycopilot { background: var(--src-securitycopilot-text); }
.chip__swatch--mdapp      { background: var(--src-pplat-text); }

/* Source badge for SharePoint — matches the chip swatch.
   Defined here (not in components.css) so the design-system tokens
   stay unchanged; SharePoint is an app-specific extension. */
.badge--sharepoint {
  background: rgba(3, 108, 112, 0.14);
  color: #4dd4d9;
}

/* Centered loading hero — lives in the Risk surface slot during the
   initial fetch + background enrichment passes. Soft spinner + rotating
   funny status text. Self-cleans when the slot is repainted with real
   content (the rotation interval polls host.isConnected). */
.loading-hero {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-4);
  padding: var(--space-8) var(--space-4);
  min-height: 240px;
  text-align: center;
}
.loading-hero__spinner {
  width: 56px;
  height: 56px;
  border-radius: 50%;
  border: 4px solid var(--border-subtle);
  border-top-color: var(--accent-text);
  animation: loading-hero-spin 0.9s linear infinite;
}
@keyframes loading-hero-spin { to { transform: rotate(360deg); } }
.loading-hero__title {
  font: var(--fw-semibold) var(--fs-h1)/1.2 var(--font-sans);
  color: var(--text-primary);
}
.loading-hero__sub {
  font: var(--fw-regular) var(--fs-h2)/1.4 var(--font-sans);
  color: var(--text-secondary);
  letter-spacing: var(--tracking-wide);
  min-height: 1.4em;
  max-width: 560px;
  transition: opacity 200ms ease-out;
}

/* Skeleton-row size variants — covers the spread of widths we used
   inline for loading placeholders. Fewer buckets than original to
   keep CSS small; the visual difference is imperceptible. */
.skel--checkbox { width: 14px; height: 14px; }
.skel--xs       { width: 40px; }
.skel--sm       { width: 80px; }
.skel--md       { width: 120px; }
.skel--lg       { width: 180px; }
/* Block placeholders for loading the overview cards. */
.skel--title    { display: block; height: 24px; width: 55%; }
.skel--line     { display: block; height: 10px; margin-top: var(--space-2); }
.skel--block    { display: block; height: 120px; width: 100%; border-radius: var(--radius-md); }

/* Toast icon variants */
.toast__icon--danger { color: var(--danger-text); }

/* Result-count and toolbar muted labels */
.toolbar__result-count { font-size: var(--fs-small); }
.toolbar__result-count .mono { color: var(--text-primary); }

/* "Copilot agents only" toolbar checkbox */
.agents-only {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: var(--fs-small);
  color: var(--text-secondary);
  cursor: pointer;
  user-select: none;
  padding: 0 var(--space-2);
}
.agents-only input[type="checkbox"] {
  accent-color: var(--accent-solid);
  cursor: pointer;
}
.agents-only:hover { color: var(--text-primary); }
.agents-only__count {
  color: var(--text-tertiary);
  font-variant-numeric: tabular-nums;
}

/* Type pill — Copilot agent vs generic app, at-a-glance in the table.
   Agents get an accent-tinted pill; non-agents (e.g. "Syskit Point -
   PR-1234" Teams apps) get a muted pill so they clearly read as
   non-agents and aren't mistaken for Copilot agents. */
.type-pill {
  display: inline-flex;
  align-items: center;
  height: 20px;
  max-width: 100%;
  padding: 0 8px;
  border-radius: var(--radius-pill);
  font-size: 11px;
  font-weight: var(--fw-medium);
  letter-spacing: var(--tracking-wide);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.type-pill--agent { background: var(--accent-soft);  color: var(--accent-text); }
.type-pill--app   { background: var(--bg-elevated);  color: var(--text-tertiary); }

/* Sensitivity-label chip (Microsoft Purview) on a knowledge source */
.sens-chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  height: 22px;
  padding: 0 10px;
  max-width: 100%;
  border-radius: var(--radius-pill);
  font-size: 11px;
  font-weight: var(--fw-bold);
  letter-spacing: var(--tracking-wide);
  background: var(--danger-soft);
  color: var(--danger-text);
  border: 1px solid color-mix(in oklch, var(--danger-text) 35%, transparent);
  text-transform: uppercase;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.sens-chip::before {
  content: '';
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--danger-text);
  flex-shrink: 0;
}
/* Larger variant — used in the callout summary so labels are unmissable. */
.sens-chip--lg {
  height: 28px;
  padding: 0 14px;
  font-size: 12px;
}
/* Callout summary: groups the banner text + a row of large label chips. */
.sens-callout { display: flex; flex-direction: column; gap: 8px; }
.sens-callout__title { margin: 0; }
.sens-callout__chips { display: flex; flex-wrap: wrap; gap: 6px; }

/* Governance risk pill — table column + side panel */
.risk-pill {
  display: inline-flex;
  align-items: center;
  height: 20px;
  padding: 0 8px;
  border-radius: var(--radius-pill);
  font-size: 11px;
  font-weight: var(--fw-semibold);
  letter-spacing: var(--tracking-wide);
  cursor: default;
  /* "Very High" is two words and was wrapping in narrow containers
     (Entra agent identity tree rows). Force a single line. */
  white-space: nowrap;
  flex-shrink: 0;
}
.risk-pill--low       { background: var(--success-soft); color: var(--success-text); }
.risk-pill--med       { background: var(--warn-soft);    color: var(--warn-text); }
.risk-pill--very-high { background: var(--danger-soft);  color: var(--danger-text); }
/* High tier — sits visually between Very High (red) and Medium (amber).
   Used for capability rows like "Orphaned identity" (Identity has no
   accountable human but isn't otherwise causing direct action). */
.risk-pill--high      { background: oklch(0.94 0.06 50); color: oklch(0.46 0.16 50); }
[data-theme="light"] .risk-pill--high, [data-theme="brand"] .risk-pill--high {
  background: oklch(0.94 0.06 50); color: oklch(0.46 0.16 50);
}
:root .risk-pill--high {
  /* Dark theme: deeper bg, lighter text */
  background: oklch(0.31 0.08 50); color: oklch(0.83 0.13 50);
}
[data-theme="light"] .risk-pill--high, [data-theme="brand"] .risk-pill--high {
  background: oklch(0.94 0.06 50); color: oklch(0.46 0.16 50);
}

/* Risk factor list inside the side panel */
.risk-factors { display: flex; flex-direction: column; gap: var(--space-1); margin-top: var(--space-2); }
.risk-factor {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: var(--fs-small);
  color: var(--text-secondary);
}
.risk-factor svg { width: 12px; height: 12px; color: var(--warn-text); flex-shrink: 0; }

/* Multi-select toolbar bar */
.selection-bar {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: 0 var(--space-2);
  margin-right: var(--space-2);
  border-right: 1px solid var(--border-subtle);
}
.selection-bar #selectionCount {
  color: var(--accent-text);
  font-size: var(--fs-small);
  font-weight: var(--fw-medium);
}

/* ---------- Virtualized table windowing -------------------- */
.tbl__body { position: relative; }
.tbl__spacer { position: relative; width: 100%; }
.tbl__rows {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  will-change: transform;
}

/* ---------- Skeleton row used during initial fetch ---------- */
.tbl__row--skel { cursor: default; pointer-events: none; }
.tbl__row--skel .skel { width: 100%; max-width: 160px; }
.tbl__row--skel .tbl__cell { padding-right: var(--space-4); }

/* ---------- Sidebar footer: sign-out --------------------- */
.sidebar__footer .btn { flex-shrink: 0; }
.sidebar__signout {
  flex: 1;
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: 0 var(--space-3);
  height: 28px;
  color: var(--text-tertiary);
  font-size: var(--fs-small);
  border-radius: var(--radius-md);
  background: transparent;
  text-align: left;
  transition: background var(--motion-fast), color var(--motion-fast);
}
.sidebar__signout:hover { background: var(--bg-elevated); color: var(--text-primary); }
.sidebar__signout svg { width: 14px; height: 14px; }
.app[data-sidebar="collapsed"] .sidebar__signout {
  justify-content: center;
  padding: 0;
}
.app[data-sidebar="collapsed"] .sidebar__signout span { display: none; }

/* ---------- Empty state inside table ------------------------ */
.tbl__empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-3);
  padding: var(--space-9) var(--space-7);
  color: var(--text-tertiary);
  text-align: center;
}
.tbl__empty svg { width: 32px; height: 32px; opacity: 0.5; }
.tbl__empty h3 {
  margin: 0;
  font-size: var(--fs-h2);
  font-weight: var(--fw-semibold);
  color: var(--text-secondary);
}
.tbl__empty p {
  margin: 0;
  max-width: 420px;
  font-size: var(--fs-body);
  line-height: var(--lh-normal);
}

/* ---------- Detail panel: capability chips ------------------ */
.cap-chips { display: flex; flex-wrap: wrap; gap: var(--space-2); }
.cap-chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  height: 22px;
  padding: 0 8px;
  border-radius: var(--radius-pill);
  background: var(--bg-elevated);
  border: 1px solid var(--border-subtle);
  font-size: 11px;
  font-weight: var(--fw-medium);
  color: var(--text-secondary);
  letter-spacing: var(--tracking-wide);
}
/* Tool chips share the danger (red) palette so they read as the Very-High
   capability tier at a glance — matches the "Tools" badge in the chip row
   above. HTTP-egress tools layer an extra arrow marker on top of the same
   palette so they remain distinct as the highest-risk subset of Tools. */
.cap-chip--tool {
  background: oklch(from var(--danger-soft) l c h / 0.55);
  border-color: var(--danger-soft);
  color: var(--danger-text);
}
/* Per-agent activity list — surfaced under "Recent activity" in the
   side panel. One row per matched audit record (when the user has
   already loaded audit data via the Audit view). */
.activity-list {
  display: flex;
  flex-direction: column;
  gap: 4px;
  margin: var(--space-2) 0;
}
.activity-row {
  display: grid;
  grid-template-columns: max-content max-content 1fr;
  align-items: baseline;
  gap: var(--space-3);
  padding: 6px 8px;
  border-radius: var(--radius-sm);
  background: var(--bg-app);
  font-size: var(--fs-small);
}
.activity-row__time { color: var(--text-tertiary); }
.activity-row__user { color: var(--text-primary); font-weight: var(--fw-medium); }
.activity-row__op   { color: var(--text-secondary); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.activity-row__turns { font-size: 11px; }
/* Copilot Studio activity rows carry channel / turns / last-step /
   status — bump the grid columns. */
.activity-row--cs {
  grid-template-columns: max-content max-content max-content 1fr max-content;
}

/* Copilot Studio analytics overview — small KPI tiles (sessions /
   last 30 days / unique users / DAU), one per column on the side
   panel's narrow grid. Mirrors the top-row cards of CS Analytics. */
.cs-analytics {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--space-2);
  margin: var(--space-2) 0;
}
.cs-stat {
  padding: 8px 10px;
  border-radius: var(--radius-md);
  background: var(--bg-app);
}
.cs-stat__label { font-size: 11px; color: var(--text-tertiary); letter-spacing: var(--tracking-wide); }
.cs-stat__value { font: var(--fw-semibold) var(--fs-h1)/1 var(--font-sans); color: var(--text-primary); margin-top: 2px; }
.cs-stat__sub   { font-size: 11px; color: var(--text-tertiary); margin-top: 2px; }
.cs-channels    { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; margin-top: var(--space-2); font-size: var(--fs-small); }

/* Bulk-delete confirm dialog — show every selected agent with its
   source badge so the user sees what they're about to delete. */
.bulk-delete-list {
  margin: var(--space-2) 0 0;
  padding-left: var(--space-4);
  font-size: var(--fs-small);
  max-height: 240px;
  overflow-y: auto;
}
.bulk-delete-list li { padding: 4px 0; }
.bulk-delete-list .badge { margin-right: 6px; }

/* Tiny daily-sessions bar chart on the Overview. 30 bars (last 30
   days), each height-encoded as a percentage of the max-day count.
   Hover shows the per-day tooltip via the title attribute. */
.sessions-chart {
  display: flex;
  align-items: flex-end;
  gap: 2px;
  height: 80px;
  padding: 6px 0;
}
.sessions-bar {
  flex: 1 1 0;
  min-width: 4px;
  background: var(--accent-text);
  border-radius: 2px 2px 0 0;
  min-height: 2px;
  transition: opacity var(--motion-fast);
}
.sessions-bar:hover { opacity: 0.7; }
.sessions-axis {
  display: flex;
  justify-content: space-between;
  font-size: 11px;
  margin-top: 4px;
}
.sessions-status {
  font-size: var(--fs-small);
  margin-top: var(--space-2);
}

/* Custom-instructions block — extracted from the Custom GPT
   botcomponent's YAML and shown as a collapsible <details> so long
   prompts don't dominate the side panel. */
.custom-instructions { cursor: pointer; }
.custom-instructions summary {
  display: block;
  color: var(--text-primary);
  line-height: 1.4;
  cursor: pointer;
  list-style: none;        /* hide default disclosure triangle */
  position: relative;
  padding-right: var(--space-6);
  border-radius: var(--radius-sm);
  transition: background var(--motion-fast);
}
.custom-instructions summary::-webkit-details-marker { display: none; }
/* Visible "click to expand" affordance — chevron pinned to the
   right edge of the summary, rotates 90deg when the details opens
   so the icon doubles as a state indicator. */
.custom-instructions summary::after {
  content: '';
  position: absolute;
  right: var(--space-2);
  top: 50%;
  width: 8px;
  height: 8px;
  border-right: 1.5px solid var(--text-secondary);
  border-bottom: 1.5px solid var(--text-secondary);
  transform: translateY(-70%) rotate(-45deg);
  transition: transform var(--motion-fast);
}
.custom-instructions[open] summary::after {
  transform: translateY(-30%) rotate(45deg);
}
.custom-instructions summary:hover { background: var(--bg-row-hover); }
.custom-instructions summary:hover::after { border-color: var(--accent-text); }
.custom-instructions[open] summary { margin-bottom: var(--space-2); }
.custom-instructions pre {
  display: block;
  white-space: pre-wrap;
  word-break: break-word;
  padding: var(--space-2) var(--space-3);
  margin: var(--space-2) 0 0;
  background: var(--bg-app);
  border-radius: var(--radius-md);
  font-size: var(--fs-small);
  color: var(--text-primary);
  max-height: 320px;
  overflow-y: auto;
}

/* Tool kind label — small monospace tag inside the chip
   ("REST API" / "Connector" / "Workflow" / "Prompt" / "MCP" / "Skill") so
   reviewers can tell at a glance what KIND of integration each tool is. */
.cap-chip__kind {
  display: inline-flex;
  align-items: center;
  height: 16px;
  padding: 0 6px;
  margin-right: 6px;
  border-radius: 3px;
  background: oklch(from currentColor l c h / 0.18);
  color: currentColor;
  font: var(--fw-bold) 9px/1 var(--font-sans);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  white-space: nowrap;
  flex-shrink: 0;
}
.cap-chip__name {
  font-weight: var(--fw-medium);
  /* Truncate long technical names (Power Platform schemanames can be
     200+ chars). Without this the chip overflows its parent and looks
     broken. Hover tooltip on the chip still shows the full string. */
  max-width: 240px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* Connector / brand icon inside cap-chip — drawn at 12px so it sits
   neatly between the KIND tag and the name. */
.cap-chip__icon {
  width: 12px;
  height: 12px;
  margin-right: 4px;
  flex-shrink: 0;
}
.cap-chip {
  /* Already inline-flex in the base rule but enforce no-shrink at the
     chip level too so it never compresses below its content. */
  flex-shrink: 0;
  max-width: 100%;
}
/* Chip / badge variants that wrap an <a> — read as clickable, get an
   accent border on hover and a tiny "external" cue so the user
   knows clicking will navigate somewhere. */
.cap-chip--link, .badge--link {
  text-decoration: none;
  cursor: pointer;
  transition: border-color var(--motion-fast), background var(--motion-fast);
}
.cap-chip--link::after, .badge--link::after {
  content: '↗';
  font-size: 0.85em;
  margin-left: 4px;
  opacity: 0.55;
}
.cap-chip--link:hover, .badge--link:hover {
  border-color: var(--accent-text);
  filter: brightness(1.05);
}
.cap-chip--link:hover::after, .badge--link:hover::after {
  opacity: 1;
}
.activity-row__link {
  color: var(--accent-text);
  text-decoration: none;
}
.activity-row__link:hover { text-decoration: underline; }
.cap-chip--http {
  background: var(--danger-soft);
  border-color: var(--danger-text);
  color: var(--danger-text);
  font-weight: var(--fw-bold);
}
.cap-chip--http::before {
  content: '↗';
  margin-right: 4px;
  font-weight: var(--fw-bold);
}
/* Custom prompt chips — info (blue) palette so prompts are visually distinct
   from Tools (default / red for HTTP) and Knowledge / Skills (default).
   Same tier as Knowledge in the risk taxonomy but a different colour family
   for at-a-glance differentiation. */
.cap-chip--prompt {
  background: var(--info-soft);
  border-color: var(--info-soft);
  color: var(--info-text);
}

/* Risk-surface chips — dashboard widget below KPIs. One chip per risk
   category present in the inventory; click drills through to the
   corresponding filtered All-agents view. */
.risk-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 26px;
  padding: 0 10px;
  margin: 4px 6px 4px 0;
  border-radius: var(--radius-pill);
  border: 1px solid transparent;
  font-size: var(--fs-small);
  font-weight: var(--fw-medium);
  letter-spacing: var(--tracking-wide);
  cursor: pointer;
  transition: filter var(--motion-fast) var(--ease-out),
              transform var(--motion-fast) var(--ease-out);
}
.risk-chip:hover { filter: brightness(1.05); transform: translateY(-1px); }
.risk-chip:active { transform: translateY(0); }
.risk-chip__count {
  font-variant-numeric: tabular-nums;
  padding: 1px 7px;
  border-radius: var(--radius-pill);
  background: oklch(from currentColor l c h / 0.18);
}
.risk-chip--danger { background: var(--danger-soft); color: var(--danger-text); border-color: var(--danger-soft); }
.risk-chip--warn   { background: var(--warn-soft);   color: var(--warn-text);   border-color: var(--warn-soft); }
.risk-chip--muted  { background: var(--bg-elevated); color: var(--text-secondary); border-color: var(--border-subtle); }

/* Capability risk taxonomy — small four-column table mapping the Microsoft
   taxonomy (Tools / HTTP / Autonomous / Skills / Knowledge / Prompts /
   Enhanced search) onto inventory counts. Each row is clickable -> drills
   to the SPECIAL_FILTERS view for that capability. */
.risk-tax {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--fs-body);
}
.risk-tax thead th {
  text-align: left;
  font-weight: var(--fw-medium);
  color: var(--text-tertiary);
  letter-spacing: var(--tracking-wide);
  padding: 6px 10px;
  border-bottom: 1px solid var(--border-subtle);
  font-size: var(--fs-small);
}
.risk-tax tbody td {
  padding: 8px 10px;
  border-bottom: 1px solid var(--border-subtle);
  vertical-align: middle;
}
.risk-tax tbody tr:last-child td { border-bottom: 0; }
.risk-tax__name { font-weight: var(--fw-medium); color: var(--text-primary); }
.risk-tax__tier { white-space: nowrap; font-weight: var(--fw-medium); }
.risk-tax__icon { margin-right: 4px; }
.risk-tax__num  { font-variant-numeric: tabular-nums; text-align: right; min-width: 56px; }
.risk-tax__why  { color: var(--text-secondary); }

/* Tier tinting — left-edge bar accent so the row's risk reads at a glance. */
.risk-tax__row--very-high { background: linear-gradient(90deg, oklch(from var(--danger-soft) l c h / 0.55) 0 4px, transparent 4px); }
/* High tier accent bar — deeper orange, matches the High pill tier
   colour so the left-edge marker reads as the same tier without
   needing a new design token. */
.risk-tax__row--high      { background: linear-gradient(90deg, oklch(0.78 0.13 50 / 0.55) 0 4px, transparent 4px); }
[data-theme="dark"] .risk-tax__row--high { background: linear-gradient(90deg, oklch(0.45 0.13 50 / 0.55) 0 4px, transparent 4px); }
.risk-tax__row--medium    { background: linear-gradient(90deg, oklch(from var(--warn-soft) l c h / 0.55) 0 4px, transparent 4px); }
.risk-tax__row--low       { background: linear-gradient(90deg, oklch(from var(--info-soft) l c h / 0.55) 0 4px, transparent 4px); }
.risk-tax__row--very-high .risk-tax__tier { color: var(--danger-text); }
/* High tier sits between Very High and Medium; using a deeper orange
   so the new "Orphaned identity" row is visually distinct from both. */
.risk-tax__row--high      .risk-tax__tier { color: oklch(0.50 0.16 50); }
[data-theme="dark"] .risk-tax__row--high  .risk-tax__tier { color: oklch(0.83 0.13 50); }
.risk-tax__row--medium    .risk-tax__tier { color: var(--warn-text); }
.risk-tax__row--low       .risk-tax__tier { color: var(--info-text); }

.risk-tax__row[data-special]:not(.risk-tax__row--zero) {
  cursor: pointer;
  transition: background-color var(--motion-fast) var(--ease-out);
}
.risk-tax__row[data-special]:not(.risk-tax__row--zero):hover td {
  background: var(--bg-elevated);
}
.risk-tax__row--zero td { opacity: 0.55; }
.risk-tax__row--zero .risk-tax__num { color: var(--text-tertiary); }

/* Connector classification chips (side panel, Power Platform agents).
   Coloured by DLP group: Business = warn (amber), Non-Business = neutral,
   Blocked = danger. A leading dot keeps them legible against the panel. */
.conn-chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  height: 22px;
  padding: 0 9px;
  border-radius: var(--radius-pill);
  font-size: 11px;
  font-weight: var(--fw-medium);
  letter-spacing: var(--tracking-wide);
  max-width: 100%;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  background: var(--bg-elevated);
  border: 1px solid var(--border-subtle);
  color: var(--text-secondary);
}
.conn-chip::before {
  content: '';
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
  flex-shrink: 0;
  opacity: 0.85;
}
.conn-chip--biz {
  background: var(--warn-soft);
  color: var(--warn-text);
  border-color: color-mix(in oklch, var(--warn-text) 30%, transparent);
}
.conn-chip--blocked {
  background: var(--danger-soft);
  color: var(--danger-text);
  border-color: color-mix(in oklch, var(--danger-text) 30%, transparent);
}

/* Published-channels chips (Power Platform agents).
   Internal channels (m365copilot/teams/outlook/office/sharepoint) read neutral;
   public-facing channels (webchat/custom/directline/telephony) take a warning
   tint because they're the exposure surface power-pwn calls out. */
.channel-chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  height: 22px;
  padding: 0 9px;
  border-radius: var(--radius-pill);
  font-size: 11px;
  font-weight: var(--fw-medium);
  letter-spacing: var(--tracking-wide);
  max-width: 100%;
  white-space: nowrap;
  background: var(--bg-elevated);
  border: 1px solid var(--border-subtle);
  color: var(--text-secondary);
}
.channel-chip::before {
  content: '';
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
  flex-shrink: 0;
  opacity: 0.8;
}
.channel-chip--public {
  background: var(--warn-soft);
  color: var(--warn-text);
  border-color: color-mix(in oklch, var(--warn-text) 30%, transparent);
}

/* ---------- JSON viewer: collapsible body ------------------- */
.json--collapsed { display: none; }

/* ---------- Toolbar override: chips shouldn't wrap to new row
              before the spacer pushes the result-count to the right */
.toolbar { flex-wrap: wrap; row-gap: var(--space-2); }

/* ---------- Inline error states inside detail panel --------- */
.detail-error {
  background: var(--danger-soft);
  color: var(--danger-text);
  border-radius: var(--radius-md);
  padding: var(--space-3);
  font-size: var(--fs-small);
  margin: 0 0 var(--space-3);
}

/* ---------- Audit-view-specific ----------------------------- */

/* The audit table uses different columns than the agents grid, so it gets
   its own grid-template-columns. */
#auditTbl .tbl__head,
#auditTbl .tbl__row {
  display: grid;
  grid-template-columns:
    140px
    minmax(200px, 1.4fr)
    minmax(160px, 1.2fr)
    120px
    120px
    44px;
}

/* Audit status pill (Queued / Running / Succeeded / Failed) — sits in the
   page-header actions slot. Animated dot on Running state. */
.audit-pill {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  height: 28px;
  padding: 0 var(--space-3);
  border-radius: var(--radius-pill);
  font-size: var(--fs-small);
  font-weight: var(--fw-medium);
  letter-spacing: var(--tracking-wide);
}
.audit-pill__dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: currentColor;
}
.audit-pill--queued   { background: var(--info-soft);    color: var(--info-text); }
.audit-pill--running  { background: var(--warn-soft);    color: var(--warn-text); }
.audit-pill--succeeded{ background: var(--success-soft); color: var(--success-text); }
.audit-pill--failed   { background: var(--danger-soft);  color: var(--danger-text); }

.audit-pill--running .audit-pill__dot { animation: pulse 1.2s ease-in-out infinite; }
@keyframes pulse {
  0%, 100% { opacity: 1;   transform: scale(1); }
  50%      { opacity: 0.5; transform: scale(1.4); }
}

/* Audit landing state — shown before a query has been run. */
.audit-blank {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-3);
  padding: var(--space-9) var(--space-7);
  color: var(--text-tertiary);
  text-align: center;
  height: 100%;
}
.audit-blank svg { width: 32px; height: 32px; opacity: 0.5; }
.audit-blank p { max-width: 480px; line-height: var(--lh-normal); margin: 0; }

/* ============================================================
   Overview dashboard
   ============================================================ */

/* The base .main grid is `auto auto 1fr`, but the agents and audit views
   each have FOUR children (page-header, banner, toolbar, content) — so the
   `1fr` landed on the toolbar and `.content` fell into an implicit auto row
   at the bottom. With a full table that was masked (the table's natural
   height filled the view); with only a few rows the toolbar's `1fr` row
   ballooned and shoved the short table to the bottom of the screen. Give
   these views an explicit four-track template so the growable `1fr` is the
   content/table row, which then provides its own inner scroll. */
#mainAgents, #mainAudit { grid-template-rows: auto auto auto 1fr; }

/* The dashboard and About views have no inner scroller, so their content was
   clipped below the fold. Override to `auto 1fr` (fixed page-header +
   growable body) and let the body scroll. */
#mainOverview, #mainAbout { grid-template-rows: auto 1fr; }
#mainOverview .dash,
#mainAbout .about {
  overflow-y: auto;
  min-height: 0;
}

.dash {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  padding: var(--space-2) 0 var(--space-7);
}
.dash__kpis {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: var(--space-3);
}
.dash__row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-4);
}
@media (max-width: 1100px) {
  .dash__kpis { grid-template-columns: repeat(2, 1fr); }
  .dash__row  { grid-template-columns: 1fr; }
}

.dash-card {
  background: var(--bg-elevated);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  padding: var(--space-4);
}
.dash-card__title {
  margin: 0 0 var(--space-3);
  font-size: var(--fs-small);
  font-weight: var(--fw-semibold);
  color: var(--text-secondary);
  letter-spacing: var(--tracking-wide);
}
.dash-card__body { min-height: 60px; }

/* KPI cards */
.kpi {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: var(--space-4);
  background: var(--bg-elevated);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  text-align: left;
  cursor: pointer;
  transition: transform var(--motion-fast) var(--ease-out), border-color var(--motion-fast);
}
.kpi:not(:disabled):hover { transform: translateY(-2px); border-color: var(--accent-solid); }
.kpi:disabled { cursor: default; }
.kpi__value {
  font-size: 30px;
  font-weight: var(--fw-bold);
  line-height: 1.1;
  font-variant-numeric: tabular-nums;
  color: var(--text-primary);
}
.kpi__label { font-size: var(--fs-body); color: var(--text-secondary); font-weight: var(--fw-medium); }
.kpi__sub   { font-size: var(--fs-small); color: var(--text-tertiary); }
.kpi--accent .kpi__value { color: var(--accent-text); }
.kpi--danger .kpi__value { color: var(--danger-text); }
.kpi--warn   .kpi__value { color: var(--warn-text); }

/* Donut */
.donut-wrap { display: flex; align-items: center; gap: var(--space-5); flex-wrap: wrap; }
.donut { width: 160px; height: 160px; flex-shrink: 0; }
.donut-seg { transition: opacity var(--motion-fast); cursor: pointer; }
.donut-seg:hover { opacity: 0.78; }
.donut__total { fill: var(--text-primary); font-size: 26px; font-weight: var(--fw-bold); }
.donut__cap   { fill: var(--text-tertiary); font-size: 10px; letter-spacing: var(--tracking-caps); text-transform: uppercase; }

.dash-legend { display: flex; flex-direction: column; gap: var(--space-2); }
.dash-legend--row { flex-direction: row; flex-wrap: wrap; gap: var(--space-3); margin-top: var(--space-3); }
.dash-legend__item {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: var(--fs-small);
  color: var(--text-secondary);
  background: transparent;
  cursor: pointer;
  padding: 2px 4px;
  border-radius: var(--radius-sm);
  transition: color var(--motion-fast), background var(--motion-fast);
}
.dash-legend__item:hover { color: var(--text-primary); background: var(--bg-app); }
.dash-legend__dot { width: 10px; height: 10px; border-radius: 50%; flex-shrink: 0; }
.dash-legend__val { color: var(--text-primary); font-weight: var(--fw-semibold); font-variant-numeric: tabular-nums; }

/* Risk bar */
.riskbar {
  display: flex;
  height: 34px;
  border-radius: var(--radius-md);
  overflow: hidden;
  background: var(--bg-app);
  gap: 2px;
}
.riskbar__seg {
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 0;
  cursor: pointer;
  transition: opacity var(--motion-fast), flex-basis var(--motion-base) var(--ease-out);
}
.riskbar__seg:hover { opacity: 0.82; }
.riskbar__num {
  font-size: 12px;
  font-weight: var(--fw-bold);
  color: rgba(0, 0, 0, 0.72);   /* dark text on the lightish risk fills */
  font-variant-numeric: tabular-nums;
}

/* Sparkline timeline */
.spark { width: 100%; height: auto; display: block; }
.spark-bar { transition: opacity var(--motion-fast); pointer-events: none; }
.spark-x { fill: var(--text-tertiary); font-size: 9px; }
.spark-num { fill: var(--text-secondary); font-size: 10px; font-weight: var(--fw-semibold); }
.spark-baseline { stroke: var(--border-subtle); stroke-width: 1; }
/* Clickable hit rect over each month column.  Inline cursor styles
   on SVG <rect> are unreliable across browsers; CSS rules aren't.
   pointer-events:all forces the (visually) transparent rect to
   capture hover + click so the cursor reliably flips. */
.spark-hit { cursor: pointer; pointer-events: all; }
.spark-hit[data-count="0"] { cursor: default; }
.dash-card__foot {
  margin: var(--space-3) 0 0;
  font-size: var(--fs-small);
  color: var(--text-tertiary);
}

/* Horizontal bars (top environments).  Base padding + transparent
   border match the clickable variant so synthetic non-clickable
   rows (e.g. "(none)") line up column-for-column with the
   buttons above and below. */
.hbar {
  display: grid;
  grid-template-columns: 140px 1fr 32px;
  align-items: center;
  gap: var(--space-3);
  margin-bottom: var(--space-2);
  padding: var(--space-1) var(--space-2);
  border: 1px solid transparent;
  border-radius: var(--radius-md);
  width: 100%;
  box-sizing: border-box;
}
/* Make the clickable Top-environments row read as a button: cursor,
   hover state.  Strips the default <button> chrome so it still
   looks like a row (no background, no border) until hover. */
button.hbar--clickable {
  background: transparent;
  cursor: pointer;
  text-align: left;
  font: inherit;
  color: inherit;
  transition: background var(--motion-fast), border-color var(--motion-fast);
}
button.hbar--clickable:hover,
button.hbar--clickable:focus-visible {
  background: var(--bg-row-hover);
  border-color: var(--border-subtle);
  outline: none;
}
.hbar__label { font-size: var(--fs-small); color: var(--text-secondary); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hbar__track { height: 10px; background: var(--bg-app); border-radius: var(--radius-pill); overflow: hidden; }
.hbar__fill  { height: 100%; border-radius: var(--radius-pill); transition: width var(--motion-base) var(--ease-out); }
.hbar__val   { font-size: var(--fs-small); color: var(--text-primary); font-variant-numeric: tabular-nums; text-align: right; }

/* Needs-attention rows */
.attn-row {
  display: grid;
  grid-template-columns: minmax(0, 1.6fr) 160px 44px minmax(0, 1.4fr);
  align-items: center;
  gap: var(--space-3);
  width: 100%;
  padding: var(--space-2) var(--space-3);
  background: transparent;
  border-radius: var(--radius-md);
  cursor: pointer;
  text-align: left;
  transition: background var(--motion-fast);
}
.attn-row:hover { background: var(--bg-app); }
.attn-row__name { font-weight: var(--fw-medium); color: var(--text-primary); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.attn-row__factor { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: var(--fs-small); }
@media (max-width: 900px) {
  .attn-row { grid-template-columns: 1fr auto auto; }
  .attn-row__factor { display: none; }
}

/* ============================================================
   Entra Agent identities — tree view
   ============================================================ */
.entra-wrap {
  padding: var(--space-2) var(--space-7) var(--space-7);
  overflow-y: auto;
  min-height: 0;
}
.entra-empty { padding: var(--space-6); text-align: center; }
.entra-tree {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  background: var(--bg-elevated);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  padding: var(--space-3);
}
.entra-node { display: flex; flex-direction: column; }
.entra-node__row {
  display: grid;
  /* Last column = risk pill; max-content so "Very High · 65/100" stays
     readable instead of clipping when name (1fr) consumes the row. */
  grid-template-columns: 18px auto minmax(120px, 1fr) auto auto max-content;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-3);
  background: transparent;
  border: 1px solid transparent;
  border-radius: var(--radius-md);
  color: var(--text-primary);
  text-align: left;
  cursor: pointer;
  font: inherit;
  width: 100%;
  transition: background var(--motion-fast), border-color var(--motion-fast);
}
.entra-node__row:hover { background: var(--bg-app); border-color: var(--border-subtle); }
.entra-node__row--root { font-weight: var(--fw-medium); }
/* Group the Enabled + Legacy badges into a single grid cell so the
   risk pill stays on the same row (the 6-column grid template ran
   out of slots when we rendered both badges as separate children +
   the risk pill, so the risk pill wrapped to a new line and looked
   like a "balloon" floating below the row). */
.entra-node__badges {
  display: inline-flex;
  gap: var(--space-2);
  align-items: center;
  flex-wrap: nowrap;
}
.entra-node__row--orphans { color: var(--text-secondary); }
.entra-node__row--child {
  /* Last column = risk pill — use max-content so "Very High · 65/100"
     is never truncated. Without this, when the name column (1fr)
     expanded aggressively the auto column for risk could shrink and
     clip the label. */
  grid-template-columns: 32px auto minmax(120px, 1fr) auto max-content;
  padding-left: var(--space-3);
}
.entra-node__chev {
  width: 14px; height: 14px;
  color: var(--text-tertiary);
  transition: transform var(--motion-fast);
  flex-shrink: 0;
}
.entra-node__chev--open { transform: rotate(90deg); }
.entra-node__chev--leaf { display: inline-block; width: 14px; height: 14px; }
.entra-node__indent { display: inline-block; width: 14px; height: 1px; }
.entra-node__warn { width: 14px; height: 14px; color: var(--warn-text); flex-shrink: 0; }
.entra-node__name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.entra-node__meta { font-size: var(--fs-small); white-space: nowrap; }
.entra-node__children {
  display: flex;
  flex-direction: column;
  gap: 2px;
  margin: 4px 0 8px 8px;
  padding-left: var(--space-3);
  border-left: 1px dashed var(--border-subtle);
}
@media (max-width: 900px) {
  .entra-node__row { grid-template-columns: 18px auto 1fr auto; }
  .entra-node__row .badge:not(.badge--agentid) ~ .entra-node__meta,
  .entra-node__row .badge--success,
  .entra-node__row .badge--danger { display: none; }
}

/* ============================================================
   About page (mostly a joke, with a hidden real panel)
   ============================================================ */
.about {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-3);
  text-align: center;
  padding: var(--space-9) var(--space-7);
  min-height: 70vh;
}
.about__actions { margin-top: var(--space-5); }
.about__hint { font-size: var(--fs-small); margin: var(--space-2) 0 0; }
.about__real { margin-top: var(--space-5); width: 100%; max-width: 640px; text-align: left; }
.about__credits { margin-top: var(--space-4); }
.about__tagline { font-size: var(--fs-body); font-style: italic; color: var(--text-secondary); margin: 0 0 var(--space-3); }
.about__origin { font-size: var(--fs-small); color: var(--text-secondary); line-height: 1.6; margin: var(--space-3) 0 0; }
.about__origin a { color: var(--accent-text); }
.about__support { font-size: var(--fs-small); color: var(--text-secondary); margin: var(--space-3) 0 0; }
.about__support a { color: var(--accent-text); }
.credit-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-3); }
.credit { display: flex; flex-direction: column; gap: 2px; }
.credit__name { font-weight: var(--fw-semibold); color: var(--text-primary); display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; }
.credit__role { font-size: var(--fs-small); color: var(--text-secondary); }
.credit__links { font-size: var(--fs-small); }
.credit__links a { color: var(--accent-text); }
.mvp-badge {
  display: inline-flex; align-items: center;
  padding: 1px 7px; border-radius: var(--radius-pill);
  font-size: 10px; font-weight: var(--fw-bold); letter-spacing: 0.04em;
  background: oklch(0.55 0.16 28); color: #fff;   /* Microsoft MVP red */
}
.mvp-badge--rd { background: oklch(0.50 0.14 255); }   /* RD blue */
.about__sponsor-row { display: flex; align-items: center; gap: var(--space-3); margin-top: var(--space-3); }
.about__sponsor-logo { flex-shrink: 0; line-height: 0; }
/* Official Syskit wordmark is black artwork — invert to white on the
   dark theme so it's visible; leave as-is on light / brand. */
[data-theme="dark"] .syskit-wordmark { filter: invert(1) brightness(1.6); }
.about__sponsor {
  margin: 0;
  font-size: var(--fs-small);
  color: var(--text-secondary);
  line-height: 1.6;
}
.about__sponsor strong { color: var(--text-primary); }
.about__sponsor a { color: var(--accent-text); }

/* ============================================================
   Side panel: overlay drawer on narrower viewports
   ------------------------------------------------------------
   The agents table's columns sum to ~1250px of min-width. Side by
   side with the 440px panel it needs ~1950px of viewport to fit
   without the table overflowing its grid track and bleeding over
   the panel. Above that, keep the original side-by-side layout.
   At or below it, drop to a single-column content grid and float
   the panel as an absolute drawer with a solid background, shadow,
   and high z-index — so the table can never show through, no matter
   how narrow the window. (.content is position:relative + overflow
   hidden, so the drawer anchors and clips to it cleanly.)
   ============================================================ */
@media (max-width: 1950px) {
  .content[data-panel="open"] {
    grid-template-columns: minmax(0, 1fr);
  }
  .content[data-panel="open"] .side-panel {
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    width: min(var(--panel-w), 94vw);
    z-index: 30;
    box-shadow: -10px 0 30px rgba(0, 0, 0, 0.40);
  }
}

/* Belt-and-suspenders: even in side-by-side mode, keep the table
   clipped to its own grid track so a future column-width change can't
   reintroduce the bleed. */
.tbl { min-width: 0; }

/* ============================================================
   Mobile (<= 720px)
   - Sidebar JS defaults to collapsed (56px) at this width.
   - The table grid has a ~1300px min, so swipe horizontally
     instead of squishing/clipping columns.
   - Trim large paddings; let the toolbar wrap.
   - Hide the topbar tenant/user text labels (icons remain).
   ============================================================ */
@media (max-width: 720px) {
  /* App shell: tighter chrome */
  .page-header,
  .main__banner { padding-left: var(--space-4); padding-right: var(--space-4); }
  .page-header  { padding-top: var(--space-3); padding-bottom: var(--space-2); flex-wrap: wrap; gap: var(--space-2); }
  .page-header__title { font-size: var(--fs-h1); }
  /* Hide the descriptive subtitle paragraph on mobile — the h1 already says
     what view this is, the subtitle text repeats it. Reclaims ~30px so the
     central table can show ~one more row at phone heights. */
  .page-header__subtitle { display: none; }
  .toolbar { padding: var(--space-2) var(--space-4); gap: var(--space-2); }

  /* Topbar: keep the avatar + tenant dot, drop the long text labels and the
     breadcrumbs (redundant with the h1 below) so the topbar fits without
     wrapping. Saves vertical space when crumbs would otherwise wrap. */
  .topbar { padding: 0 var(--space-3); gap: var(--space-2); }
  .topbar__crumbs    { display: none; }
  .topbar__tenant-name,
  .topbar__user-name { display: none; }
  .topbar__tenant    { padding-left: var(--space-2); padding-right: var(--space-2); }
  .topbar__loading   { margin-left: var(--space-2); padding: 4px 10px; font-size: 11px; }

  /* Export button: keep the icon, drop the label text — saves header width
     so the title gets full room. */
  #exportBtn { font-size: 0; padding: 0 var(--space-2); }
  #exportBtn svg { font-size: var(--fs-body); }

  /* Table: allow horizontal swipe instead of clipping the grid. Sticky head
     stays aligned with the rows because the body scrolls them together. */
  .tbl__body { overflow-x: auto; }

  /* KPI grid already collapses to 2 cols at 1100px — drop to a single
     column on very narrow screens so each card stays readable. */
  .dash__kpis { grid-template-columns: 1fr; }

  /* Side panel already drops to an absolute drawer above 1950px; ensure it
     fully covers the viewport on phone widths for legibility. */
  .content[data-panel="open"] .side-panel { width: 100vw; max-width: 100%; }

  /* Loading hero — keep the spinner + heading visible but compress the
     vertical footprint so it doesn't push everything below the fold. */
  .loading-hero { min-height: 160px; padding: var(--space-5) var(--space-3); gap: var(--space-3); }
  .loading-hero__spinner { width: 40px; height: 40px; border-width: 3px; }
  .loading-hero__title { font-size: var(--fs-h2); }
  .loading-hero__sub   { font-size: var(--fs-body); max-width: 92vw; }

  /* Toast notifications — full-width-ish at phone widths so the slide-in
     animation doesn't push them off-screen. Top inset shrinks too so
     they don't crowd the system status bar. */
  .toast-stack {
    top: var(--space-3);
    right: var(--space-3);
    left: var(--space-3);
    align-items: stretch;
    max-height: calc(100vh - var(--space-3) * 2);
  }
  /* Phones don't have room for the desktop fixed 360px width — let toasts
     stretch to the stack's width instead, but keep them uniform with
     each other (align-items: stretch on the parent already does that). */
  .toast { width: auto; min-width: 0; max-width: 100%; }

  /* Capability risk taxonomy — the 4-column table is too cramped at
     phone widths. Collapse to 2 rows per entry: row 1 = Functionality +
     tier badge + count; row 2 = the "Why?" rationale. */
  .risk-tax, .risk-tax thead, .risk-tax tbody, .risk-tax tr,
  .risk-tax td, .risk-tax th { display: block; }
  .risk-tax thead { display: none; }   /* column headers don't make sense in a stacked layout */
  .risk-tax tbody tr {
    display: grid;
    grid-template-columns: 1fr auto auto;
    gap: var(--space-2);
    align-items: center;
    padding: var(--space-2) var(--space-2);
    border-bottom: 1px solid var(--border-subtle);
  }
  .risk-tax tbody tr:last-child { border-bottom: 0; }
  .risk-tax__name  { font-size: var(--fs-body); }
  .risk-tax__tier  { font-size: var(--fs-small); padding: 0; }
  .risk-tax__num   { padding: 0; min-width: 0; }
  .risk-tax__why   { grid-column: 1 / -1; font-size: var(--fs-small); color: var(--text-tertiary); }

  /* Risk-surface chips — already wrap; just bump touch target slightly
     so taps don't miss. */
  .risk-chip { height: 28px; padding: 0 12px; }

  /* Entra tree rows — already collapse via the 900px media query but
     reinforce here: don't let the risk pill wrap onto a second line on
     narrow screens. */
  .entra-node__row { gap: var(--space-2); padding: var(--space-2); }
  .entra-node__row .risk-pill { font-size: 10px; padding: 0 6px; }
}
