/* ── Table base ──────────────────────────────────────────────────────── */

.service-group { display: flex; flex-direction: column; gap: 0.5rem; margin-bottom: 1.25rem; }

.service-group h3 {
  font-size: 0.95rem;
  font-weight: 600;
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

table {
  width: 100%;
  border-collapse: collapse;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 6px;
  overflow: hidden;
}

th, td {
  text-align: left;
  padding: 0.55rem 0.8rem;
  border-bottom: 1px solid var(--border);
  font-size: 0.875rem;
  vertical-align: top;
}

th { background: var(--panel-3); color: var(--muted); font-weight: 500; font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.04em; }

/* No zebra striping — borders + hover state carry row separation
   (industry pattern, cf. Linear/Vercel/Notion). */
tbody tr:hover { background: var(--accent-a04); }

thead th { position: relative; }

#inv-table thead th {
  position: sticky;
  top: 0;
  z-index: 3;
  box-shadow: inset 0 -1px 0 var(--border);
}

#inv-table { table-layout: fixed; }

/* Default: each column truncates with an ellipsis. The previous
   `overflow-wrap: anywhere` rule let long values (endpoints, ARNs,
   account ids) wrap vertically, which collapsed row height into
   illegible character-per-line text when the detail drawer narrowed
   the table column. Hover the cell to see the full value via the
   tooltip baked into the <td title="…"> attribute. */
#inv-table td {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 0;        /* lets the column width drive cell width, so
                          long values clip at the column boundary
                          rather than push the table wider. */
}

/* Hard row-height ceiling — defense in depth against pathological
   wrap modes. Even if some future cell escapes nowrap, the row stays
   bounded so a 60-row table never explodes vertically.
   `td { vertical-align: middle }` keeps content vertically centered
   inside the bounded height rather than top-anchored with overflow. */
#inv-table tbody tr {
  height: 44px;
  max-height: 80px;
}
#inv-table tbody td { vertical-align: middle; }

/* Endpoint column is the worst offender — RDS endpoints are 100+
   characters. Pin a sensible max-width so the column never gobbles
   the rest of the table, and add a copy-to-clipboard affordance
   inline (rendered by inventory.js when the cell has a value). */
#inv-table th[data-col="endpoint"],
#inv-table td[data-col="endpoint"] {
  max-width: 240px;
  width: 240px;
}
@media (max-width: 768px) {
  #inv-table th[data-col="endpoint"],
  #inv-table td[data-col="endpoint"] { max-width: 160px; width: 160px; }
}
/* ARN identifier column — same shape but slightly wider since it's the
   primary identifier. */
#inv-table th[data-col="id"],
#inv-table td[data-col="id"] {
  max-width: 320px;
}

/* Sensitivity badge column — keep the cell tight so the pill doesn't
   leave acres of whitespace when the column otherwise stretches. */
#inv-table th[data-col="sensitivity"],
#inv-table td[data-col="sensitivity"] {
  max-width: 110px;
  width: 110px;
}

/* The summary-count columns are short-by-design (single digits or
   small badges). Centered text + auto-width feels better than
   ellipsis here. */
#inv-table td[data-col="critical"],
#inv-table td[data-col="high"],
#inv-table td[data-col="medium"],
#inv-table td[data-col="low"] {
  text-align: center;
}

/* When the detail drawer is open, the table sits next to a 360px
   panel; allow horizontal scroll so the user can still reach the
   right-edge columns instead of squishing everything to nothing. */
#compliance-table-area { overflow-x: auto; }
#compliance-layout.has-detail #compliance-table-area { overflow-x: auto; }

/* Hover affordance — slightly elevate the row so the user knows the
   ellipsized text has more in the tooltip. */
#inv-table td[title]:hover {
  background: var(--accent-a04);
  cursor: default;
}

th.sortable { cursor: pointer; user-select: none; white-space: nowrap; }
th.sortable:hover { color: var(--text); }
th.sort-asc::after  { content: " ↑"; color: var(--accent); }
th.sort-desc::after { content: " ↓"; color: var(--accent); }

