/* sp-ux.css - app-wide layout and usability layer (1.77.0, RM-339 / RM-340).
   Loaded on every page of both apps after the brand file; byte-identical in apex/support and
   apex/talan. Colours come only from Universal Theme variables, so it follows each app's brand.
   Standard: docs/ui/design-standard.md. Behaviour: sp-ux.js. */

:root {
  --sp-gap: 12px;
  --sp-radius: 10px;
  --sp-border: var(--ut-component-border-color, rgba(0, 0, 0, .1));
  --sp-surface: var(--ut-component-background-color, #fff);
  --sp-muted: var(--ut-body-text-color, #1f2937);
  --sp-accent: var(--ut-palette-primary, #4f46e5);
}

/* ── 1. Collapsed side menu: icons only ─────────────────────────────────────
   The brand file forces the label colour with !important, which defeated Universal Theme's
   own hiding, so the collapsed 52px rail showed an 8px slice of every label after its icon. */
body.js-navCollapsed .t-TreeNav .a-TreeView-node--topLevel > .a-TreeView-content > .a-TreeView-label {
  color: transparent !important;
}

/* ── 2. Filter bar (.sp-filterbar on the region) ────────────────────────────
   Fields sit side by side and wrap, whatever each item's "start new row" says: every APEX
   grid row inside the bar is flattened into one wrapping flex line. */
.sp-filterbar {
  background: var(--sp-surface);
  border: 1px solid var(--sp-border);
  border-radius: var(--sp-radius);
  padding: 10px 14px 4px;
  margin-bottom: 16px;
}
.sp-filterbar .t-Region-header { display: none; }
.sp-filterbar .t-Region-body { padding: 0; }
.sp-filterbar .t-Region-body > .container,
.sp-filterbar > .container {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 0 var(--sp-gap);
}
.sp-filterbar .container > .row { display: contents; }
.sp-filterbar .container > .row > .col {
  flex: 1 1 160px;
  max-width: 280px;
  width: auto;
  padding: 0;
}
.sp-filterbar .container > .row > .col:has(.sp-filter-wide),
.sp-filterbar .container > .row > .col:has([data-sp-wide]) {
  flex: 2 1 260px;
  max-width: 420px;
}
.sp-filterbar .t-Form-fieldContainer { margin-bottom: 8px; }
.sp-filterbar .t-Form-fieldContainer--floatingLabel .t-Form-label { white-space: nowrap; }
.sp-filterbar__actions {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0 0 8px auto;
  min-height: 48px;
}
.sp-filterbar__count {
  font-size: 12px;
  opacity: .75;
  white-space: nowrap;
}
.sp-filterbar__reset {
  white-space: nowrap;
  color: var(--sp-accent);
  font-weight: 600;
}
.sp-filterbar__reset:hover,
.sp-filterbar__reset:focus-visible { text-decoration: underline; }
.sp-filterbar__reset .t-Icon { color: inherit; }
.sp-filterbar:not(.has-filters) .sp-filterbar__reset { opacity: .7; }
.sp-filterbar__toggleLabel {
  flex: 1 1 auto;
  text-align: left;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.sp-filterbar__toggle { display: none; }
.sp-filterbar__toggle .fa { transition: transform .15s ease; }
.sp-filterbar:not(.is-collapsed) .sp-filterbar__toggle .fa { transform: rotate(180deg); }

@media (max-width: 640px) {
  .sp-filterbar { padding: 8px 10px 2px; }
  .sp-filterbar__toggle {
    display: flex;
    width: 100%;
    justify-content: space-between;
    align-items: center;
    margin: 0 0 6px;
    padding: 6px 2px;
    background: none;
    border: 0;
    box-shadow: none;
    font-weight: 600;
  }
  .sp-filterbar.is-collapsed .t-Region-body > .container > .row,
  .sp-filterbar.is-collapsed > .container > .row,
  .sp-filterbar.is-collapsed .sp-filterbar__actions { display: none; }
  .sp-filterbar .container > .row > .col { flex: 1 1 calc(50% - 6px); max-width: none; }
  .sp-filterbar .container > .row > .col:has(.sp-filter-wide) { flex-basis: 100%; }
  .sp-filterbar__actions { margin-left: 0; min-height: 0; }
}

/* ── 3. Info boxes: a real icon, a compact gutter, long text folded ─────────── */
.t-Alert--horizontal .t-Alert-icon { padding: 14px 10px 14px 14px; }
.t-Alert--horizontal .t-Alert-icon .t-Icon { width: 22px; height: 22px; font-size: 20px; }
/* Before sp-ux.js gives it an icon (or if it cannot), an empty gutter takes no room. */
.t-Alert-icon:empty,
.t-Alert-icon:not(:has(.t-Icon, .fa)) { display: none; }
.t-Alert--horizontal.t-Alert--info .t-Alert-body,
.t-Alert--horizontal.t-Alert--warning .t-Alert-body { font-size: 13px; line-height: 1.5; }
.t-Alert--horizontal .t-Alert-title { font-size: 15px; }
.sp-clamp .t-Alert-body {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  overflow: hidden;
}
.sp-clamp.is-open .t-Alert-body {
  display: block;
  -webkit-line-clamp: unset;
  overflow: visible;
}
.sp-clamp__more {
  display: block;
  margin: 0 auto 0 0;
  text-align: left;
  background: none;
  border: 0;
  padding: 2px 0 0;
  font: inherit;
  font-size: 12px;
  font-weight: 600;
  color: var(--sp-accent);
  cursor: pointer;
}
.sp-clamp__more:hover, .sp-clamp__more:focus-visible { text-decoration: underline; }

/* ── 4. Report cells ──────────────────────────────────────────────────────────
   Dates, times, versions and short codes never wrap (sp-ux.js marks the cells); numeric
   columns align right; a table wider than its card scrolls inside it. */
.sp-nowrap { white-space: nowrap; }
td.sp-num, th.sp-num { text-align: right; font-variant-numeric: tabular-nums; }
.t-Report-tableWrap, .a-IRR-tableContainer, .t-Report-wrap, .sp-xscroll { overflow-x: auto; max-width: 100%; }
.sp-xscroll { -webkit-overflow-scrolling: touch; }
/* on a phone a wrapped table of 4+ columns keeps readable columns and scrolls, instead of
   squeezing every cell to one word per line (a 2-column label/value table still wraps) */
@media (max-width: 640px) {
  .sp-xscroll > table:has(tr > :nth-child(4)) > * > tr > :is(th, td) { min-width: 6em; }
}
/* A grid column may shrink below its widest table, so the table's own wrapper scrolls instead of
   the column pushing past the card (cut on the right) or the page (sideways scroll on a phone). */
.row > .col, .t-Region-bodyWrap, .t-Region-body, .t-Body-mainContent { min-width: 0; }

/* Region class sp-hide-empty-cols: sp-ux.js marks a classic-report column whose cells are all empty. */
.sp-hide-empty-cols .sp-col-empty { display: none; }

/* Region class sp-stick (or td/th.sp-stick): the first column stays put while the table scrolls
   sideways - the record's name stays next to the values on a phone. */
.sp-stick table.t-Report-report tr > :first-child,
.sp-stick table.a-IRR-table tr > :first-child,
td.sp-stick, th.sp-stick {
  position: sticky;
  left: 0;
  z-index: 1;
  background: var(--sp-surface);
  box-shadow: inset -1px 0 0 var(--sp-border);
}
.sp-stick table.t-Report-report thead tr > :first-child,
.sp-stick table.a-IRR-table thead tr > :first-child,
th.sp-stick { z-index: 2; }

/* Region class sp-cap: a long secondary table is capped at 70% of the screen and scrolls inside,
   its header row staying visible. */
.sp-cap > .t-Region-bodyWrap > .t-Region-body { max-height: 70vh; overflow: auto; }
.sp-cap table thead th { position: sticky; top: 0; z-index: 3; background: var(--sp-surface); }

/* ── 5. KPI card rows: balanced columns (sp-ux.js sets --sp-kpi-cols) ─────── */
.sp-kpi-balanced {
  display: grid !important;
  grid-template-columns: repeat(var(--sp-kpi-cols, 4), minmax(0, 1fr)) !important;
}
.sp-kpi-balanced > * { min-width: 0 !important; max-width: none !important; }

/* ── 6. Title band on a phone: buttons in one scrollable row under the title ── */
@media (max-width: 640px) {
  .t-BreadcrumbRegion-top { flex-wrap: wrap; }
  .t-BreadcrumbRegion-body { order: 1; flex: 1 1 100%; }
  .t-BreadcrumbRegion-buttons--end {
    order: 2;
    flex: 1 1 100%;
    display: flex;
    flex-wrap: nowrap;
    overflow-x: auto;
    gap: 6px;
    padding: 6px 0 2px;
    -webkit-overflow-scrolling: touch;
  }
  .t-BreadcrumbRegion-buttons--end .t-Button {
    flex: 0 0 auto;
    margin: 0;
    width: auto;
    font-size: 12px;
    padding: 6px 10px;
  }
}

/* ── 7. Faceted search on a phone (768px and narrower): folded behind one button ────
   sp-ux.js marks the host (.sp-facets-host: the side column, or the facets' region) and toggles
   is-folded with a media-query listener, so a page opened wide and then narrowed folds too. */
.sp-facets-toggle { display: none; }
@media (max-width: 768px) {
  .sp-facets-toggle {
    display: flex;
    width: 100%;
    justify-content: space-between;
    align-items: center;
    margin: 0 0 12px;
    padding: 10px 14px;
    background: var(--sp-surface);
    border: 1px solid var(--sp-border);
    border-radius: var(--sp-radius);
    box-shadow: none;
    font-weight: 600;
    color: var(--sp-rec-ink, #0f172a);
  }
  .sp-facets-toggle .fa { color: var(--sp-accent); }
  .sp-facets-host--side.is-folded > *:not(.sp-facets-toggle) { display: none !important; }
  .t-Region.sp-facets-host.is-folded { display: none !important; }
}

/* ── 8. Report headers: one style for classic and interactive reports ────────── */
.t-Report-colHead,
.a-IRR-header {
  font-weight: 600;
}

/* ── 9. Record header (.sp-rec) ───────────────────────────────────────────────
   The top of a detail page: the record's name, its state as pills, a muted context line, its
   facts in labelled groups laid out across the page, and the page's actions. Built by
   app_ui_pkg.rec_header / rec_group / rec_fact / rec_pill (PL/SQL), so every detail page emits
   the same markup. Colours come from the brand tokens: purple on DB Realm, navy on Talan. */
.sp-rec {
  --sp-rec-ink: var(--dbr-slate-900, #0f172a);
  --sp-rec-muted: var(--dbr-slate-600, #475569);
  --sp-rec-line: var(--dbr-slate-200, #e2e8f0);
  position: relative;
  background: var(--sp-surface);
  border: 1px solid var(--sp-rec-line);
  border-radius: 12px;
  box-shadow: var(--dbr-shadow-sm, 0 1px 2px rgba(15, 23, 42, .06));
  overflow: hidden;
  margin: 0 0 16px;
  color: var(--sp-rec-ink);
}
.sp-rec::before {
  content: "";
  display: block;
  height: 4px;
  background: linear-gradient(90deg, var(--dbr-primary-700, #5b21b6) 0%,
                                     var(--dbr-primary-500, #7c3aed) 55%,
                                     var(--dbr-highlight-500, #c2414a) 100%);
}
.sp-rec__head {
  display: flex;
  align-items: flex-start;
  gap: 14px 16px;
  flex-wrap: wrap;
  padding: 18px 22px 16px;
}
.sp-rec__icon {
  flex: 0 0 auto;
  width: 44px;
  height: 44px;
  border-radius: 10px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--dbr-primary-50, #f5f3ff);
  color: var(--dbr-primary-700, #5b21b6);
  font-size: 20px;
}
.sp-rec__titles { flex: 1 1 320px; min-width: 0; }
.sp-rec__eyebrow {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--dbr-primary-700, #5b21b6);
  margin: 0 0 3px;
}
.sp-rec .sp-rec__title {
  margin: 0;
  font-size: 22px;
  line-height: 1.25;
  font-weight: 700;
  color: var(--sp-rec-ink);
  overflow-wrap: anywhere;
}
.sp-rec__sub {
  margin: 4px 0 0;
  font-size: 13px;
  color: var(--sp-rec-muted);
  overflow-wrap: anywhere;
}
.sp-rec__pills {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  align-items: center;
  justify-content: flex-end;
  flex: 0 1 auto;
  padding-top: 2px;
}
.sp-rec__body {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  border-top: 1px solid var(--sp-rec-line);
  background: var(--dbr-slate-50, #f8fafc);
}
.sp-rec__group {
  padding: 14px 22px 16px;
  min-width: 0;
  border-left: 1px solid var(--sp-rec-line);
  margin-left: -1px;
}
.sp-rec .sp-rec__gtitle,
.sp-rec__group .sp-rec__gtitle {
  margin: 0 0 10px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--dbr-primary-700, #5b21b6);
  display: flex;
  align-items: center;
  gap: 6px;
}
.sp-rec__facts {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(130px, 1fr));
  gap: 12px 18px;
  margin: 0;
}
.sp-fact { min-width: 0; margin: 0; }
.sp-fact--wide { grid-column: 1 / -1; }
.sp-fact__k {
  display: block;
  margin: 0 0 2px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .05em;
  text-transform: uppercase;
  color: var(--dbr-slate-500, #64748b);
}
.sp-fact__v {
  display: block;
  margin: 0;
  font-size: 14px;
  font-weight: 600;
  line-height: 1.4;
  color: var(--sp-rec-ink);
  overflow-wrap: anywhere;
}
.sp-fact__v a { font-weight: 600; }
.sp-fact__v--id {
  display: flex;
  align-items: center;
  gap: 6px;
  font-weight: 500;
}
.sp-fact__v .sp-pill { vertical-align: 1px; }
.sp-id {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
  font-size: 12.5px;
  color: var(--dbr-slate-700, #334155);
}
.sp-mono {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
  font-size: 12.5px;
  font-weight: 500;
}
.sp-fact__none { color: var(--dbr-slate-400, #94a3b8); font-weight: 500; }
.sp-rec__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  padding: 12px 22px;
  border-top: 1px solid var(--sp-rec-line);
  background: var(--sp-surface);
}
.sp-rec__actions .t-Button { margin: 0; }
.sp-rec__note {
  padding: 10px 22px;
  border-top: 1px solid var(--sp-rec-line);
  font-size: 13px;
  color: var(--sp-rec-muted);
}

/* A record header whose actions are APEX buttons placed in the region body: the region is
   only a host (no chrome), the header comes first and the button row reads as its footer.
   Region: cssClasses sp-rec-host, template options t-Region--hideHeader and t-Region--noUI. */
/* !important: the brand file forces a border and shadow on every .t-Region */
.t-Region.sp-rec-host { background: transparent !important; border: 0 !important; box-shadow: none !important; }
.sp-rec-host > .t-Region-bodyWrap > .t-Region-body {
  display: flex;
  flex-direction: column;
  padding: 0;
  margin: 0 0 16px;
  background: var(--sp-surface);
  border: 1px solid var(--dbr-slate-200, #e2e8f0);
  border-radius: 12px;
  box-shadow: var(--dbr-shadow-sm, 0 1px 2px rgba(15, 23, 42, .06));
  overflow: hidden;
}
.sp-rec-host > .t-Region-bodyWrap > .t-Region-body > .sp-rec {
  order: 0;
  margin: 0;
  border: 0;
  border-radius: 0;
  box-shadow: none;
}
.sp-rec-host > .t-Region-bodyWrap > .t-Region-body > .container {
  order: 1;
  margin: 0;
  padding: 12px 22px;
  border-top: 1px solid var(--dbr-slate-200, #e2e8f0);
  max-width: none;
}
.sp-rec-host > .t-Region-bodyWrap > .t-Region-body > .container > .row {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 0;
}
.sp-rec-host > .t-Region-bodyWrap > .t-Region-body > .container > .row > .col {
  flex: 0 0 auto;
  width: auto;
  max-width: none;
  padding: 0;
}
.sp-rec-host > .t-Region-bodyWrap > .t-Region-body > .container > .row > .col:empty { display: none; }
.sp-rec-host > .t-Region-bodyWrap > .t-Region-body > .container:not(:has(.t-Button)) { display: none; }
.sp-rec-host .t-Button { margin: 0; }

/* A record header that carries its own actions: the region is only a frame-less wrapper.
   Region: cssClasses sp-rec-bare, template options t-Region--hideHeader and t-Region--noUI. */
.t-Region.sp-rec-bare { background: transparent !important; border: 0 !important; box-shadow: none !important; }
.sp-rec-bare > .t-Region-bodyWrap > .t-Region-body { padding: 0; }

/* Status pills: a word and a dot, in a semantic tone. app_ui_pkg.rec_pill / tone_of. */
.sp-pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 10px;
  border-radius: 999px;
  border: 1px solid transparent;
  font-size: 12px;
  font-weight: 600;
  line-height: 1.4;
  white-space: nowrap;
  background: var(--dbr-slate-100, #f1f5f9);
  color: var(--dbr-slate-700, #334155);
  border-color: var(--dbr-slate-200, #e2e8f0);
}
.sp-pill::before {
  content: "";
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: currentColor;
  opacity: .85;
}
.sp-pill--ok    { background: var(--dbr-success-50, #ecfdf5); color: var(--dbr-success-700, #047857); border-color: var(--dbr-success-100, #d1fae5); }
.sp-pill--warn  { background: var(--dbr-warning-50, #fffbeb); color: var(--dbr-warning-700, #b45309); border-color: var(--dbr-warning-100, #fef3c7); }
.sp-pill--bad   { background: var(--dbr-danger-50, #fef2f2);  color: var(--dbr-danger-700, #b91c1c);  border-color: var(--dbr-danger-100, #fee2e2); }
.sp-pill--info  { background: var(--dbr-info-50, #eff6ff);    color: #1d4ed8;                          border-color: var(--dbr-info-100, #dbeafe); }
.sp-pill--brand { background: var(--dbr-primary-50, #f5f3ff); color: var(--dbr-primary-700, #5b21b6); border-color: var(--dbr-primary-100, #ede9fe); }
.sp-pill--neutral::before { opacity: .55; }
/* a small pill for a flag in a table cell (app_ui_pkg.flag: Yes / No) */
.sp-pill--sm { gap: 5px; padding: 1px 8px; font-size: 11.5px; }
.sp-pill--sm::before { width: 6px; height: 6px; }

/* Copy button beside an identifier or a code panel (sp-ux.js copies data-sp-copy). */
.sp-copy {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 5px;
  min-width: 26px;
  height: 26px;
  padding: 0 6px;
  border: 1px solid var(--dbr-slate-200, #e2e8f0);
  border-radius: 6px;
  background: var(--sp-surface);
  color: var(--dbr-slate-600, #475569);
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
}
.sp-copy:hover, .sp-copy:focus-visible {
  color: var(--dbr-primary-700, #5b21b6);
  border-color: var(--dbr-primary-300, #c4b5fd);
  background: var(--dbr-primary-50, #f5f3ff);
}
.sp-copy.is-copied { color: var(--dbr-success-700, #047857); border-color: var(--dbr-success-100, #d1fae5); }

@media (max-width: 640px) {
  .sp-rec__head { padding: 14px 16px 12px; }
  .sp-rec .sp-rec__title { font-size: 19px; }
  .sp-rec__icon { width: 36px; height: 36px; font-size: 16px; }
  .sp-rec__titles { flex: 1 1 0; }
  .ivgroups { grid-template-columns: minmax(0, 1fr); }
  .sp-rec__pills { justify-content: flex-start; flex-basis: 100%; }
  .sp-rec__group { padding: 12px 16px 14px; border-left: 0; margin-left: 0; border-top: 1px solid var(--sp-rec-line); }
  .sp-rec__group:first-child { border-top: 0; }
  .sp-rec__facts { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px 14px; }
  .sp-rec__actions, .sp-rec__note,
  .sp-rec-host > .t-Region-bodyWrap > .t-Region-body > .container { padding: 10px 16px; }
}

/* ── 10. Code panel (.sp-code): raw JSON, a config file, an SQL text, a stack ─────
   A header strip (label, note, copy) over a monospace, scrolling body. Replaces bare <pre>. */
.sp-code {
  margin: 0 0 14px;
  border: 1px solid var(--dbr-slate-200, #e2e8f0);
  border-radius: 10px;
  overflow: hidden;
  background: var(--sp-surface);
}
* + .sp-code { margin-top: 12px; }
.sp-code__bar {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 7px 8px 7px 14px;
  background: var(--dbr-slate-50, #f8fafc);
  border-bottom: 1px solid var(--dbr-slate-200, #e2e8f0);
  border-left: 3px solid var(--dbr-primary-500, #7c3aed);
}
.sp-code__label {
  font-size: 12.5px;
  font-weight: 700;
  color: var(--dbr-primary-700, #5b21b6);
  white-space: nowrap;
}
.sp-code__note {
  flex: 1 1 auto;
  min-width: 0;
  font-size: 12px;
  color: var(--dbr-slate-500, #64748b);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* the strip wraps (a long label or note on a phone), so its Copy button stays inside the card */
.sp-code__bar { flex-wrap: wrap; }
.sp-code__bar .sp-copy { flex: 0 0 auto; margin-left: auto; }
@media (max-width: 640px) {
  .sp-code__label { white-space: normal; min-width: 0; }
}
.sp-code pre,
pre.sp-code__body {
  margin: 0;
  padding: 12px 14px;
  max-height: 420px;
  overflow: auto;
  background: var(--dbr-slate-900, #0f172a);
  color: #e2e8f0;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
  font-size: 12.5px;
  line-height: 1.55;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  border: 0;
  border-radius: 0;
}
.sp-code--light pre { background: var(--sp-surface); color: var(--dbr-slate-800, #1e293b); }
.sp-code--tall pre { max-height: 560px; }
.sp-code--short pre { max-height: 240px; }

/* Plain text that keeps its line breaks (an email body, a message): prose, not code. */
.sp-text {
  margin: 0 0 14px;
  padding: 12px 14px;
  background: var(--dbr-slate-50, #f8fafc);
  border: 1px solid var(--dbr-slate-200, #e2e8f0);
  border-radius: 10px;
  font-size: 13px;
  line-height: 1.55;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  font-family: inherit;
}
/* an HTML email body shown inside the app (cli_email_pkg previews) */
.sp-email-body { background: #fff; border: 1px solid var(--dbr-slate-200, #e2e8f0); border-radius: 10px; padding: 14px; }

/* ── 11. Module helpers used across modules (UI-012) ───────────────────────────
   These classes are emitted by pages and packages of several modules, but each was defined
   in one module stylesheet only, so on every other page they rendered as unstyled text (a
   red error box as plain text, an empty state as a normal paragraph). The rules are copied
   VERBATIM from their module file (finops-dashboard.css, monitoring-report.css, audit.css,
   client-360.css), which still ships them: a page loading both gets the same result.
   tools/check-css-classes.py keeps a page from using a class its stylesheets do not load. */
.fin-region-error { color: #9a2020; background: #fdecea; border: 1px solid #f5c6c0; border-radius: 6px; padding: 10px 14px; font-size: 13px; }
.fin-hint { color: #5b6b7a; font-size: 13px; margin: 2px 2px 10px; }
.mon-wrap { max-width: none; }   /* 1.78.0 (RM-344): fills the content width; p70 and p72 used to override the old 1100px cap */
.mon-empty { color: #94a3b8; font-style: italic; font-size: 13px; }
.mon-ctx { display: flex; flex-wrap: wrap; gap: 10px 26px; background: #f8fafc; border: 1px solid #e5e7eb;
  border-radius: 10px; padding: 14px 18px; margin-bottom: 20px; }
.mon-ctx__item { font-size: 13px; }
.mon-ctx__k { color: #64748b; font-size: 11px; text-transform: uppercase; letter-spacing: .04em; display: block; }
.mon-ctx__v { font-weight: 700; color: #0f172a; }
.mon-kv { width: 100%; border-collapse: collapse; }
.mon-kv td { padding: 6px 10px; border-bottom: 1px solid #eef2f7; vertical-align: top; }
.mon-kv tr:last-child td { border-bottom: 0; }
.mon-kv__k { white-space: nowrap; font-weight: 600; width: 1%; }
.sp-gap-top { margin-top: 10px; }
.aud-banner { border-radius:6px; padding:10px 14px; margin:0 0 12px; font-size:13px;
              display:flex; align-items:center; flex-wrap:wrap; gap:8px; }
.aud-banner--fresh { background:#ebfbee; color:#2b8a3e; border:1px solid #b2f2bb; }
.aud-banner--stale { background:#fff5f5; color:#b3261e; border:1px solid #ffc9c9; }
.aud-banner--muted { background:#f1f3f5; color:#495057; border:1px solid #dee2e6; }
.aud-banner .fa { font-size:15px; }
.c360-card {
  background: var(--fin-card-bg,#fff); border: 1px solid var(--fin-card-border,#ece9f5);
  border-radius: 12px; padding: 14px 16px; box-shadow: var(--fin-shadow, 0 1px 3px rgba(16,24,40,.08));
  position: relative;
}

/* ── 12. Inventory detail tables (inv_render_pkg: Details, Related Resources) ───
   Was an inline <style> in the package with a fixed navy header; now one place, brand tokens. */
.ivt { border-collapse: collapse; width: 100%; font-size: 13px; margin: 2px 0 16px; }
.ivt th, .ivt td { border-bottom: 1px solid var(--dbr-slate-200, #e2e8f0); padding: 7px 10px; text-align: left; vertical-align: top; }
.ivt thead th {
  background: var(--dbr-slate-50, #f8fafc);
  color: var(--dbr-slate-600, #475569);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .05em;
  text-transform: uppercase;
  white-space: nowrap;
  border-bottom: 2px solid var(--dbr-slate-200, #e2e8f0);
}
.ivt tbody tr:hover td { background: var(--dbr-slate-50, #f8fafc); }
.ivk { width: 34%; color: var(--dbr-slate-600, #475569); font-weight: 600; }
.ivv { word-break: break-word; }
/* the section heading inv_render_pkg emits (<h4 class="ivh">); a scoped selector, because
   inv_health_render_pkg uses .ivh as the root of its panels (p5) */
h4.ivh {
  margin: 18px 0 8px;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--dbr-primary-700, #5b21b6);
  display: flex;
  align-items: baseline;
  gap: 8px;
}
h4.ivh:first-child { margin-top: 4px; }
.ivsub { font-size: 12px; color: var(--dbr-slate-500, #64748b); font-weight: 500; letter-spacing: 0; text-transform: none; }
.ivbadge {
  display: inline-block;
  font-size: 11px;
  font-weight: 600;
  padding: 2px 8px;
  border-radius: 999px;
  background: var(--dbr-primary-50, #f5f3ff);
  color: var(--dbr-primary-700, #5b21b6);
}
/* the configuration of a resource as grouped cards (inv_render_pkg.config_cards) */
.ivgroups {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(340px, 1fr));
  gap: 14px;
  margin: 4px 0 18px;
  align-items: start;
}
.ivgroups > .sp-rec__group {
  margin: 0;
  padding: 14px 16px 16px;
  background: var(--sp-surface);
  border: 1px solid var(--dbr-slate-200, #e2e8f0);
  border-top: 3px solid var(--dbr-primary-500, #7c3aed);
  border-radius: 10px;
}
.ivgroups .sp-fact__v { font-size: 13.5px; }
.ivgroups__flags { grid-column: 1 / -1; }

/* on/off chips (Yes/No fields) */
.sp-chips { display: flex; flex-wrap: wrap; gap: 6px; }
.sp-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 10px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 600;
  border: 1px solid var(--dbr-slate-200, #e2e8f0);
  background: var(--dbr-slate-50, #f8fafc);
  color: var(--dbr-slate-600, #475569);
}
.sp-chip::before { font-family: inherit; font-weight: 700; }
.sp-chip--on { background: var(--dbr-success-50, #ecfdf5); border-color: var(--dbr-success-100, #d1fae5); color: var(--dbr-success-700, #047857); }
.sp-chip--on::before { content: "\2713"; }
.sp-chip--off::before { content: "\2013"; color: var(--dbr-slate-400, #94a3b8); }

/* ── 14. Change timeline (.sp-tl, inv_render_pkg.changes_html) ──────────────── */
.sp-tl { list-style: none; margin: 0; padding: 0 0 0 4px; }
.sp-tl__item {
  position: relative;
  display: grid;
  grid-template-columns: 140px minmax(0, 1fr);
  gap: 4px 16px;
  padding: 10px 0 10px 20px;
  border-left: 2px solid var(--dbr-slate-200, #e2e8f0);
}
.sp-tl__item::before {
  content: "";
  position: absolute;
  box-sizing: border-box;
  left: -8px;
  top: 13px;
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: var(--sp-surface);
  border: 3px solid var(--dbr-primary-500, #7c3aed);
}
.sp-tl__item--routine { padding-top: 6px; padding-bottom: 6px; }
.sp-tl__item--routine::before { width: 10px; height: 10px; left: -6px; top: 10px; border-width: 2px; border-color: var(--dbr-slate-300, #cbd5e1); }
.sp-tl__when { font-size: 12.5px; font-weight: 600; color: var(--dbr-slate-600, #475569); font-variant-numeric: tabular-nums; padding-top: 2px; }
.sp-tl__item--routine .sp-tl__when { font-weight: 500; color: var(--dbr-slate-500, #64748b); }
.sp-tl__body { min-width: 0; display: flex; flex-direction: column; gap: 6px; }
.sp-tl__chg { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 10px; font-size: 13px; }
.sp-tl__attr { font-weight: 700; color: var(--dbr-slate-900, #0f172a); }
.sp-tl__vals { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 6px; min-width: 0; }
.sp-tl__old, .sp-tl__new {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 12px;
  padding: 1px 6px;
  border-radius: 4px;
  overflow-wrap: anywhere;
}
.sp-tl__old { background: var(--dbr-danger-50, #fef2f2); color: var(--dbr-danger-700, #b91c1c); text-decoration: line-through; text-decoration-color: rgba(185, 28, 28, .45); }
.sp-tl__new { background: var(--dbr-success-50, #ecfdf5); color: var(--dbr-success-700, #047857); }
.sp-tl__arrow { color: var(--dbr-slate-400, #94a3b8); }
/* RM-344 (1.78.0): the word variant. A value that is a word or a phrase (Critical, Production, Oracle
   Database) is plain text; the monospace chip stays for hostnames, versions, numbers and paths. */
.sp-tl__old--word, .sp-tl__new--word { font-family: inherit; font-size: 13px; }
.sp-tl__routine { font-size: 12.5px; color: var(--dbr-slate-500, #64748b); display: flex; gap: 8px; align-items: baseline; }
.sp-tl__routine .fa { color: var(--dbr-slate-400, #94a3b8); }
@media (max-width: 640px) {
  .sp-tl__item { grid-template-columns: minmax(0, 1fr); }
}

/* ── 15. Empty state (.sp-empty): an icon, what is missing, what to do ─────────── */
.sp-empty {
  display: flex;
  gap: 14px;
  align-items: flex-start;
  padding: 16px 18px;
  border: 1px dashed var(--dbr-slate-300, #cbd5e1);
  border-radius: 10px;
  background: var(--dbr-slate-50, #f8fafc);
}
.sp-empty__icon {
  flex: 0 0 auto;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--dbr-primary-50, #f5f3ff);
  color: var(--dbr-primary-700, #5b21b6);
  font-size: 16px;
}
.sp-empty__title { font-weight: 700; font-size: 14px; color: var(--dbr-slate-800, #1e293b); margin: 0 0 2px; }
.sp-empty__text { font-size: 13px; color: var(--dbr-slate-600, #475569); line-height: 1.5; }

/* ── 13. Tool strip (.sp-strip): a segmented choice, a sentence about it, a hint ─── */
.sp-strip {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 14px;
  align-items: center;
  margin: 0 0 12px;
  padding: 10px 14px;
  background: var(--sp-surface);
  border: 1px solid var(--dbr-slate-200, #e2e8f0);
  border-left: 3px solid var(--dbr-primary-500, #7c3aed);
  border-radius: 10px;
  font-size: 13px;
}
.sp-strip__seg { display: inline-flex; gap: 6px; }
.sp-strip .fin-hint { margin: 0; }

/* ── 16. Callout (.sp-callout) and panel (.sp-panel) ───────────────────────────
   A callout separates explanation from data: an icon, a tinted background, smaller text.
   A panel is a frame for rec_group sections outside a record header (a status panel). */
.sp-callout {
  display: flex;
  gap: 12px;
  align-items: flex-start;
  margin: 0 0 14px;
  padding: 12px 14px;
  border-radius: 10px;
  background: var(--dbr-info-50, #eff6ff);
  border: 1px solid var(--dbr-info-100, #dbeafe);
  color: var(--dbr-slate-700, #334155);
  font-size: 13px;
  line-height: 1.55;
}
.sp-callout > .fa { flex: 0 0 auto; font-size: 16px; line-height: 1.4; color: #1d4ed8; }
.sp-callout p { margin: 0 0 6px; }
.sp-callout p:last-child { margin-bottom: 0; }
.sp-callout--warn { background: var(--dbr-warning-50, #fffbeb); border-color: var(--dbr-warning-100, #fef3c7); }
.sp-callout--warn > .fa { color: var(--dbr-warning-700, #b45309); }
.sp-callout--brand { background: var(--dbr-primary-50, #f5f3ff); border-color: var(--dbr-primary-100, #ede9fe); }
.sp-callout--brand > .fa { color: var(--dbr-primary-700, #5b21b6); }
.sp-panel {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  margin: 0 0 14px;
  background: var(--dbr-slate-50, #f8fafc);
  border: 1px solid var(--dbr-slate-200, #e2e8f0);
  border-radius: 10px;
  overflow: hidden;
}
.sp-panel > .sp-rec__group { padding: 12px 16px 14px; }
.sp-panel + .sp-callout, .sp-panel + .fin-hint { margin-top: -4px; }

/* ── 17. Daily AI review digest (aud_review_pkg.digest_html, p100) ───────────────
   The model's sanitised list, structured: a head with severity counts, the summary line,
   each finding a card led by its severity pill, "Next action" as a label. */
.aud-dg__head { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 8px; margin: 0 0 10px; }
.aud-dg__title { font-weight: 700; font-size: 14px; color: var(--dbr-slate-900, #0f172a); margin-right: 6px; display: inline-flex; gap: 8px; align-items: center; }
.aud-dg__title .fa { color: var(--dbr-primary-600, #6d28d9); }
.aud-dg__summary { color: var(--dbr-slate-600, #475569); font-size: 13px; }
.aud-digest__body ul.aud-dg__list, ul.aud-dg__list { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }
.aud-dg__item {
  padding: 10px 12px 10px 14px;
  border: 1px solid var(--dbr-slate-200, #e2e8f0);
  border-left: 4px solid var(--dbr-slate-300, #cbd5e1);
  border-radius: 8px;
  background: var(--sp-surface);
  font-size: 13px;
  line-height: 1.55;
}
.aud-dg__item > .sp-pill { margin-right: 8px; vertical-align: 1px; }
.aud-dg__item--critical, .aud-dg__item--high { border-left-color: var(--dbr-danger-500, #ef4444); }
.aud-dg__item--medium { border-left-color: var(--dbr-warning-500, #f59e0b); }
.aud-dg__item--low { border-left-color: var(--dbr-info-500, #3b82f6); }
.aud-dg__next {
  display: inline-block;
  margin: 4px 6px 0 0;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .05em;
  text-transform: uppercase;
  color: var(--dbr-primary-700, #5b21b6);
}

/* ── 18. KPI cards: one card app-wide ──────────────────────────────────────────
   Global: every class app_ui_pkg.kpi_card emits is defined here, so no page needs a module
   stylesheet for it (UI-012). The left-accent card: white, a 4px accent on the left, a small
   icon and an upper-case label,
   the value, a muted line under it. .fin-kpi (most pages, mon_render_pkg, mon_outage_pkg),
   .ui-kpi (app_ui_pkg.render_card: was an icon-tile card) and .mon-kpi (p70) all render as it.
   The accent follows the tone: sp-kpi--ok | warn | bad | info | brand | neutral (and the older
   ui-kpi--success|warning|danger|info|muted, mon-kpi--ok|warn|crit). A card whose value is 0 is
   neutral (sp-ux.js adds sp-kpi--zero unless the page set an sp-kpi-- tone). A card that draws
   its own status border gets no second stripe (sp-kpi--striped). `body` outranks the module
   stylesheets a page loads after this file. */
/* The card row (app_ui_pkg.kpi_card output goes in it). The same rule as finops-dashboard.css,
   here so a page needs no module stylesheet for a KPI row; sp-ux.js then balances the columns. */
.fin-kpi-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
  gap: 14px;
  margin: 4px 0 8px;
}
body .fin-kpi,
body .ui-kpi,
body .mon-kpi {
  --sp-kpi-accent: var(--dbr-primary-500, #7c3aed);
  --sp-kpi-icon: var(--dbr-primary-600, #6d28d9);
  position: relative;
  overflow: hidden;
  background: var(--sp-surface);
  border: 1px solid var(--dbr-slate-200, #e2e8f0);
  border-radius: 10px;
  box-shadow: var(--dbr-shadow-sm, 0 1px 2px rgba(15, 23, 42, .06));
  padding: 14px 16px 14px 18px;
  color: var(--dbr-slate-900, #0f172a);
  text-decoration: none;
}
body .fin-kpi::before,
body .ui-kpi::before,
body .mon-kpi::before {
  content: "";
  position: absolute;
  inset: 0 auto 0 0;
  width: 4px;
  background: var(--sp-kpi-accent);
}
body .fin-kpi.sp-kpi--striped::before { display: none; }
body a.fin-kpi:hover, body a.ui-kpi:hover { box-shadow: 0 4px 12px rgba(15, 23, 42, .12); }

body .fin-kpi__label,
body .ui-kpi .ui-kpi__label,
body .mon-kpi .mon-kpi__l {
  display: flex;
  align-items: center;
  gap: 7px;
  margin: 0;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .05em;
  text-transform: uppercase;
  color: var(--dbr-slate-500, #64748b);
}
body .fin-kpi__icon { color: var(--sp-kpi-icon); font-size: 13px; line-height: 1; }
body .fin-kpi__value,
body .ui-kpi .ui-kpi__value,
body .mon-kpi .mon-kpi__n {
  margin-top: 8px;
  font-size: 26px;
  font-weight: 700;
  line-height: 1.1;
  color: var(--dbr-slate-900, #0f172a);
  font-variant-numeric: tabular-nums;
}
body .fin-kpi__meta,
body .ui-kpi .ui-kpi__sub {
  margin-top: 3px;
  font-size: 12px;
  color: var(--dbr-slate-500, #64748b);
}

/* .ui-kpi markup is icon + body(value, label, sub): laid out as label row, value, sub. */
body .ui-kpi {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  grid-template-areas: "icon label" "value value" "sub sub";
  column-gap: 7px;
  align-items: center;
}
body .ui-kpi .ui-kpi__body { display: contents; }
body .ui-kpi .ui-kpi__icon {
  grid-area: icon;
  width: auto;
  height: auto;
  background: none !important;
  border-radius: 0;
  color: var(--sp-kpi-icon);
  font-size: 13px;
  line-height: 1;
  animation: none;
}
body .ui-kpi .ui-kpi__label { grid-area: label; }
body .ui-kpi .ui-kpi__value { grid-area: value; }
body .ui-kpi .ui-kpi__sub { grid-area: sub; }
/* .mon-kpi markup is value then label: the label goes first. */
body .mon-kpi { display: flex; flex-direction: column; }
body .mon-kpi .mon-kpi__l { order: -1; }
body .mon-kpi .mon-kpi__n { margin-top: 8px; }

/* tones */
body .sp-kpi--brand { --sp-kpi-accent: var(--dbr-primary-500, #7c3aed); --sp-kpi-icon: var(--dbr-primary-600, #6d28d9); }
body .sp-kpi--ok, body .ui-kpi--success, body .mon-kpi--ok {
  --sp-kpi-accent: var(--dbr-success-500, #22c55e); --sp-kpi-icon: var(--dbr-success-700, #047857);
}
body .sp-kpi--warn, body .ui-kpi--warning, body .mon-kpi--warn {
  --sp-kpi-accent: var(--dbr-warning-500, #f59e0b); --sp-kpi-icon: var(--dbr-warning-700, #b45309);
}
body .sp-kpi--bad, body .ui-kpi--danger, body .mon-kpi--crit {
  --sp-kpi-accent: var(--dbr-danger-500, #ef4444); --sp-kpi-icon: var(--dbr-danger-700, #b91c1c);
}
body .sp-kpi--bad .fin-kpi__value,
body .ui-kpi--danger .ui-kpi__value,
body .mon-kpi--crit .mon-kpi__n { color: var(--dbr-danger-700, #b91c1c); }
body .sp-kpi--info, body .ui-kpi--info { --sp-kpi-accent: var(--dbr-info-500, #3b82f6); --sp-kpi-icon: #1d4ed8; }
body .sp-kpi--neutral, body .ui-kpi--muted, body .sp-kpi--zero {
  --sp-kpi-accent: var(--dbr-slate-300, #cbd5e1); --sp-kpi-icon: var(--dbr-slate-400, #94a3b8);
}
/* a zero is never an alarm: !important beats an inline style="color:#b91c1c" on the value */
body .sp-kpi--zero .fin-kpi__value,
body .sp-kpi--zero .ui-kpi__value,
body .sp-kpi--zero .mon-kpi__n { color: var(--dbr-slate-500, #64748b) !important; }
body .sp-kpi--zero.sp-kpi--striped { border-left-color: var(--dbr-slate-200, #e2e8f0) !important; border-left-width: 1px !important; }
body .sp-kpi--zero.sp-kpi--striped::before { display: block; }

/* ── 19. Tabs: the selected tab in the brand colour ─────────────────────────────
   Tabs containers and region display selectors drew the selected tab in the theme's teal
   (p25 Client Profile) on both apps. Brand tokens: purple on DB Realm, navy on Talan. */
.t-Tabs .t-Tabs-item.is-active > .t-Tabs-link,
.t-Tabs .t-Tabs-item.apex-rds-selected > .t-Tabs-link {
  color: var(--dbr-primary-700, #5b21b6) !important;
}
.t-Tabs:not(.t-Tabs--pill) .t-Tabs-item.is-active > .t-Tabs-link,
.t-Tabs:not(.t-Tabs--pill) .t-Tabs-item.apex-rds-selected > .t-Tabs-link {
  border-color: var(--dbr-primary-500, #7c3aed) !important;
  box-shadow: inset 0 -2px 0 var(--dbr-primary-500, #7c3aed) !important;
}
.t-Tabs .t-Tabs-item.is-active > .t-Tabs-link::after,
.t-Tabs .t-Tabs-item.apex-rds-selected > .t-Tabs-link::after {
  background-color: var(--dbr-primary-500, #7c3aed) !important;
  border-color: var(--dbr-primary-500, #7c3aed) !important;
}
.t-Tabs--pill .t-Tabs-item.is-active > .t-Tabs-link,
.t-Tabs--pill .t-Tabs-item.apex-rds-selected > .t-Tabs-link,
.t-TabsRegion-mod--pill .t-Tabs-item.is-active > .t-Tabs-link,
.t-TabsRegion-mod--pill .t-Tabs-item.apex-rds-selected > .t-Tabs-link {
  background-color: var(--dbr-primary-50, #f5f3ff) !important;
  border-color: var(--dbr-primary-200, #ddd6fe) !important;
}

/* ── 20. Platform marks in lists (mon_platform_pkg.badge_html style A) ───────────
   The engine, flavor, distro and OS-family marks read as small neutral pills, like .sp-pill
   (the target header's style C tiles are unchanged). Outranks platform-badges.css. */
.sp-plat--a.sp-plat--engine,
.sp-plat--a.sp-plat--flavor,
.sp-plat--a.sp-plat--distro,
.sp-plat--a.sp-plat--os-family {
  gap: 5px;
  padding: 2px 9px 2px 7px;
  border-radius: 999px;
  border: 1px solid var(--dbr-slate-200, #e2e8f0);
  background: var(--dbr-slate-100, #f1f5f9);
  font-size: 12px;
  font-weight: 600;
  line-height: 1.4;
}
.sp-plat--a.sp-plat--engine .sp-plat__lbl,
.sp-plat--a.sp-plat--flavor .sp-plat__lbl,
.sp-plat--a.sp-plat--distro .sp-plat__lbl,
.sp-plat--a.sp-plat--os-family .sp-plat__lbl { color: var(--dbr-slate-700, #334155); }
.sp-plat--a.sp-plat--engine .sp-plat__ico,
.sp-plat--a.sp-plat--flavor .sp-plat__ico,
.sp-plat--a.sp-plat--distro .sp-plat__ico,
.sp-plat--a.sp-plat--os-family .sp-plat__ico { width: 14px; height: 14px; }
.sp-plat--a.sp-plat--unknown .sp-plat__lbl { color: var(--dbr-slate-500, #64748b); }

/* ── 21. Empty current-facets strip ─────────────────────────────────────────────
   A faceted page's "current facets" region (<div id="..._active_facets">, the facets'
   currentFacetsSelector) is an empty card until a filter is chosen: sp-ux.js marks it. */
.sp-strip-empty { display: none !important; }