td pre {
  margin: 0;
  white-space: pre-wrap;
  word-break: break-word;
  max-height: 20rem;
  overflow: auto;
  font-size: 0.8rem;
  color: var(--muted);
  background: var(--panel);
  padding: 0.5rem;
  border-radius: 4px;
}

td.num { text-align: center; }

/* ── In-header search inputs + filter buttons ────────────────────────── */

th.th-with-search { white-space: normal; vertical-align: top; }
th.th-with-search.sort-asc::after,
th.th-with-search.sort-desc::after { content: none; }
th.th-with-search.sort-asc .th-label-row::after  { content: " ↑"; color: var(--accent); }
th.th-with-search.sort-desc .th-label-row::after { content: " ↓"; color: var(--accent); }

.th-label-row { white-space: nowrap; }

th .th-search {
  display: block;
  width: 100%;
  min-width: 60px;
  margin-top: 4px;
  font-size: 0.72rem;
  padding: 2px 5px;
  height: 22px;
  font-weight: 400;
  text-transform: none;
  letter-spacing: 0;
}
th .th-search:focus { border-color: var(--accent); }
th .th-search::placeholder { color: var(--muted); opacity: 0.7; }
th .th-search::-webkit-search-cancel-button { cursor: pointer; }

.th-filter-btn {
  display: block;
  width: 100%;
  min-width: 60px;
  margin-top: 4px;
  font-size: 0.72rem;
  padding: 2px 6px;
  height: 22px;
  font-weight: 400;
  text-transform: none;
  letter-spacing: 0;
  cursor: pointer;
  text-align: left;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  color: var(--muted);
  border-color: var(--border);
}
.th-filter-btn:hover { border-color: var(--accent); color: var(--text); }
.th-filter-btn.filter-active { border-color: var(--accent); color: var(--accent); background: var(--accent-a10); }

/* ── Column resize handle ────────────────────────────────────────────── */

.col-resizer {
  position: absolute;
  top: 0;
  right: 0;
  width: 5px;
  height: 100%;
  cursor: col-resize;
  user-select: none;
  z-index: 2;
  transition: background 0.12s;
}
.col-resizer:hover { background: var(--accent); opacity: 0.6; }
body.col-resizing { cursor: col-resize !important; user-select: none; }
body.col-resizing .col-resizer { background: var(--accent); opacity: 0.6; }

/* ── Row highlight + selection (inventory) ───────────────────────────── */

tr.row-highlight { background: var(--ok-bg); outline: 1px solid var(--ok); }
#inv-tbody tr { cursor: pointer; }
#inv-table tr.row-selected { background: var(--panel-3); outline: 1px solid var(--accent); }
#inv-table tr.row-selected:hover { background: var(--panel-3); }

/* ── Badges ──────────────────────────────────────────────────────────── */

.badge {
  display: inline-block;
  padding: 0.1rem 0.5rem;
  border-radius: 999px;
  font-size: 0.72rem;
  font-weight: 500;
  background: var(--border);
  color: var(--text);
  text-transform: lowercase;
  white-space: nowrap;
}

/* Cross-Account accounts table reuses these to communicate cell state.
   Mixed-case labels override the default lowercase so the pill reads as
   prose ("Configured", "Not deployed") rather than a status tag. */
.badge.badge-ok    { background: var(--ok-bg); color: var(--ok); text-transform: none; }
.badge.badge-muted { background: var(--neutral-bg); color: var(--muted, var(--neutral)); text-transform: none; }
.badge.badge-warn  { background: var(--warn-bg);  color: var(--warn-2); text-transform: none; }
.badge.badge-info  { background: var(--accent-a16);  color: var(--accent); text-transform: none; }

/* Inventory "Provider" chip (ADR #16). Semantic tokens only — a vendor
   brand hex does not re-theme and #ff9900 reads as --warn (the
   _PROVIDER_SLUGS rule in inventory.js). AWS = neutral (the incumbent
   majority provider); Azure = accent (the distinct path), mirroring the
   remote/outpost mode-pill split. An unknown provider value keeps the
   base .badge look, which is visibly "unstyled" on purpose. */
.badge.provider-aws   { background: var(--neutral-bg); color: var(--muted, var(--neutral)); }
.badge.provider-azure { background: var(--accent-a16); color: var(--accent); }

.status-running { background: var(--ok-bg); color: var(--ok); }
.status-creating, .status-modifying, .status-backing-up, .status-updating { background: var(--warn-bg); color: var(--warn); }
.status-deleting, .status-failed, .status-stopped, .status-inaccessible-encryption-credentials { background: var(--danger-bg); color: var(--danger); }

/* Classification-driven fallback. The four literals above cover the statuses
   that happened to be common when the column was written; AWS has dozens, and
   the ones our OWN one-clicks produce (`upgrading` from an engine upgrade,
   `maintenance` from forcing a pending action, `storage-optimization`) were not
   among them — so a fix in flight rendered as an unstyled, colourless badge.
   Keyed on classifyStatus so a status nobody enumerated still gets a colour. */
.badge.st-healthy  { background: var(--ok-bg);      color: var(--ok); }
.badge.st-degraded { background: var(--warn-bg);    color: var(--warn); }
.badge.st-failed   { background: var(--danger-bg);  color: var(--danger); }
.badge.st-unknown  { background: var(--neutral-bg); color: var(--muted, var(--neutral)); }

/* The status came from a MEMBER instance, not this row — the cluster itself is
   still `available`. Dotted underline marks it as inherited; the title says
   which member. Without the marker "updating" on a row whose own status is
   available reads as a glitch. */
.badge.status-rollup {
  border-bottom: 1px dotted currentColor;
  cursor: help;
}

/* Severity palette — kept in sync with the Home stat cards + framework
   pills so a critical row in the inventory legend reads the same hue
   as the Critical card on the dashboard. Lighter rgba backgrounds with
   a matching border-color give the chips a unified look at a glance. */
.sev-critical { background: var(--sev-critical-bg); color: var(--sev-critical); border: 1px solid var(--sev-critical-border); }
.sev-high     { background: var(--sev-high-bg); color: var(--sev-high); border: 1px solid var(--sev-high-border); }
.sev-medium   { background: var(--sev-medium-bg); color: var(--sev-medium); border: 1px solid var(--sev-medium-border); }
.sev-low      { background: var(--sev-low-bg); color: var(--sev-low); border: 1px solid var(--sev-low-border); }

/* Summary toggle above the inventory table — collapses the chart row
   so the table is above the fold by default. Charts are useful, but
   the primary task is "find a database and act on it", and 800px of
   donuts above the table interrupts that. */
.inv-summary-details {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 6px;
}
.inv-summary-details > summary {
  cursor: pointer;
  padding: 0.55rem 0.85rem;
  font-size: 0.85rem;
  color: var(--text);
  list-style: none;
  user-select: none;
}
.inv-summary-details > summary::marker { content: ""; }
.inv-summary-details > summary::-webkit-details-marker { display: none; }
.inv-summary-details > summary::before { content: "▸ "; color: var(--muted); }
.inv-summary-details[open] > summary::before { content: "▾ "; }
.inv-summary-details[open] > summary { border-bottom: 1px solid var(--border); }
.inv-summary-details > #compliance-summary,
.inv-summary-details > #inv-charts {
  padding: 0.85rem;
}

/* Inventory filter bar — appears above the table whenever ≥ 1 active
   filter is in effect. Mirrors the pattern from email/log UIs where
   "active filters" gets its own bar with an explicit clear button
   rather than expecting users to find a per-column × glyph. */
.inv-filter-bar {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.4rem 0.75rem;
  background: var(--accent-a04);
  border: 1px solid var(--accent-a35);
  border-radius: 6px;
  font-size: 0.82rem;
}
.inv-filter-bar[hidden] { display: none; }
.inv-filter-bar-summary { flex: 1; }
.inv-filter-clear-all {
  padding: 0.25rem 0.7rem;
  font-size: 0.78rem;
}

/* ── Cluster grouping — expand/collapse + child rows ───────────────── */

/* Cluster Identifier cell — the whole cell is the expand/collapse click
   target. Inline chevron + child-count badge are visual cues; the click
   handler lives on the TD and stopPropagations so the row's detail-drawer
   handler never sees it. Other cells on the same row remain clickable for
   the drawer. */
.cluster-id-cell {
  cursor: pointer;
  user-select: none;
}
.cluster-id-cell:hover { background: var(--panel-3); }

.inline-chevron {
  display: inline-block;
  color: var(--muted);
  font-size: 1.05rem;
  line-height: 1;
  min-width: 14px;
  margin-right: 6px;
  text-align: center;
}
.cluster-id-cell:hover .inline-chevron { color: var(--text); }

.child-count-badge {
  display: inline-block;
  margin-left: 0.4rem;
  padding: 0 6px;
  border-radius: 9px;
  font-size: 0.68rem;
  background: var(--panel-3);
  border: 1px solid var(--border-mid);
  color: var(--muted);
  letter-spacing: 0.02em;
  text-transform: lowercase;
}

.comp-row.child-row { background: var(--panel); }
.comp-row.child-row td { border-top: 1px dashed var(--panel-3); }
.comp-row.child-hidden { display: none; }
.child-row-cell { color: var(--muted); }

/* ── Controls catalog — category groups + merged-row expansion ───────── */

/* Category header row — pinned visually as a group label inside <tbody>.
   Spans every column. Not interactive. */
.ctrl-category-row td {
  padding: 0.7rem 0.85rem 0.4rem;
  background: var(--panel);
  border-bottom: 1px solid var(--border);
  border-top: 1px solid var(--border);
}
.ctrl-category-row .ctrl-category-name {
  font-size: 0.72rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--muted);
  margin-right: 0.5rem;
}

/* Per-framework posture cards above the controls table — mirror the
   Home dashboard's framework rows so a count of "20 GDPR" reads as
   "9/12 passing" with a tiered bar. Falls back to count-only chrome
   when no compliance data is cached (e.g. user landed on Controls
   before Home/Inventory). */
#controls-summary {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  gap: 0.6rem;
}
.ctrl-stat-card {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 0.55rem 0.75rem;
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  position: relative;
  overflow: hidden;
}
.ctrl-stat-card.ctrl-stat-card-overall {
  grid-column: span 2;
}
.ctrl-stat-card::after {
  content: "";
  position: absolute;
  inset: auto 0 0 0;
  height: 2px;
  background: transparent;
}
.ctrl-stat-card.ok::after   { background: var(--ok); }
.ctrl-stat-card.warn::after { background: var(--warn); }
.ctrl-stat-card.bad::after  { background: var(--danger); }
.ctrl-stat-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.5rem;
}
.ctrl-stat-label {
  font-size: 0.72rem;
  font-weight: 600;
  color: var(--text);
  letter-spacing: 0.04em;
  text-transform: uppercase;
}
.ctrl-stat-pct {
  font-size: 1.1rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.ctrl-stat-pct.ok   { color: var(--ok); }
.ctrl-stat-pct.warn { color: var(--warn); }
.ctrl-stat-pct.bad  { color: var(--danger); }
.ctrl-stat-pct.dim  { color: var(--muted); }
.ctrl-stat-bar {
  height: 4px;
  background: var(--track);
  border-radius: 999px;
  overflow: hidden;
}
.ctrl-stat-bar-fill {
  height: 100%;
  border-radius: 999px;
  min-width: 2px;
  transition: width 0.4s ease;
}
.ctrl-stat-bar-fill.ok   { background: var(--ok); }
.ctrl-stat-bar-fill.warn { background: var(--warn); }
.ctrl-stat-bar-fill.bad  { background: var(--danger); }
.ctrl-stat-counts { font-size: 0.74rem; }
.ctrl-stat-await {
  color: var(--warn);
  font-weight: 500;
  margin-left: 0.2rem;
}
/* Manual-attestation count on the framework cards. --info (not --warn) keeps
   "no automated check exists" visually distinct from "awaiting a scan". */
.ctrl-stat-manual {
  color: var(--info);
  font-weight: 500;
  margin-left: 0.2rem;
  cursor: help;
}

/* Description column — full descriptions are 6–8 lines and dominate
   the row height. Clamp to 2 lines by default with a `title` tooltip
   for hover, plus click-to-expand for users who want the full text
   without leaving the table. The title column alone is enough for
   scanning; this brings the row height down to ~3 lines max. */
.ctrl-desc-cell {
  max-width: 360px;
  vertical-align: top;
}
.ctrl-desc-clamp {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  overflow: hidden;
  font-size: 0.82rem;
  color: var(--muted);
  line-height: 1.45;
  cursor: pointer;
  word-break: break-word;
}
.ctrl-desc-clamp.is-expanded {
  -webkit-line-clamp: unset;
  display: block;
}
.ctrl-desc-clamp:hover { color: var(--text); }

/* Each merged-canonical row toggles its detail row when clicked. */
.ctrl-row { cursor: pointer; }
.ctrl-row:hover { background: var(--accent-a04); }

/* The leading expand-chevron column is narrow so it doesn't take width
   from real content. */
th.ctrl-expand-cell, td.ctrl-expand-cell {
  width: 24px;
  padding-left: 0.5rem;
  padding-right: 0;
  text-align: center;
}
.ctrl-expand-cell .inline-chevron { margin-right: 0; }

/* Detail row (canonical IDs + per-db_type severity breakdown). */
.ctrl-detail-row td {
  background: var(--panel);
  border-top: none;
  padding: 0.85rem 1.1rem 1rem;
}

.ctrl-detail-wrap {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 1.25rem;
}
.ctrl-detail-section { display: flex; flex-direction: column; gap: 0.4rem; }
.ctrl-detail-label {
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--muted);
  font-weight: 600;
}

.ctrl-detail-canonicals {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.55rem;
}
.ctrl-detail-canonicals li {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
}
.ctrl-detail-canonical-head {
  display: flex;
  align-items: center;
  gap: 0.55rem;
}
.ctrl-detail-cid {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.78rem;
  color: var(--text);
  background: var(--panel-2);
  border: 1px solid var(--border);
  padding: 0.1rem 0.4rem;
  border-radius: 3px;
}
.ctrl-detail-services {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.3rem;
  padding-left: 1.5rem;
}
.ctrl-detail-services-label {
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--muted);
  font-weight: 500;
}
/* AWS service chip — distinct from db_type chip (different palette so
   the two chip categories stay readable when they appear together). */
.svc-chip {
  display: inline-block;
  padding: 0.05rem 0.4rem;
  font-size: 0.7rem;
  font-weight: 500;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  border-radius: 3px;
  border: 1px solid var(--warn-bg);
  background: var(--warn-bg);
  color: var(--warn);
  white-space: nowrap;
}

.ctrl-detail-sev-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  gap: 0.35rem;
}
.ctrl-detail-sev-row {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

/* "Severity varies" hint — small ± symbol next to the merged severity
   badge, suggesting the user expand the row to see the breakdown. */
.ctrl-sev-varies {
  display: inline-block;
  margin-left: 0.3rem;
  color: var(--muted);
  font-weight: 600;
  cursor: help;
}

/* DB type chip (used in the DB Types column + the detail row). Same
   visual weight as .framework-chip but a slightly different palette
   so the two chip categories stay readable side-by-side. */
.db-type-chip {
  display: inline-block;
  margin: 0 0.2rem 0.15rem 0;
  padding: 0.05rem 0.4rem;
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  border-radius: 3px;
  border: 1px solid var(--border-mid);
  background: var(--panel-3);
  color: var(--muted);
  white-space: nowrap;
  text-transform: lowercase;
}
.db-type-chip-more {
  cursor: help;
  border-style: dashed;
  background: transparent;
  color: var(--muted);
}

/* Inventory: registry-driven "service unavailable in this account"
   info banner. Triggered when the user has narrowed to a service whose
   ServiceDefinition.unavailable_note is set (e.g. Timestream LiveAnalytics
   closed to new customers 2025-06-20). Renders above the table so the
   explanation is visible even when the filtered result set is empty. */
.inv-unavailable-card {
  margin: 0.6rem 0 0.8rem;
  padding: 0.6rem 0.8rem;
  border: 1px solid var(--warn-bg);
  border-left: 3px solid var(--warn);
  background: var(--warn-bg);
  border-radius: 3px;
  font-size: 0.82rem;
  line-height: 1.45;
}
.inv-unavailable-title {
  font-weight: 600;
  color: var(--warn);
  margin-bottom: 0.25rem;
}
.inv-unavailable-body {
  color: var(--warn);
}
