.chartRow{ display:flex; flex-wrap:wrap; gap:16px; align-items:flex-start; }
.chartBox{ flex:1 1 520px; max-width: 640px; background:#0b1520; border:1px solid #233041; border-radius:12px; padding:12px; box-shadow:0 1px 2px rgba(0,0,0,.25); }
.chartTitle{ font-weight:600; margin:4px 0 8px 0; }
.legend{ display:flex; flex-wrap:wrap; gap:8px; margin-top:8px; }
.legend .item{ display:flex; align-items:center; gap:6px; font-size:12px; background:#0f172a; padding:4px 8px; border-radius:10px; }
.legend .sw{ width:12px; height:12px; border-radius:3px; display:inline-block; }

/* App Info Card */
.appInfoCard {
  background: var(--card);
  padding: 18px 20px;
  margin-top: 12px;
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.appInfoTop { display: flex; gap: 20px; align-items: flex-start; }
.appInfoIcon {
  width: 72px;
  height: 72px;
  border-radius: 16px;
  object-fit: cover;
  flex-shrink: 0;
  border: 1px solid var(--border);
  background: var(--bg);
}
.appInfoIconPlaceholder {
  width: 72px;
  height: 72px;
  border-radius: 16px;
  flex-shrink: 0;
  border: 1px solid var(--border);
  background: var(--bg);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 28px;
}
.appInfoBody { flex: 1; min-width: 0; }
.appInfoName { font-size: 18px; font-weight: 700; margin-bottom: 4px; }
.appInfoHostname { font-size: 12.5px; margin-bottom: 4px; }
.appInfoHostname .appInfoLabel { color: var(--muted); }
.appInfoDesc { color: var(--muted); font-size: 13px; margin-bottom: 10px; }
.appInfoGrid {
  display: grid;
  grid-template-columns: repeat(2, minmax(220px, 1fr));
  gap: 14px;
}
.appInfoCol {
  min-width: 0;
  background: color-mix(in srgb, var(--panel), black 6%);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 12px 14px;
}
.appInfoColTitle {
  margin-bottom: 10px;
}
.appInfoColTitle .appInfoBadge {
  font-size: 13px;
}
.appInfoRows {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.appInfoRow {
  display: flex;
  align-items: flex-start;
  gap: 7px;
  font-size: 13px;
  flex-wrap: wrap;
}
.appInfoLabel { color: var(--muted); white-space: nowrap; }
.appInfoVal { font-weight: 600; word-break: break-word; overflow-wrap: anywhere; }
.appInfoStore {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: color-mix(in srgb, var(--panel), black 8%);
  font-size: 13px;
  color: inherit;
  text-decoration: none;
}
.appInfoStore:hover {
  text-decoration: none;
  transform: translateY(-1px);
}
.appInfoBadge {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 3px 9px; border-radius: 20px; font-size: 12px; font-weight: 600;
}
.appInfoBadge a {
  color: inherit;
  text-decoration: none;
}
.appInfoBadge .badgeAction {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  border-radius: 999px;
  opacity: .9;
}
.appInfoBadge .badgeAction:hover {
  opacity: 1;
  transform: translateY(-1px);
}
.appInfoBadge.android { background: var(--green-bg); color: var(--green); }
.appInfoBadge.ios     { background: var(--blue-bg);  color: var(--blue);  }
.appInfoBadge.off     { background: var(--gray-bg);  color: var(--muted); }

@media (max-width: 1100px) {
  .appInfoGrid { grid-template-columns: 1fr; }
}

@media (max-width: 700px) {
  .appInfoCard {
    flex-direction: column;
    align-items: stretch;
    gap: 12px;
    padding: 14px 14px;
  }
  .appInfoIcon,
  .appInfoIconPlaceholder {
    width: 56px;
    height: 56px;
  }
}


/* Show only on mobile */
.only-mobile { display:inline-flex !important; }
@media (min-width:768px){ .only-mobile { display:none !important; } }

/* File list link color normalization */
#fileList a { color: var(--muted) !important; text-decoration: none; }
#fileList a:hover { color: var(--text) !important; text-decoration: underline; }

/* =============================
  App Styles — Cleaned & Fixed
  - Syntax errors fixed (all braces closed)
  - Duplicates consolidated
  - Modern CSS preserved (custom props, gap, color-mix, inset)
  - Light/Dark theming kept
  ============================= */

/* Prevent white flash: keep dark backdrop while app boots */
html.preload,
html.preload body { background:var(--color-bg, #0d0d12) !important; }

#appLoader {
 position: fixed;
 inset: 0;
 display: flex;
 align-items: center;
 justify-content: center;
 background: var(--color-bg, #0d0d12);
 z-index: 2147483647;
 transition: opacity .25s ease;
}
#appLoader .spinner {
 width: 48px;
 height: 48px;
 border-radius: 50%;
 border: 3px solid rgba(255,255,255,0.18);
 border-top-color: #ffffff;
 animation: spin 1s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg) } }

/* =============================
  Theme tokens
  ============================= */
/* Local aliases — tied to the global theme tokens so view_report.css
   themes automatically when html.theme-light is active. Page-specific
   accents that don't map to theme tokens keep their literal hex. */
:root {
 --bg:     var(--color-bg, var(--color-bg, #0d0d12));
 --card:   var(--color-bg-elevated, var(--color-bg-elevated, #16161e));
 --text:   var(--color-text, var(--color-text, #e8e8f0));
 --muted:  var(--color-text-dim, var(--color-text-dim, #8888aa));
 --border: var(--color-border, rgba(0, 229, 212, 0.14));
 --green:#00e5a0;   --green-bg:rgba(0, 229, 160, 0.11);
 --yg:#ffb700;      --yg-bg:rgba(255, 183, 0, 1);
 --blue: var(--color-accent, #00e5d4);    --blue-hover:#00c4b8;
 --blue-bg:rgba(0, 229, 212, 0.11);
 --red:#ff4d6d;     --red-bg:rgba(255, 77, 109, 0.13);
 --gray:var(--color-text-dim, #8888aa);    --gray-bg:rgba(136, 136, 170, 0.15);

 --panel: var(--card);
 --accent: var(--blue);
 --accent-hover: var(--blue-hover);
 --accent-contrast: var(--color-bg, var(--color-bg, #0d0d12));
 --ok: var(--green);
 --ok-bg: var(--green-bg);
 --warn: var(--yg);
 --warn-bg: var(--yg-bg);
 --danger: var(--red);
 --danger-bg: var(--red-bg);
 --pill: var(--gray-bg);
 --pill-text: var(--text);

 --page-max: 1600px;
}
/* Light-theme overrides for the custom page-specific hues. */
html.theme-light {
  --green-bg: rgba(0, 168, 100, 0.10);
  --yg-bg:    rgba(168, 120, 0, 0.12);
  --blue-bg:  rgba(0, 168, 154, 0.08);
  --red-bg:   rgba(201, 42, 71, 0.10);
  --gray-bg:  rgba(20, 30, 55, 0.06);
  --green:    #1e7a3d;
  --yg:       #a87800;
  --red:      #c92a47;
  --gray:     #4b5568;
  --border:   var(--color-border);
}


/* =============================
  Base
  ============================= */
* { box-sizing: border-box; }
body {
 margin: 0;
 background: var(--bg);
 color: var(--text);
 font-family: ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,Ubuntu,Cantarell,Arial;
}
.wrap { max-width: var(--page-max); margin: 0 auto; padding: 0 16px; padding-top: 10px; padding-bottom: 10px }

/* Toolbar */
.toolbar { padding: 20px 0 8px; }
.toolbar h1 { margin: 0; font-size: 40px; }
.toolbar .sub { margin: 6px 0 14px; color: var(--muted); }
.toolbar .bar {
 display: flex;
 gap: 10px;
 align-items: center;
 background: var(--panel);
 border: 1px solid var(--border);
 border-radius: 12px;
 padding: 10px;
 width: 100%;
}
.toolbar input {
 flex: 1;
 min-width: 240px;
 padding: 10px 12px;
 border: 1px solid var(--border);
 border-radius: 10px;
 background: var(--panel);
 color: var(--text);
}
.toolbar .ghost {
 background: transparent;
 border: 1px solid var(--border);
 color: var(--text);
 border-radius: 10px;
 padding: 8px 12px;
 cursor: pointer;
}
.toolbar .primary {
 background: var(--accent);
 border: 0;
 color: #0b1220;
 font-weight: 700;
 border-radius: 10px;
 padding: 8px 12px;
 cursor: pointer;
}

/* Layout — modDetail (content) dictates height; aside (modules list) matches it via JS, modList scrolls.
   `minmax(0, 1fr)` on the content column (not bare `1fr`, which is `minmax(auto, 1fr)`) prevents wide
   intrinsic content (e.g. a Records Index table row) from pushing the column wider than its share,
   which otherwise grows the whole .layout past --page-max and makes the page visibly resize when
   sections with wider content open. Wide content inside should scroll within its own container
   (e.g. .tableWrap { overflow-x: auto } below), not blow up the page layout. */
.layout { display: grid; grid-template-columns: 320px minmax(0, 1fr); gap: 16px; padding-bottom: 20px; align-items: start; }
.layout > aside { display: flex; flex-direction: column; min-height: 0; align-self: start; }

/* Sidebar */
aside { background: var(--panel); border:1px solid var(--border); border-radius:12px; padding:12px; }
aside h3 { margin: 0 0 8px; }
#modList { display:flex; flex-direction:column; gap:8px; overflow-y:auto; flex:1; min-height:0; scrollbar-width: thin; scrollbar-color: rgba(0,229,212,.35) transparent; }
#modList::-webkit-scrollbar { width: 5px; }
#modList::-webkit-scrollbar-track { background: transparent; }
#modList::-webkit-scrollbar-thumb { background: rgba(0,229,212,.35); border-radius: 999px; }
#modList::-webkit-scrollbar-thumb:hover { background: rgba(0,229,212,.65); }

/* Module buttons */
.modBtn {
 all: unset;
 display: block;
 padding: 8px 10px;
 border: 1px solid var(--border);
 border-radius: 999px;
 background: color-mix(in srgb, var(--panel), black 10%);
 color: var(--text);
 cursor: pointer;
}
/* Selected module highlight (dark+light aware) */
.modBtn.active {
 background: color-mix(in srgb, var(--accent), white 75%);
 border-color: color-mix(in srgb, var(--accent), black 20%);
 font-weight: 700;
 color: #0b1220;
}
.modBtn.active {
 background: color-mix(in srgb, var(--accent), black 75%);
 border-color: color-mix(in srgb, var(--accent), black 30%);
 color: #fff;
}
/* Main/entry module — subtle accent outline so it stays identifiable even when another is active */
.modBtn.main {
 border-color: color-mix(in srgb, var(--accent), transparent 40%);
 box-shadow: inset 2px 0 0 0 var(--accent);
}
.modBtn.main.active {
 box-shadow: none;
}

/* Panels */
.panel { background: var(--panel); border:1px solid var(--border); border-radius:12px; padding:12px; }
.grid2 { display:grid; grid-template-columns:1fr; gap:8px; }
.title h2 { margin:0; }

/* ─────────────────────────────────────────────────────────────────────
 * Module Identity Hero — replaces the old .kv table at the top of each
 * module's detail panel. Built by view_report.js renderModuleDetail().
 *
 * Layout: title row (with optional Sends-Email pill) → 4×2 cards grid
 * → optional <details class="modIdTechSection"> with full Application/
 * Home keys.  See data.json: reactiveModules[i].moduleInfo.{hasEmails,
 * applicationKey, homeKey, moduleVersion, moduleSequence, …}.
 *
 * Card values are clipped to one line via overflow:ellipsis. UUIDs in
 * key cards are pre-truncated to first8…last5 in JS so the visible
 * string is naturally short; the copy button still copies the full
 * value, and the expandable below shows it untruncated.
 * ───────────────────────────────────────────────────────────────────── */
.modIdHeroTitle { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
/* Module sequence rendered inside the H2 next to the name. Smaller +
   muted + regular-weight so it reads as a build-number annotation
   rather than a second title. Monospace makes the digits line up if
   the user is mentally diffing across modules. */
.modIdHeroTitle h2 .modIdSeq {
  color: var(--muted); font-weight: 400;
  font-size: 0.65em; margin-left: 4px;
  font-family: 'Fira Code', ui-monospace, monospace;
  vertical-align: middle;
}
.modIdEmailPill {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 4px 10px; border-radius: 999px; font-size: 12px; font-weight: 600;
  border: 1px solid rgba(0,229,212,0.45); color: var(--blue);
  background: rgba(0,229,212,0.08);
}
.modIdCards {
  display: grid; gap: 12px;
  /* 3-up on wide screens (one card per primary identity field).
     Was 4-up when Module Name had its own card; now that the H2 title
     carries the module name, dropping to 3 columns keeps the row
     evenly filled instead of leaving a blank fourth slot. */
  grid-template-columns: repeat(3, minmax(0, 1fr));
}
/* 4-up modifier for callers with four cards (server hero uses this). */
.modIdCards.cols4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
@media (max-width: 1100px) {
  .modIdCards,
  .modIdCards.cols4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 600px)  {
  .modIdCards,
  .modIdCards.cols4 { grid-template-columns: 1fr; }
}

/* ─────────────────────────────────────────────────────────────────────
 * Server Hero — top of #serverPanel. Same family as Module Identity
 * Hero (.modIdCards / .modIdCard / .modIdTechSection are reused). The
 * only new pieces here are the URL-display row and the scan-window
 * strip; everything else is borrowed from the module hero so the page
 * has one consistent identity-panel language.
 * ───────────────────────────────────────────────────────────────────── */
.svHero { display: flex; flex-direction: column; gap: 16px; }
.svHeroUrlRow {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 12px 14px;
  background: color-mix(in srgb, var(--panel), black 8%);
  border: 1px solid var(--border); border-radius: 10px;
  min-width: 0;
}
.svHeroIcon { color: var(--blue); font-size: 18px; flex: 0 0 auto; }
.svHeroUrl {
  /* Long URLs are common — let the row truncate gracefully on narrow
     widths via min-width:0 + ellipsis, but break-word on wider ones so
     the whole URL is visible. */
  flex: 1 1 auto; min-width: 0;
  font-family: 'Fira Code', ui-monospace, monospace;
  font-size: 15px; font-weight: 600;
  color: var(--text); text-decoration: none;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.svHeroUrl:hover { color: var(--blue); text-decoration: underline; }
.svEnvPill {
  flex: 0 0 auto;
  display: inline-flex; align-items: center; gap: 6px;
  padding: 4px 10px; border-radius: 999px; font-size: 12px; font-weight: 600;
  border: 1px solid rgba(0,229,212,0.45); color: var(--blue);
  background: rgba(0,229,212,0.08);
  text-transform: uppercase; letter-spacing: 0.04em;
}
/* Server-wide hardening pills. Same pill geometry as .svEnvPill but
   warn-coloured (debugEnabled / showExceptionStack). Rendered only in
   the TRUE state by view_report.js — see comment near _hardenPills. */
.svConfigPill {
  flex: 0 0 auto;
  display: inline-flex; align-items: center; gap: 6px;
  padding: 4px 10px; border-radius: 999px; font-size: 12px; font-weight: 600;
  border: 1px solid var(--border); color: var(--muted);
  background: transparent;
}
.svConfigPill.warn {
  border-color: rgba(255,183,0,0.55); color: var(--yg); background: rgba(255,183,0,0.10);
}
.svConfigPill.bad {
  border-color: rgba(255,77,109,0.55); color: var(--red); background: rgba(255,77,109,0.10);
}
.svScanParams {
  display: flex; flex-direction: column; gap: 6px;
  padding: 10px 14px;
  background: color-mix(in srgb, var(--panel), black 8%);
  border: 1px solid var(--border); border-radius: 10px;
  font-size: 13px;
}
.modIdCard {
  background: color-mix(in srgb, var(--panel), black 6%);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 14px 14px 12px;
  display: flex; flex-direction: column; gap: 6px;
  /* min-width:0 is required so flex/grid children can shrink below their
     intrinsic content width — without it the ellipsis on .modIdValue
     never engages and the card overflows the grid track. */
  min-width: 0;
}
.modIdCard .modIdIcon { color: var(--blue); font-size: 18px; }
.modIdCard .modIdLabel { color: var(--muted); font-size: 12px; text-transform: uppercase; letter-spacing: 0.04em; }
.modIdCard .modIdValue {
  color: var(--text); font-size: 16px; font-weight: 600;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  min-width: 0;
}
.modIdCard .modIdValue.mono { font-family: 'Fira Code', ui-monospace, monospace; font-size: 14px; font-weight: 500; }
.modIdCard .modIdSub { color: var(--muted); font-size: 12px; }
.modIdValueRow { display: flex; align-items: center; gap: 6px; min-width: 0; }
.modIdValueRow > .modIdValue { flex: 1 1 auto; }
.modIdCopy {
  flex: 0 0 auto;
  background: transparent; border: 1px solid var(--border); color: var(--muted);
  border-radius: 6px; padding: 4px 6px; cursor: pointer;
  transition: color 120ms, border-color 120ms;
}
.modIdCopy:hover { color: var(--blue); border-color: rgba(0,229,212,0.45); }
.modIdCopy.copied { color: var(--green); border-color: rgba(0,229,160,0.45); }

/* Technical identifiers expandable. Native <details> avoids JS state. */
.modIdTechSection {
  background: color-mix(in srgb, var(--panel), black 6%);
  border: 1px solid var(--border); border-radius: 10px;
  padding: 0;
}
.modIdTechSection > summary {
  list-style: none; cursor: pointer;
  padding: 12px 14px;
  display: flex; align-items: center; gap: 10px;
  font-weight: 600;
}
.modIdTechSection > summary::-webkit-details-marker { display: none; }
.modIdTechSection > summary::before {
  content: ''; display: inline-block; width: 0; height: 0;
  border-left: 5px solid var(--muted); border-top: 4px solid transparent; border-bottom: 4px solid transparent;
  transition: transform 120ms;
}
.modIdTechSection[open] > summary::before { transform: rotate(90deg); }
.modIdTechSection > summary .modIdTechExpand {
  margin-left: auto; font-size: 12px; color: var(--muted); font-weight: 400;
}
.modIdTechSection[open] > summary .modIdTechExpand { display: none; }
.modIdTechRow {
  display: flex; align-items: center; gap: 12px;
  padding: 10px 14px; border-top: 1px solid var(--border);
  min-width: 0;
}
.modIdTechRow .modIdTechLabel { color: var(--muted); font-size: 13px; min-width: 130px; }
.modIdTechRow .modIdTechValue {
  flex: 1 1 auto; min-width: 0;
  font-family: 'Fira Code', ui-monospace, monospace; font-size: 13px;
  color: var(--text);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* Key/Value table */
.kv { width:100%; border-collapse:collapse; }
.kv th,
.kv td { border-bottom:1px solid var(--border); padding:8px 10px; text-align:left; vertical-align:top; }
.kv th { width:220px; color: color-mix(in srgb, var(--text), white 10%); background: color-mix(in srgb, var(--panel), black 10%); }

/* Pills */
.pill { display:inline-flex; align-items:center; justify-content:center; min-width:22px; padding:0 6px; height:22px; border-radius:999px; border:1px solid transparent; background:color-mix(in srgb, var(--accent), black 35%); color:#fff; font-weight:600; }
.bad { color: var(--danger); }
.warn{ color: var(--warn); }
.ok { color: var(--ok); }

/* Sections (collapsible) */
.section { border:1px solid var(--border); border-radius:10px; margin-top:10px; overflow:hidden; }
.section .head { display:flex; align-items:center; justify-content:flex-start; padding:10px; background: color-mix(in srgb, var(--panel), black 10%); cursor:pointer; }
.section .head::before { content:'▸'; margin-right:8px; }
.section.open .head::before { content:'▾'; }
.section .body { display:none; padding:10px; }
.section.open .body { display:block; }
/* Non-collapsible sections */
.section.no-collapse .head { cursor: default !important; }
.section.no-collapse .head::before { content:'' !important; }

/* Text helpers */
.url { word-break: break-word; overflow-wrap:anywhere; }
.mono { font-family: ui-monospace, Menlo, Consolas, monospace; }

/* Rows & buttons */
.urlRow { display:flex; gap:8px; align-items:center; justify-content:space-between; flex-wrap:wrap; }
.btns { display:flex; gap:6px; }
.btn {
 font-weight:600;
 border-radius:8px;
 padding:6px 10px;
 cursor:pointer;
 text-decoration:none;
 display:inline-block;
 background: color-mix(in srgb, var(--panel), black 8%);
 color: var(--text);
 border: 1px solid var(--border);
 transition: background .15s ease, border-color .15s ease;
}
.btn:hover {
 background: color-mix(in srgb, var(--accent), black 55%);
 border-color: color-mix(in srgb, var(--accent), transparent 50%);
}
.btn.sm { font-size:12px; padding:4px 8px; }
.btn.ghost { background:transparent; border:1px solid var(--border); color:var(--text); }
.list { margin:0; padding-left:18px; }
.scroll { overflow:auto; }
code { background: color-mix(in srgb, var(--panel), black 15%); border:1px solid var(--border); border-radius:6px; padding:2px 6px; color:#7ee8d7; }

/* Server header */
.svGrid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 1rem;
}
.svCard { display:grid; grid-template-columns:auto 1fr; grid-template-rows:auto auto; gap:4px 8px; align-items:center; background: color-mix(in srgb, var(--panel), black 6%); border:1px solid var(--border); border-radius:10px; padding:12px; }
.svIcon { grid-row:1/3; font-size:20px; }
.svTitle { font-size:12px; color:var(--muted); }
.svMain { font-weight:700; }
.svSub { font-size:12px; color:var(--muted); }

/* Mobile items */
.mobItem { display:flex; align-items:center; justify-content:flex-start; gap:12px; margin:6px 0; padding:6px 8px; background: color-mix(in srgb, var(--panel), black 6%); border:1px solid var(--border); border-radius:8px; }
.mobName { font-weight:700; }
.mobText { display:flex; flex-direction:column; gap:4px; min-width:0; }
.mobDesc { font-size:12px; color:var(--muted); line-height:1.45; word-break:break-word; overflow-wrap:anywhere; }
.mobBadge { display:inline-block; border:1px solid var(--border); border-radius:999px; padding:2px 8px; margin-right:6px; background: color-mix(in srgb, var(--panel), black 10%); width: 42; display: flex; align-items: center; justify-content: center; }
.mobBadge.ok { border-color:transparent; background:var(--accent); color:#0b1220; }

/* Generic text */
.muted { color: var(--muted); }
.row { display:flex; gap:8px; align-items:center; margin-bottom:8px; }
.subhead { font-weight:700; margin:6px 0; }
.chip { display:inline-block; margin:2px 4px 2px 0; }

/* Action cards (Global Server Actions, per-module action lists) */
.aCard { border:1px solid var(--border); border-radius:10px; margin:6px 0; background: color-mix(in srgb, var(--panel), black 6%); overflow:hidden; transition: border-color .12s; }
.aCard.open { border-color: color-mix(in srgb, var(--accent, #00e5d4), transparent 55%); }
.aHead { display:flex; align-items:center; gap:10px; padding:9px 12px; cursor:pointer; }
.aHead:hover { background: color-mix(in srgb, var(--panel), black 12%); }
/* chevron affordance so it's obvious the row expands */
.aHead::after { content:'\f078'; font-family:'Font Awesome 6 Free'; font-weight:900; font-size:10px; color:var(--muted); margin-left:auto; transition: transform .15s; opacity:.7; }
.aCard.open .aHead::after { transform: rotate(180deg); }
.aTitle { font-weight:600; font-size:13px; display:flex; align-items:center; gap:8px; min-width:0; flex-wrap:wrap; }

/* ── "Called from {clientAction}" chip ─────────────────────────────
   Rendered inside .aTitle on server-action cards when the Python
   scanner's calledFrom[] array is populated — surfaces the calling
   client action(s) on a screen. Visually subdued (muted background +
   small font) because it's secondary signal: the primary thing is the
   action name + warning badges. The arrow icon points BACK at the
   caller (← visually "this is invoked from over there"). */
.calledFromChip {
  display: inline-flex; align-items: center; gap: 4px;
  font-weight: 500; font-size: 11px;
  padding: 2px 8px; border-radius: 999px;
  background: color-mix(in srgb, var(--muted, #8888aa), transparent 88%);
  color: var(--muted, #8888aa);
  border: 1px solid color-mix(in srgb, var(--muted, #8888aa), transparent 70%);
  white-space: nowrap;
}
.calledFromChip code {
  background: transparent !important;
  border: 0 !important;
  padding: 0 !important;
  color: var(--color-text, inherit) !important;
  font-family: ui-monospace, 'Fira Code', Menlo, Consolas, monospace;
  font-size: 11px;
}
.calledFromChip .calledFromIco {
  font-size: 9px;
  opacity: .7;
  transform: rotate(-90deg);   /* point LEFT → "invoked from over here" */
}

/* Clickable variant — when the chip carries a resolved client-action
   key + window.OML_FLOW is available, clicking opens the calling
   client action's flow modal. Cursor + hover state signal it's
   interactive. Subtle accent shift on hover so it doesn't compete with
   the action card's own header hover. */
.calledFromChip.calledFromChipClickable {
  cursor: pointer;
  transition: background-color .12s ease, border-color .12s ease, color .12s ease;
}
.calledFromChip.calledFromChipClickable:hover {
  background: color-mix(in srgb, var(--accent, #5b9aff), transparent 80%);
  border-color: color-mix(in srgb, var(--accent, #5b9aff), transparent 50%);
  color: color-mix(in srgb, var(--accent, #5b9aff), white 5%);
}
.calledFromChip.calledFromChipClickable:hover .calledFromIco {
  opacity: 1;
}

/* ── Site Properties table ─────────────────────────────────────────
   Replaces the old inline saItem rendering where name/type/default/
   badges were all crammed into one line. Now a five-column table:
   Name · Type · Default · Last edited by · Flags. Columns align
   across rows; cells stay compact. spAuthor column collapses to "—"
   when no author info (typical for platform-provided properties
   like TenantId / TenantName). */
.spTable {
  width: 100%;
  border-collapse: collapse;
  font-size: 12px;
}
.spTable thead th {
  text-align: left;
  font-weight: 600;
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--muted, #8888aa);
  padding: 6px 12px;
  border-bottom: 1px solid color-mix(in srgb, var(--muted, #8888aa), transparent 75%);
}
.spTable tbody td {
  padding: 6px 12px;
  border-bottom: 1px solid color-mix(in srgb, var(--muted, #8888aa), transparent 88%);
  vertical-align: middle;
}
.spTable tbody tr:last-child td { border-bottom: 0; }
.spTable .spName code {
  font-size: 12px;
}
.spTable .spType,
.spTable .spDefault,
.spTable .spAuthor {
  white-space: nowrap;
}
.spTable .spFlags {
  text-align: right;
}

/* ── Integrations: method cards ────────────────────────────────────
   Each method gets its own bordered card with a contrast band so
   the methods don't visually bleed into each other (the previous
   layout was bare <li>s and a 10-method service looked like one
   unbroken paragraph). The integration-level wrapper (.integCard) is
   the outer <details>; .integMethod is each method's row. */
.integCard {
  margin-bottom: 6px;
}
.integMethodList {
  margin-top: 10px;
  padding-left: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.integMethod {
  display: block;
  padding: 10px 12px;
  border: 1px solid color-mix(in srgb, var(--muted, #8888aa), transparent 75%);
  border-radius: 8px;
  background: color-mix(in srgb, var(--panel, #1a1a24), white 2%);
}
.integMethod .integMethodHead {
  display: flex;
  align-items: center;
  gap: 8px;
  justify-content: space-between;
  margin-bottom: 4px;
}
.integMethod .mod-name {
  font-weight: 600;
  font-size: 13px;
}

/* ── Author block (in expanded action body) ────────────────────────
   OML-sourced developer attribution. Lives INSIDE the action card
   body (not the row header) — surfaces "Created by" + "Last edited
   by" as small labelled rows so reviewers find the owner after
   drilling in, rather than seeing the email noise on every row of
   the SA list. */
.authorBlock {
  display: flex; align-items: flex-start; gap: 10px;
  margin-top: 10px; padding: 8px 12px;
  border: 1px solid color-mix(in srgb, var(--muted, #8888aa), transparent 75%);
  border-radius: 8px;
  background: color-mix(in srgb, var(--muted, #8888aa), transparent 92%);
}
.authorBlock .authorBlockIco {
  margin-top: 2px;
  font-size: 13px;
  color: var(--muted, #8888aa);
  opacity: .8;
}
.authorBlock .authorRows {
  display: flex; flex-direction: column; gap: 3px;
  min-width: 0;
}
.authorBlock .authorRow {
  display: flex; align-items: baseline; gap: 8px;
  font-size: 12px;
  line-height: 1.4;
}
.authorBlock .authorLabel {
  font-weight: 600;
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--muted, #8888aa);
  min-width: 90px;
}
.authorBlock .authorEmail {
  background: transparent !important;
  border: 0 !important;
  padding: 0 !important;
  font-family: ui-monospace, 'Fira Code', Menlo, Consolas, monospace;
  font-size: 12px;
  color: var(--color-text, inherit) !important;
}

/* ── Legacy single-line chip (kept for future compact callers) ────
   Same data, one-line pill format. Not currently in use anywhere on
   the page; keep the rule so future code can reuse it without
   re-deriving the styling. */
.authorChip {
  display: inline-flex; align-items: center; gap: 4px;
  font-weight: 500; font-size: 11px;
  padding: 2px 8px; border-radius: 999px;
  background: color-mix(in srgb, var(--accent, #5b9aff), transparent 90%);
  color: color-mix(in srgb, var(--accent, #5b9aff), white 10%);
  border: 1px solid color-mix(in srgb, var(--accent, #5b9aff), transparent 65%);
  white-space: nowrap;
}
.authorChip code {
  background: transparent !important;
  border: 0 !important;
  padding: 0 !important;
  color: inherit !important;
  font-family: ui-monospace, 'Fira Code', Menlo, Consolas, monospace;
  font-size: 11px;
}
.authorChip .authorIco {
  font-size: 10px;
  opacity: .75;
}

/* ── Global Server Actions list — calmer title rendering ──────────────
   actionCard wraps the name in <code>, and the global `code { … }` rule
   adds a teal pill (background + border + green text). On the GSA list
   that visual weight is loud — we already have a row count pill, severity
   pills, and per-row chevrons fighting for attention. The user asked for
   the calm treatment Structures uses (<span class="mono"> inside <summary>):
   monospace text, no chrome. Scoped to .gsaList so per-screen action
   lists (which DO benefit from the pill look) stay untouched. */
.gsaList .aTitle code {
  background: transparent;
  border: 0;
  padding: 0;
  color: var(--color-text, var(--text, inherit));
  font-family: ui-monospace, 'Fira Code', Menlo, Consolas, monospace;
  font-size: 13px;
  border-radius: 0;
}

.aBody { display:none; padding:2px 12px 12px; }
.aCard.open .aBody { display:block; }
.aBody .urlRow { margin:6px 0 2px; }
.aBody .url.mono { font-size:11px; color:var(--muted); word-break:break-all; }
.aKey { margin-top:8px; }

/* Inputs / Outputs as a clean two-column grid of chips */
.ioGrid { display:grid; grid-template-columns:1fr 1fr; gap:14px; margin-top:8px; }
@media (max-width:640px){ .ioGrid { grid-template-columns:1fr; } }
.ioGrid > div { min-width:0; }
.aBody .subhead, .aKey .subhead, .ioGrid .subhead {
 font-weight:600; font-size:10px; text-transform:uppercase; letter-spacing:.05em;
 color:var(--muted); margin:0 0 6px;
}
/* Styled chips inside the action body (param name : type). Scoped to .aBody
   so the bare global `.chip` used elsewhere is untouched. */
.aBody .chip {
 display:inline-flex; align-items:baseline; gap:5px;
 background: rgba(127,127,127,0.10);
 border:1px solid var(--border);
 border-radius:6px; padding:3px 8px; margin:0 5px 5px 0;
 font-size:11.5px; color:var(--muted); max-width:100%;
}
.aBody .chip code { background:transparent; border:0; padding:0; color:var(--text); font-weight:600; word-break:break-all; }
.aBody .ioGrid .muted { font-size:11.5px; }
.grid.auto { table-layout:auto; }
.grid.auto.wide td { white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }

/* Collapsible screen cards */
.screenHead { display:flex; align-items:center; justify-content:space-between; padding:10px; cursor:pointer; }
.screenHead .left { display:flex; align-items:center; gap:8px; }
.screenCard .screenBody { display:none; border-top:1px solid var(--border); padding-top:8px; }
.screenCard.open .screenBody { display:block; }

/* Tabs */
.tabs { display:flex; gap:8px; margin-bottom:8px; }
.tab { all:unset; cursor:pointer; border:1px solid var(--border); border-radius:999px; padding:6px 12px; background: color-mix(in srgb, var(--panel), black 8%); }
.tab.active { background:var(--accent); color:#0b1220; }
.badge { display:inline-block; min-width:20px; text-align:center; padding:1px 6px; border-radius:999px; border:1px solid var(--border); margin-left:6px; background: color-mix(in srgb, var(--panel), black 12%); }

/* Print styles */
@media print {
 .no-print, .no-print * { display:none !important; }
 body { background:#fff; color:#000; }
 .panel, aside, .section, .screenCard, .kv th, .kv td { border-color:#ccc !important; background:#fff !important; }
 a,button { color:#000 !important; }
 /* Neutral gray for file links */
 a.fileLink, a.fileLink:visited { color:#9aa4b2 !important; }
 a.fileLink:hover { color:#b8c0cc !important; text-decoration:underline; }
}

/* Client var chip */
.cvChip { display:inline-block; margin:4px 6px 0 0; padding:3px 8px; border-radius:999px; border:1px solid var(--border); background: color-mix(in srgb, var(--panel), black 6%); font-size:.9rem; line-height:1.6; white-space:nowrap; }

/* Environment card alignment (consolidated latest styles) */
.svGrid { display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:12px; margin-top:12px; }
.svCard { display:grid; grid-template-columns:24px 1fr; grid-template-rows:auto auto auto; gap:4px 10px; align-items:start; background: color-mix(in srgb, var(--panel), black 4%); border:1px solid var(--border); border-radius:12px; padding:12px; }
.svIcon { grid-row:1 / span 3; align-self:start; font-size:18px; opacity:.9; }
.svTitle { grid-column:2; font-size:12px; color:var(--muted); margin-top:2px; }
.svMain { grid-column:2; font-weight:800; font-size:1.05rem; line-height:1.3; }
.svSub  { grid-column:2; font-size:12px; color:var(--muted); opacity:.9; }

/* Mobile badge variants with icons */
.mobBadge { display:inline-flex; align-items:center; gap:6px; padding:6px 12px; border-radius:999px; border:1px solid var(--border); background: color-mix(in srgb, var(--panel), black 10%); }
.mobBadge.android { background:var(--green-bg); color:var(--green); border-color:transparent; }
.mobBadge.ios { background:var(--blue-bg); color:var(--blue); border-color:transparent; }
.mobBadge i { font-size:14px; line-height:1; }

/* Clickable URL links in module list (neutral gray like file links) */
a.urlLink, a.urlLink:visited { color:#9aa4b2 !important; }
a.urlLink:hover { color:#b8c0cc !important; text-decoration:underline; }

/* Colored status pills */
.pill.ok  { background: var(--ok-bg);  color:#fff; border-color:transparent; }
.pill.bad { background: var(--danger-bg); color:#fff; border-color:transparent; }
.pill.warn { background: var(--warn-bg); color:#fff; border-color:transparent; }
.pill.danger { background: var(--red, #ff4d6d); color:#fff; border-color:transparent; font-weight:700; letter-spacing:.02em; }

/* Better contrast for selected tabs */
.tab.active { background: var(--accent); color:#fff; }
.tab.active .badge { background: rgba(255,255,255,.25); color:#fff; border-color:transparent; }

/* Screen Variables: grouped by type */
.svType,
.svType.input,
.svType.local,
.svType.output,
.svType.aggregate { display:inline-flex; align-items:center; gap:6px; padding:2px 10px; border-radius:999px; border:1px solid var(--border); font-size:12px; line-height:1.6; background: color-mix(in srgb, var(--panel), black 10%); color:var(--text); }
.svType.input     { background:var(--blue-bg);  color:#fff; border-color:transparent; }
.svType.local     { background:var(--gray-bg);  color:#fff; border-color:transparent; }
.svType.output    { background:var(--green-bg); color:#fff; border-color:transparent; }
.svType.aggregate { background:rgba(180, 120, 255, 0.18); color:#fff; border-color:transparent; }
/* Response Headers section */
.hdrCard { display:flex; flex-direction:column; gap:10px; padding:4px 0; }
.hdrTopRow { display:flex; align-items:center; gap:10px; flex-wrap:wrap; }
.hdrSubHead { font-weight:600; color: var(--text); margin-top:6px; font-size:13px; }
.hdrFindings { display:flex; flex-direction:column; gap:10px; }
.hdrFindGroup { border:1px solid var(--border); border-radius:10px; overflow:hidden; }
.hdrFindGroup.sevHigh { border-color: color-mix(in srgb, var(--red), transparent 60%); }
.hdrFindGroup.sevMed  { border-color: color-mix(in srgb, var(--yg, #ffb700), transparent 55%); }
.hdrFindGroup.sevLow  { border-color: color-mix(in srgb, var(--gray, var(--color-text-dim, #8888aa)), transparent 55%); }
.hdrFindGroupHead { display:flex; align-items:center; gap:8px; padding:8px 12px; font-weight:600; font-size:13px; cursor:pointer; list-style:none; }
.hdrFindGroupHead::-webkit-details-marker { display:none; }
.hdrFindGroupHead::before { content:"▸"; display:inline-block; transition: transform .15s ease; opacity:.7; }
.hdrFindGroup[open] > .hdrFindGroupHead::before { transform: rotate(90deg); }
.hdrFindGroup.sevHigh .hdrFindGroupHead { background: var(--red-bg); color: var(--red); }
.hdrFindGroup.sevMed  .hdrFindGroupHead { background: rgba(255,183,0,0.11); color: var(--yg, #ffb700); }
.hdrFindGroup.sevLow  .hdrFindGroupHead { background: var(--gray-bg); color: var(--text); }
.hdrFindGroupIco { opacity:.9; }
.hdrFindGroupLabel { letter-spacing:.3px; }
.hdrFindGroup .pinnedCountPill { margin-left:auto; }
.hdrFindGroupItems { display:flex; flex-direction:column; gap:10px; padding:8px 10px; background: color-mix(in srgb, var(--panel), black 4%); }
.hdrCatGroup { display:flex; flex-direction:column; gap:4px; }
.hdrCatHead { display:flex; align-items:center; gap:8px; padding:2px 4px; }
.hdrCatHead .hdrCat { font-size:11px; color: var(--muted); text-transform:uppercase; letter-spacing:.5px; font-weight:600; }
.hdrCatCount { font-size:11px; color: var(--muted); padding:0 7px; border-radius:999px; background: color-mix(in srgb, var(--panel), black 12%); border:1px solid var(--border); }
.hdrCatItems { display:flex; flex-direction:column; gap:4px; padding-left:8px; border-left:2px solid var(--border); }
.hdrFindItem { display:flex; flex-direction:column; gap:4px; padding:6px 8px; border-radius:6px; background: color-mix(in srgb, var(--panel), black 8%); }
.hdrGuideLink { margin-left:auto; color: var(--muted); text-decoration:none; font-size:14px; opacity:.75; transition: opacity .12s, color .12s; }
.hdrGuideLink:hover { opacity:1; color: var(--accent, #00e5d4); }
.hdrFindHead { display:flex; align-items:center; gap:8px; flex-wrap:wrap; }
.pill.sevLowPill { background: var(--gray-bg); color: var(--text); border-color:transparent; }
.hdrCat { font-size:11px; color: var(--muted); text-transform:uppercase; letter-spacing:.4px; }
.hdrMsg { font-size:13px; }
.hdrEvidence { font-size:11.5px; color: var(--muted); padding:4px 8px; border-left:2px solid var(--border); white-space:pre-wrap; word-break:break-all; max-height:120px; overflow:auto; }
.cookRow { display:flex; align-items:center; gap:10px; padding:6px 0; border-bottom:1px dashed var(--border); flex-wrap:wrap; }
.cookRow:last-child { border-bottom:0; }
.cookName { font-weight:600; }
.cookFlags { display:flex; gap:6px; flex-wrap:wrap; }
.cookFlag { font-size:11px; padding:2px 8px; border-radius:999px; border:1px solid transparent; }
.cookFlag.ok  { background: var(--green-bg); color: var(--green); border-color: color-mix(in srgb, var(--green), transparent 70%); }
.cookFlag.bad { background: var(--red-bg);   color: var(--red);   border-color: color-mix(in srgb, var(--red), transparent 70%); }
.cookDom { font-family: 'Fira Code', ui-monospace, monospace; font-size:11.5px; }
.hdrRawDetails summary { cursor:pointer; padding:8px 0; color: var(--muted); font-size:12px; }
.hdrRaw { display:flex; flex-direction:column; gap:4px; padding-top:6px; }
.hdrRawRow { display:grid; grid-template-columns: minmax(180px, max-content) 1fr; gap:8px; padding:6px 8px; border-radius:6px; background: color-mix(in srgb, var(--panel), black 4%); }
.hdrRawKey { color: var(--accent); font-weight:600; word-break:break-all; }
.hdrRawVal { word-break:break-all; white-space:pre-wrap; }
.svNote { display:flex; align-items:center; gap:6px; padding:6px 10px; margin:0 0 10px; border:1px dashed var(--border); border-radius:8px; background: color-mix(in srgb, var(--panel), black 4%); font-size:12px; }
.svNote i { opacity:.85; }
.svGroup { margin: 6px 0 12px; }
.svGroup + .svGroup { border-top: 1px dashed var(--border); padding-top: 10px; }
.svGroupHead { display:flex; align-items:center; gap:8px; margin-bottom:8px; }
.svGroupHead .small { font-size:12px; }
.svVarChip {
 display:inline-block; padding:4px 10px; border:1px solid var(--border); border-radius:8px;
 background: color-mix(in srgb, var(--panel), black 8%); color: var(--text);
 font-family: 'Fira Code', ui-monospace, monospace; font-size:12px; line-height:1.4;
 white-space: nowrap; overflow:hidden; text-overflow:ellipsis;
}

/* Unified search input styling */
.searchWrap { position:relative; min-width:240px; width:min(420px,100%); }
.searchIcon { position:absolute; left:10px; top:50%; transform:translateY(-50%); pointer-events:none; opacity:.6; font-size:14px; }
.searchInput { width:100%; padding:10px 12px 10px 32px; border:1px solid var(--border); border-radius:10px; background: color-mix(in srgb, var(--panel), white 3%); color:var(--text); outline:none; }
.searchInput::placeholder { color:var(--muted); }
.searchInput:focus { border-color: color-mix(in srgb, var(--accent), white 40%); box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent), transparent 85%); }
/* Data list (two-line rows) */
.dataList { display:block; }
.dataRow { display:grid; grid-template-columns:28px 1fr; gap:10px 12px; padding:10px 0; }
.dataSep { border:0; border-top:1px solid var(--border); margin:0; }
.dataIcon { grid-row:1 / span 2; align-self:start; opacity:.9; }
.dataIcon i { font-size:16px; }
.dataContent { display:block; width:100%; }
.dataTop { display:grid; grid-template-columns:1fr 1fr 1fr; gap:8px 12px; }
.dataField { display:flex; flex-direction:column; gap:4px; }
.dataBottom { display:grid; grid-template-columns:1fr; gap:6px; margin-top:4px; }
.lbl { font-size:12px; color:var(--muted); }
.val { font-weight:600; word-break:break-word; overflow-wrap:anywhere; }
.dataBottom .val { font-weight:400; }

/* Web Blocks list */
.wbHead { display:grid; grid-template-columns:1fr 1fr 1fr; gap:6px 12px; font-weight:700; margin:6px 0; }
.wbList { display:block; }
.wbRow { display:grid; grid-template-columns:1fr 1fr 1fr; gap:6px 12px; padding:6px 0; }
.wbCell.mod strong { font-weight:700; }
.wbSep { border:0; border-top:1px solid var(--border); margin:8px 0; }

/* Section header icons */
.sec-ico { margin-right:8px; opacity:.9; }
.section .head { gap:8px; }
.section .head:hover { background: color-mix(in srgb, var(--panel), black 10%); }
.section .head .title { display:flex; align-items:center; gap:8px; }

/* Counter pill utility */
.pill.secCounter { color:#ffffff !important; background:#334155 !important; border-color:transparent !important; }

/* Brand mappings */
.cardish, .sectionBody, .section, .svCard { background: var(--panel); }

/* Deep-link pulse — applied to a .screenCard for ~2.4s when the
   App Overview page lands here via /report_viewer/{code}#Module__Screen.
   Two layers of glow + a brief border accent so the eye finds the card
   even on a long page. The animation runs once and cleans up via JS. */
.screenCard.vr-deeplink-pulse {
  animation: vrDeepLinkPulse 2.4s ease-out;
  border-radius: 10px;
}
@keyframes vrDeepLinkPulse {
  0%   { box-shadow: 0 0 0 0 rgba(34,245,226,0); }
  20%  { box-shadow: 0 0 0 4px rgba(34,245,226,0.55), 0 0 32px 8px rgba(34,245,226,0.25); }
  100% { box-shadow: 0 0 0 0 rgba(34,245,226,0), 0 0 0 0 rgba(34,245,226,0); }
}

/* Structures cards */
.structCard { border:1px solid var(--border); border-radius:10px; background: color-mix(in srgb,var(--panel), black 6%); padding:.25rem .75rem; }
.structCard summary { display:flex; align-items:center; gap:.5rem; cursor:pointer; padding:.5rem 0; font-weight:600; list-style:none; }
.structCard summary::-webkit-details-marker { display:none; }
.structCard .tableWrap { padding:.5rem 0 .75rem; }
.table-tight { width:100%; border-collapse:collapse; }
.table-tight th,
.table-tight td { padding:.4rem .5rem; border-bottom:1px solid rgba(255,255,255,.06); }
.table-tight thead th { font-size:.85rem; color:var(--muted); text-align:left; }
.robotsTable td { vertical-align: top; }
.robotsTable td ul.list { margin: 0; padding-left: 0; list-style: none; }
.robotsGroupSource { word-break: break-all; }
.pill.tiny { font-size:.7rem; padding:.1rem .45rem; }
.pill-ok { background:var(--ok-bg); color:var(--text); }
.pill-neutral { background:var(--pill); color:var(--text); }
.pill-warn { background: color-mix(in srgb, var(--warn, #ffb454), transparent 70%); color: var(--text); border: 1px solid color-mix(in srgb, var(--warn, #ffb454), transparent 50%); }

/* ── Records Index section ────────────────────────────────────────────
   Sibling to the Structures section above — same data, table view with
   filters + click-through to the structure modal. Reuses .table-tight
   for the core grid; only the row-interaction + filter-bar bits are new. */
.recIdxToolbar {
  display: flex; gap: 12px; align-items: center; flex-wrap: wrap;
  padding: 8px 0 10px;
}
.recIdxToolbar .searchWrap { flex: 1 1 220px; max-width: 320px; }
.recIdxToggle {
  display: inline-flex; align-items: center; gap: 6px;
  color: var(--muted); font-size: .82rem; cursor: pointer; user-select: none;
}
.recIdxToggle input[type="checkbox"] { accent-color: var(--accent, #00e5d4); }
.recIdxCount { margin-left: auto; }

/* Belt-and-braces — even with the layout fix above, a really long row
   (e.g. a structure with a 60-char synthetic anonymous name) should
   scroll inside its own card rather than push the page. */
.recIdxWrap { overflow-x: auto; }
.recIdxTable { table-layout: auto; }
.recIdxTable th.num, .recIdxTable td.num {
  text-align: right; font-variant-numeric: tabular-nums; width: 80px;
}
.recIdxTable td.recIdxAction { text-align: right; width: 28px; color: var(--muted); opacity: .55; }
.recIdxTable .recIdxName { font-weight: 600; }
.recIdxTable .recIdxUsed { color: var(--accent, #22f5e2); font-weight: 600; }

/* Whole row is the click target. Hover surfaces the affordance; arrow
   in the action column brightens too. */
.recIdxRow { cursor: pointer; transition: background .12s; }
.recIdxRow:hover { background: color-mix(in srgb, var(--accent, #22f5e2), transparent 92%); }
.recIdxRow:hover .recIdxAction { opacity: 1; color: var(--accent, #22f5e2); }
.recIdxRow:focus-visible {
  outline: 2px solid var(--accent, #22f5e2); outline-offset: -2px;
}

/* ── Structure resolver modal ─────────────────────────────────────────
   One reused modal element; openStructureModal() pushes a frame, the
   header/breadcrumb + body get re-rendered each push. Wraps the existing
   Bootstrap modal chrome — only the per-modal bits live here. */
.strModal .modal-content { background: var(--panel); border-color: var(--border); }
.strModal .modal-header  { border-color: var(--border); }
.strModalBreadcrumb {
  display: flex; align-items: center; gap: 4px; flex: 1; min-width: 0;
  overflow-x: auto; font-size: .82rem; color: var(--muted);
}
.strModalBreadcrumb .strCrumbItem {
  background: none; border: 0; color: var(--accent, #22f5e2);
  padding: 0; font: inherit; cursor: pointer; text-decoration: none;
  white-space: nowrap; max-width: 200px; overflow: hidden; text-overflow: ellipsis;
}
.strModalBreadcrumb .strCrumbItem:hover { text-decoration: underline; }
.strModalBreadcrumb .strCrumbCurrent {
  color: var(--text); font-weight: 600; white-space: nowrap;
  max-width: 240px; overflow: hidden; text-overflow: ellipsis;
}
.strModalBreadcrumb .strCrumbSep { color: var(--muted); opacity: .6; }

#strModalBack { background: none; border: 0; font-size: 1rem; opacity: .9; }
#strModalBack:hover { opacity: 1; }

.strModalSubhead { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 12px; padding-bottom: 10px; border-bottom: 1px dashed var(--border); }
.strModalName    { font-size: 1rem; font-weight: 600; }
.strModalNoAttrs { padding: 16px; text-align: center; }
.strModalEmpty   { padding: 18px; color: var(--muted); }
.strModalEmpty.strModalMissing { color: var(--text); }
.strModalEmpty i { margin-right: 8px; opacity: .75; }

.strModalUsedAs { margin-top: 16px; padding-top: 12px; border-top: 1px dashed var(--border); }

/* Used-as chips. Dedicated wrapper (NOT .chipWrap) so the action-chip
   grid's ellipsis + nowrap rules don't kick in. flex-wrap so long kind
   labels (e.g. "nestedAttrOf:MyExtraActivityInfo") flow to a new row
   instead of overlapping their neighbours. */
.strUsedAsWrap {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  padding: 4px 0;
  align-items: center;
}
.strUsedAsChip {
  display: inline-flex;
  align-items: stretch;
  border-radius: 6px;
  overflow: hidden;
  border: 1px solid var(--border);
  background: rgba(127,127,127,0.08);
  max-width: 100%;
  font-size: .78rem;
  line-height: 1.4;
}
.strUsedAsName {
  padding: 3px 8px;
  color: var(--text, #e8e8f0);
  font-family: ui-monospace, 'Fira Code', Menlo, Consolas, monospace;
  word-break: break-all;
}
.strUsedAsKind {
  padding: 3px 8px;
  background: rgba(0,0,0,0.18);
  color: var(--muted);
  border-left: 1px solid var(--border);
  font-family: ui-monospace, 'Fira Code', Menlo, Consolas, monospace;
  font-size: .72rem;
  white-space: nowrap;
}
.strUsedAsMore {
  align-self: center;
  padding: 0 8px;
  color: var(--muted);
  font-size: .78rem;
  font-style: italic;
}

/* Clickable-type button — used in three places:
     • action I/O chips (ioChip)
     • screenVar / clientActionVar chips
     • nested-attribute Type cells inside the modal itself
   Looks like a link/button hybrid. Hover surfaces the affordance; the
   trailing arrow icon confirms it's a navigation, not a label. */
.strTypeBtn {
  background: color-mix(in srgb, var(--accent, #22f5e2), transparent 88%);
  border: 1px solid color-mix(in srgb, var(--accent, #22f5e2), transparent 65%);
  color: var(--text);
  padding: 1px 8px;
  border-radius: 6px;
  font: 600 .78rem/1.3 ui-monospace, 'Fira Code', Menlo, Consolas, monospace;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  transition: background .12s, border-color .12s;
}
.strTypeBtn:hover {
  background: color-mix(in srgb, var(--accent, #22f5e2), transparent 78%);
  border-color: var(--accent, #22f5e2);
}
.strTypeBtn i { font-size: 9px; opacity: .7; }
.strTypeBtn:hover i { opacity: 1; }

/* Static Entities chips + Module Client Actions.
   Grid (not flex-wrap) so the chip rhythm is uniform regardless of
   the underlying action name lengths — 88 actions on a single line
   were unreadable as a flex flow. auto-fill + minmax gives a
   responsive column count without media queries. */
.chipWrap {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: .35rem;
  padding: .25rem 0 .5rem;
}
/* One cell per (action + optional suspicious badges). align-items:center
   keeps the badge baseline aligned with the action pill. min-width:0
   lets the pill's text-overflow:ellipsis kick in for long names instead
   of forcing the grid column wider. */
.chipWrap .chipCell {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
}
.chipWrap .chipCell > .pill.soft {
  /* Let the pill fill the cell so the grid stays tidy when names are
     short, but allow ellipsis when they're long. justify-content:
     flex-start so the text doesn't wander to the middle. */
  flex: 1 1 auto;
  min-width: 0;
  justify-content: flex-start;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
/* Quieter chip — drops the bright yellow tint that read as a glow on
   pages with 80+ pills. Neutral muted background blends with the
   surrounding card; the suspicious-badge (warn / danger) still pops
   because it keeps its bright colour. */
.pill.soft {
  background: rgba(127, 127, 127, 0.10);
  color: var(--text, #e8e8f0);
  border: 1px solid var(--border);
  font-weight: 500;
  font-family: ui-monospace, Menlo, Consolas, monospace;
  font-size: 11.5px;
  padding: 4px 10px;
  border-radius: 7px;
  width: 100%;
  transition: background .12s, border-color .12s;
}
.chipWrap .chipCell > .pill.soft:hover {
  background: rgba(127, 127, 127, 0.18);
  border-color: color-mix(in srgb, var(--accent, #00e5d4), transparent 55%);
}
/* When a chip has a warning badge, hint at it on the action pill
   itself — a subtle amber left border. Doesn't reintroduce the glow,
   but makes the at-risk action discoverable in a sea of soft pills. */
.chipWrap .chipCell.has-warning > .pill.soft {
  border-left: 2px solid rgba(255, 183, 0, 0.55);
  padding-left: 5px;
}

/* Roles: auto-fit multi-column grid — keeps long role lists (95+) scannable.
   Columns sized ~150–220px depending on viewport. Chips are compact pill-like tags. */
.rolesGrid {
 display: grid;
 grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
 gap: 6px 10px;
 margin: 0;
 padding: 0;
}
.roleChip {
 display: inline-block;
 padding: 4px 10px;
 border: 1px solid var(--border);
 border-radius: 8px;
 background: color-mix(in srgb, var(--panel), black 8%);
 color: var(--text);
 font-family: 'Fira Code', ui-monospace, monospace;
 font-size: 12px;
 line-height: 1.4;
 white-space: nowrap;
 overflow: hidden;
 text-overflow: ellipsis;
}

/* Clickable URL links (also used elsewhere) */
a.urlLink, a.urlLink:visited { color:#9aa4b2 !important; }
a.urlLink:hover { color:#b8c0cc !important; text-decoration:underline; }


/* === Improved Screen Header Visibility === */
.screenHead {
 background: color-mix(in srgb, var(--panel), black 12%);
 border: 1px solid var(--border);
 border-radius: 10px;
 margin-top: 8px;
 padding: 10px 12px;
 transition: background 0.2s ease, transform 0.1s ease, box-shadow 0.2s ease, border-color 0.2s ease;
}
.screenHead:hover {
 background: color-mix(in srgb, var(--accent), black 30%);
 transform: translateY(-1px);
 box-shadow: 0 0 6px color-mix(in srgb, var(--accent), transparent 70%);
}

/* Chevron indicator on screen header */
.chev {
 display: inline-block;
 width: 10px;
 height: 10px;
 border-right: 2px solid var(--muted);
 border-bottom: 2px solid var(--muted);
 transform: rotate(-45deg);
 transition: transform 0.2s ease, border-color 0.2s ease;
 margin-right: 4px;
 flex-shrink: 0;
}
.screenCard.open .chev {
 transform: rotate(45deg) translate(-2px, -2px);
 border-color: var(--accent);
}

/* Expanded state — keeps the card visually distinct from its neighbours */
.screenCard.open .screenHead {
 background: color-mix(in srgb, var(--accent), black 55%);
 border-color: color-mix(in srgb, var(--accent), transparent 40%);
 border-bottom-left-radius: 0;
 border-bottom-right-radius: 0;
 box-shadow: 0 0 0 1px color-mix(in srgb, var(--accent), transparent 70%) inset;
}
.screenCard.open .screenHead .screenTitle {
 color: var(--accent);
}
.screenCard.open .screenBody {
 border: 1px solid color-mix(in srgb, var(--accent), transparent 40%);
 border-top: none;
 border-bottom-left-radius: 10px;
 border-bottom-right-radius: 10px;
 padding: 10px 12px 12px;
}


/* === Responsive === */
@media (max-width: 900px) {
 .svGrid { grid-template-columns: 1fr; }
 .dataTop { grid-template-columns:1fr; }
}

@media (max-width: 860px) {
 /* Stack the two-column layout */
 .layout { display:flex !important; flex-direction:column !important; gap:12px; }
 .layout.wrap { padding-left:12px; padding-right:12px; }

 /* Put module list above details and keep it handy */
 .layout aside.no-print { order:1; position: static; top: 8px; z-index: 30; }
 #modDetail { order:2; }

 /* Prevent module list from taking the whole viewport */
 aside.no-print #modList { max-height: 45vh; overflow:auto; }

 /* Toolbar compaction */
 .toolbar h1 { font-size: 28px; }
 .toolbar .bar { flex-wrap: wrap; gap: 8px; }
 .toolbar input { min-width: 0; flex: 1 1 100%; }

 /* Tabs wrap when space is tight */
 .tabs { flex-wrap: wrap; }

 /* Tighter section header for small screens */
 .section .head { padding: 10px; }

 /* Key/value table tweaks */
 .kv th { width: 140px; white-space: normal; word-break: break-word; line-height: 1.25; }
 .kv td { width: auto; }

 /* Web Blocks grid collapse */
 .wbHead, .wbRow { grid-template-columns:1fr; }

 /* Server Action List: stacked layout */
 .saList { display:block; }
 .saItem { padding:8px 0; }
 .saTop { display:flex; gap:8px; flex-wrap:wrap; align-items:center; }
 .saSep { opacity:.5; }
 .saBottom { margin-top:2px; }
}

@media (max-width: 420px) {
 .toolbar h1 { font-size: 24px; }
 .kv th { width: 120px; }
 .btn { padding: 6px 10px; }
}

/* Final mobile stack override for grid layout */
@media (max-width: 860px) {
 .layout { display:grid !important; grid-template-columns: 1fr !important; }
 .layout > * { grid-column: 1 / -1 !important; width:100% !important; max-width:100% !important; }
}


/* Mobile-friendly key/value layout */
@media (max-width: 600px) {
 .kv tr {
  display: block;
  margin-bottom: 1rem;
  border: 1px solid var(--border, #2a3440);
  border-radius: 6px;
  padding: 0.5rem;
  background: var(--card, #121a23);
 }

 .kv th {
  display: block;
  width: 100% !important;
  white-space: normal !important;
  font-weight: bold;
  margin-bottom: 0.25rem;
 }

 .kv td {
  display: block;
  width: 100% !important;
 }

 .kv td pre,
 .kv td .mono {
  white-space: normal !important;
  word-break: break-all;
  overflow-wrap: anywhere;
 }
}

/* Size chip for resource bytes */
.sizeChip{
  display:inline-flex; align-items:center; gap:6px;
  margin-left:8px; padding:2px 8px;
  border:1px solid var(--border); border-radius:999px;
  font-size:.85rem; line-height:1.6;
  color:var(--muted); background: color-mix(in srgb, var(--panel), black 6%);
}
.sizeChip .sizeIco{ font-size:.9em; opacity:.9; }

.sizeChip.warn{ background: var(--warn-bg); color:#fff; border-color: transparent; }

/* Suspicious term markers */
.suspiciousHits{ display:inline-flex; flex-wrap:wrap; gap:4px; margin-left:8px; vertical-align:middle; }
.suspiciousHits .pill{ height:20px; min-width:auto; padding:0 7px; font-size:11px; line-height:20px; display:inline-flex; align-items:center; gap:5px; }
.suspiciousHits .badgeGuideLink { color: inherit; opacity: .7; text-decoration: none; line-height: 1; display: inline-flex; align-items: center; }
.suspiciousHits .badgeGuideLink:hover { opacity: 1; }
.suspiciousHits .badgeGuideLink i { font-size: 11px; }
.suspiciousInline{ display:inline-flex; align-items:center; flex-wrap:wrap; gap:6px; }

/* ── Suspicious server files panel ─────────────────────────────────────
   Top-of-report alert card for possible web shells / non-OutSystems
   executable files (.aspx / .php / .jsp / …) detected in the published
   urlVersions map. Built by buildSuspiciousServerFilesPanel() in
   view_report.js. Hidden when nothing matched. Styled to be impossible
   to miss — bold red border + skull icon + danger-pill counts.
   --------------------------------------------------------------------- */
.suspiciousFilesCard {
  background: linear-gradient(135deg, rgba(255, 77, 109, 0.10), rgba(255, 77, 109, 0.04));
  border: 1px solid rgba(255, 77, 109, 0.55);
  border-left: 4px solid var(--danger-bg, #ff4d6d);
  border-radius: 10px;
  padding: 16px 20px;
  margin-bottom: 18px;
}
.suspiciousFilesCard .sfHead {
  display: flex; gap: 14px; align-items: flex-start;
  margin-bottom: 12px;
}
.suspiciousFilesCard .sfHeadIco {
  color: #ff4d6d; font-size: 1.6rem; flex: 0 0 auto; margin-top: 2px;
}
.suspiciousFilesCard .sfHeadText { flex: 1 1 auto; min-width: 0; }
.suspiciousFilesCard .sfTitle {
  font-weight: 700; font-size: 1.05rem; color: #ffd0d8;
  margin-bottom: 4px;
}
.suspiciousFilesCard .sfSub { line-height: 1.45; }
.suspiciousFilesCard .sfCounts {
  flex: 0 0 auto; display: flex; gap: 6px; align-items: flex-start;
}
.suspiciousFilesCard .sfBody {
  display: flex; flex-direction: column; gap: 8px;
}
/* One row per flagged path. The .sfRowMain stays on a single line so
   the path + tier pill scan at a glance; the reasons wrap underneath. */
.suspiciousFilesCard .sfRow {
  background: rgba(0, 0, 0, 0.20);
  border: 1px solid rgba(255, 77, 109, 0.22);
  border-radius: 6px;
  padding: 10px 12px;
}
.suspiciousFilesCard .sfRow.sevHigh {
  border-color: rgba(255, 77, 109, 0.45);
}
.suspiciousFilesCard .sfRowMain {
  display: flex; gap: 10px; align-items: center;
  flex-wrap: wrap;
}
.suspiciousFilesCard .sfPath {
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  color: #ffd0d8; font-size: 0.92rem;
  background: rgba(0, 0, 0, 0.30);
  padding: 3px 8px; border-radius: 4px;
  border: 1px solid rgba(255, 77, 109, 0.22);
  word-break: break-all;
}
.suspiciousFilesCard .sfExt {
  font-family: ui-monospace, monospace;
  font-size: 0.78rem;
  color: #ff8295;
  background: rgba(255, 77, 109, 0.10);
  border: 1px solid rgba(255, 77, 109, 0.30);
  padding: 1px 6px; border-radius: 3px;
  text-transform: lowercase;
}
.suspiciousFilesCard .sfReasons {
  margin: 8px 0 0; padding: 0 0 0 22px;
  color: #e8b5be; font-size: 0.85rem; line-height: 1.45;
}
.suspiciousFilesCard .sfReasons li { margin: 2px 0; }
.suspiciousFilesCard .sfMeta { margin-top: 6px; }
@media (max-width: 640px) {
  .suspiciousFilesCard .sfHead { flex-wrap: wrap; }
  .suspiciousFilesCard .sfCounts { width: 100%; }
}

/* Grouped list (Server/Client/Data action lists) */
.glControls { display:flex; gap:8px; align-items:center; flex-wrap:wrap; }
.glControls .searchWrap { flex:1 1 240px; min-width:200px; }
.glControls .glToggleAll { flex:0 0 auto; display:flex; gap:6px; }
@media (max-width: 600px){
 .glControls .glToggleAll { flex:1 1 100%; justify-content:stretch; }
 .glControls .glToggleAll .btn { flex:1 1 50%; }
}
.glList { display:flex; flex-direction:column; gap:4px; }
.glFlow, .glScreen { border:1px solid var(--border, #2a3440); border-radius:6px; background: color-mix(in srgb, var(--panel, #0b1520), black 3%); }
.glScreen { background: transparent; border:none; border-left:2px solid var(--border, #2a3440); border-radius:0; margin: 2px 0 2px 12px; }
.glHead { display:flex; align-items:center; gap:8px; padding:8px 10px; cursor:pointer; user-select:none; flex-wrap:wrap; }
.glScreenHead { padding:6px 10px; }
.glHead:hover { background: rgba(255,255,255,0.03); }
.glChevron { display:inline-block; font-size:10px; opacity:.65; transition: transform .15s ease; width:10px; text-align:center; }
.glFlow.expanded > .glHead > .glChevron,
.glScreen.expanded > .glHead > .glChevron { transform: rotate(90deg); }
.glBody { display:none; padding: 0 10px 8px; }
.glFlow.expanded > .glBody,
.glScreen.expanded > .glBody { display:block; }
.glCount { margin-left:auto; font-size:12px; opacity:.6; font-variant-numeric: tabular-nums; }
.glScreen .glBody { padding: 0 10px 6px; }
.glScreen .saItem { padding:6px 0; }
.glScreen .saItem + .saItem { border-top:1px solid color-mix(in srgb, var(--border, #2a3440), transparent 60%); }
/* Single-level grouped lists (no screen sub-group) */
.glFlow > .glBody > .saItem { padding:7px 12px; }
.glFlow > .glBody > .saItem + .saItem { border-top:1px solid color-mix(in srgb, var(--border, #2a3440), transparent 60%); }

/* Column layout for short-label grouped lists (e.g. client variables). Columns auto-fit 1 to ~4 based on width. */
.glFlow.expanded > .glCols {
 display: grid;
 grid-template-columns: repeat(auto-fill, minmax(var(--col-min, 200px), 1fr));
 gap: 4px 12px;
 padding: 4px 10px 8px;
}
.glCols > .saItem {
 border-top: none !important;
 padding: 5px 8px;
 min-width: 0;
}
.glCols .saItem code {
 overflow-wrap: anywhere;
 word-break: break-word;
 display: inline-block;
 max-width: 100%;
}
@media (max-width: 600px) {
 .glCols { grid-template-columns: 1fr; }
}
.glFlowName { font-weight:600; font-size:14px; color: var(--text, var(--color-text, #e8e8f0)); letter-spacing:.01em; }
.glScreenName { font-weight:500; font-size:13px; color: var(--muted, #96a0ad); }
.glFlow.expanded > .glHead .glFlowName { color: var(--accent, #00e5d4); }

/* Row layout for saItem top line — flex so separator/name siblings get proper spacing on all widths */
.saItem .saTop { display:flex; flex-wrap:wrap; align-items:center; gap:8px; }
.saItem .saSep { opacity:.55; }

/* --- Translations --- */
.trLangBtns { display: flex; gap: 6px; flex-wrap: wrap; margin: 4px 0; }
.trLangBtn {
 font-size: 11px; font-weight: 600; letter-spacing: .02em;
 padding: 4px 11px; border-radius: 999px;
 border: 1px solid var(--border);
 background: color-mix(in srgb, var(--panel, var(--color-bg-elevated, #16161e)), black 8%);
 color: var(--muted, var(--color-text-dim, #8888aa));
 cursor: pointer;
 transition: background .15s ease, color .15s ease, border-color .15s ease;
 font-family: ui-monospace, Menlo, Consolas, monospace;
}
.trLangBtn:hover { color: var(--text, var(--color-text, #e8e8f0)); border-color: color-mix(in srgb, var(--accent, #00e5d4), transparent 50%); }
.trLangBtn.active {
 background: var(--accent, #00e5d4);
 color: var(--color-bg, #0d0d12);
 border-color: transparent;
}
.trItem { padding: 6px 0; }
.trItem + .trItem { border-top: 1px solid color-mix(in srgb, var(--border, #2a3440), transparent 60%); }
.trTop { display: flex; align-items: flex-start; gap: 8px; flex-wrap: wrap; }
.trToggle {
 background: transparent; border: 1px solid transparent;
 cursor: pointer; padding: 2px 8px;
 color: var(--muted, var(--color-text-dim, #8888aa)); border-radius: 6px;
 flex: 0 0 auto;
 font-size: 11px; line-height: 1;
 transition: color .15s ease, background .15s ease;
}
.trToggle:hover { color: var(--text, var(--color-text, #e8e8f0)); background: color-mix(in srgb, var(--panel, var(--color-bg-elevated, #16161e)), black 12%); }
.trToggle i { transition: transform .15s ease; display: inline-block; }
.trToggle.open i { transform: rotate(90deg); }
.trText { display: none; flex: 1 1 auto; min-width: 0; word-break: break-word; line-height: 1.45; }
.trText.trActive { display: block; }
.trAll {
 margin-top: 8px; margin-left: 30px;
 padding: 6px 12px;
 border-left: 2px solid color-mix(in srgb, var(--border, #2a3440), transparent 30%);
 display: flex; flex-direction: column; gap: 6px;
}
.trLine { display: flex; gap: 10px; align-items: baseline; font-size: 13px; }
.trLine .trLang {
 flex: 0 0 auto;
 font-size: 10px; font-weight: 700; letter-spacing: .06em;
 padding: 1px 7px; border-radius: 999px;
 background: color-mix(in srgb, var(--accent, #00e5d4), black 65%);
 color: var(--accent, #00e5d4);
 border: 1px solid color-mix(in srgb, var(--accent, #00e5d4), transparent 60%);
 font-family: ui-monospace, Menlo, Consolas, monospace;
 min-width: 50px; text-align: center;
}
.trLine .trAllText { color: var(--text, var(--color-text, #e8e8f0)); flex: 1 1 auto; word-break: break-word; }
.trList { display: flex; flex-direction: column; }

/* Pinned "Dangerous Actions" group at the top of the Server Action List */
.glFlow.glDanger {
 border: 1px solid color-mix(in srgb, var(--red, #ff4d6d), transparent 55%);
 background: color-mix(in srgb, var(--red, #ff4d6d), black 82%);
}
.glFlow.glDanger > .glHead { background: color-mix(in srgb, var(--red, #ff4d6d), black 70%); }
.glFlow.glDanger > .glHead:hover { background: color-mix(in srgb, var(--red, #ff4d6d), black 60%); }
.glDangerName { color: var(--red, #ff4d6d) !important; text-transform: uppercase; font-size: 13px; letter-spacing: .06em; }
.glDangerIco { color: var(--red, #ff4d6d); font-size: 13px; }
.glFlow.glDanger.expanded > .glHead .glFlowName { color: var(--red, #ff4d6d) !important; }

/* Pinned "Suspicious Actions" group — amber, sits below the Dangerous group */
.glFlow.glSuspicious {
 border: 1px solid color-mix(in srgb, var(--yg, #ffb700), transparent 60%);
 background: color-mix(in srgb, var(--yg, #ffb700), black 85%);
}
.glFlow.glSuspicious > .glHead { background: color-mix(in srgb, var(--yg, #ffb700), black 75%); }
.glFlow.glSuspicious > .glHead:hover { background: color-mix(in srgb, var(--yg, #ffb700), black 65%); }
.glSuspiciousName { color: var(--yg, #ffb700) !important; text-transform: uppercase; font-size: 13px; letter-spacing: .06em; }
.glSuspiciousIco { color: var(--yg, #ffb700); font-size: 13px; }
.glFlow.glSuspicious.expanded > .glHead .glFlowName { color: var(--yg, #ffb700) !important; }

/* "Marked only" filter toggle + CSS-only hiding when active */
.glMarkFilterBtn.active {
 background: color-mix(in srgb, var(--accent, #00e5d4), black 55%);
 border-color: color-mix(in srgb, var(--accent, #00e5d4), transparent 50%);
 color: var(--accent, #00e5d4);
}
.glList.markFilterActive .glFlow:not(.glDanger):not(.glSuspicious) .saItem:not(:has(.markBadge)) { display: none !important; }
.glList.markFilterActive .glFlow:not(.glDanger):not(.glSuspicious) .glScreen:not(:has(.saItem:has(.markBadge))) { display: none !important; }
.glList.markFilterActive .glFlow:not(.glDanger):not(.glSuspicious):not(:has(.saItem:has(.markBadge))) { display: none !important; }

/* Sidebar module-list counters — per-module unreviewed findings */
.modBtn {
 display: flex; align-items: center; gap: 6px;
 flex-wrap: nowrap; /* pills stay pinned to the right even when the name wraps */
 border-radius: 14px; /* softer corners so multi-line names don't look stretched */
 line-height: 1.25;
}
.modName {
 flex: 1 1 auto;
 min-width: 0;               /* allow the flex child to shrink below content width */
 word-break: break-word;
 overflow-wrap: anywhere;    /* break very long module names anywhere to avoid overflow */
}
.modCountPill {
 display: inline-flex; align-items: center; gap: 3px;
 flex: 0 0 auto;             /* never shrink the counter pill */
 font-size: 10px; font-weight: 700; letter-spacing: .04em;
 padding: 1px 7px; border-radius: 999px;
 border: 1px solid transparent;
 white-space: nowrap;
}
.modCountDanger { background: var(--red, #ff4d6d); color: #fff; }
.modCountWarn   { background: var(--yg,  #ffb700); color: var(--color-bg, #0d0d12); }

/* SVC badge — sidebar chip for backend-only service modules (Python
   scanner's isService flag, surfaced by view_report.js's boot-time
   normalisation). Subtle / cool-toned so it's distinguishable from
   the count pills (warn / danger) which carry actionable signal. */
.modKindBadge {
 display: inline-flex; align-items: center;
 flex: 0 0 auto;
 font-size: 9px; font-weight: 700; letter-spacing: .08em;
 padding: 1px 6px; border-radius: 999px;
 border: 1px solid color-mix(in srgb, var(--accent, #5b9aff), transparent 55%);
 background: color-mix(in srgb, var(--accent, #5b9aff), transparent 82%);
 color: var(--accent, #5b9aff);
 white-space: nowrap;
 text-transform: uppercase;
}

/* Info-link icon inside pinned group headers — opens the security guide in a new tab */
.glGuideLink { display:inline-flex; align-items:center; justify-content:center; text-decoration:none; font-size:13px; opacity:.7; transition: opacity .15s ease, transform .15s ease; }
.glGuideLink:hover { opacity:1; transform: scale(1.1); text-decoration:none; }

/* --- Action marks (fixed / ignored / false_positive) --- */
.markBadge {
 display:inline-flex; align-items:center;
 font-size:10px; font-weight:700; letter-spacing:.06em;
 padding:2px 8px; border-radius:999px;
 border:1px solid transparent;
 text-transform:uppercase;
}
.markBadge-fixed          { background: color-mix(in srgb, var(--green, #00e5a0), transparent 78%); color: var(--green, #00e5a0); border-color: color-mix(in srgb, var(--green, #00e5a0), transparent 55%); }
.markBadge-ignored        { background: color-mix(in srgb, var(--muted, var(--color-text-dim, #8888aa)), transparent 78%); color: var(--muted, var(--color-text-dim, #8888aa)); border-color: color-mix(in srgb, var(--muted, var(--color-text-dim, #8888aa)), transparent 55%); }
.markBadge-false_positive { background: color-mix(in srgb, var(--muted, var(--color-text-dim, #8888aa)), transparent 78%); color: var(--muted, var(--color-text-dim, #8888aa)); border-color: color-mix(in srgb, var(--muted, var(--color-text-dim, #8888aa)), transparent 55%); }

.markWrap { position: relative; display: inline-flex; align-items: center; }
.markBtn {
 background: transparent; border: 1px solid transparent;
 color: var(--muted, var(--color-text-dim, #8888aa));
 border-radius: 6px; padding: 2px 6px;
 cursor: pointer; font-size: 12px;
 opacity: .55; transition: opacity .15s ease, background .15s ease, border-color .15s ease;
}
.markBtn:hover {
 opacity: 1;
 background: color-mix(in srgb, var(--panel, var(--color-bg-elevated, #16161e)), black 10%);
 border-color: var(--border);
 color: var(--text, var(--color-text, #e8e8f0));
}
.markMenu {
 position: fixed;
 z-index: 9999;
 width: 210px;
 background: var(--panel, var(--color-bg-elevated, #16161e));
 border: 1px solid var(--border);
 border-radius: 8px;
 box-shadow: 0 4px 14px rgba(0,0,0,.4);
 display: flex; flex-direction: column;
 padding: 4px;
}
.markMenuItem {
 background: transparent; border: 0;
 color: var(--text, var(--color-text, #e8e8f0));
 text-align: left; cursor: pointer;
 padding: 6px 10px; border-radius: 6px;
 font-size: 13px;
}
.markMenuItem:hover { background: color-mix(in srgb, var(--panel, var(--color-bg-elevated, #16161e)), black 12%); }
.markMenuFixed:hover   { background: color-mix(in srgb, var(--green, #00e5a0), transparent 85%); color: var(--green, #00e5a0); }
.markMenuIgnored:hover { background: color-mix(in srgb, var(--muted, var(--color-text-dim, #8888aa)), transparent 80%); }
.markMenuFp:hover      { background: color-mix(in srgb, var(--muted, var(--color-text-dim, #8888aa)), transparent 80%); }
.markMenuClear { border-top: 1px solid var(--border); margin-top: 2px; padding-top: 8px; color: var(--red, #ff4d6d); }
.markMenuClear:hover { background: color-mix(in srgb, var(--red, #ff4d6d), transparent 85%); }

/* Rule-label chip shown as the sub-group header inside pinned groups */
.pinnedRuleLabel {
 font-size: 11px;
 font-weight: 700;
 letter-spacing: .04em;
 padding: 2px 8px;
 border-radius: 999px;
}

/* Deduped pinned rows: "(N call-sites)" pill + expandable list */
.pinnedCountPill {
 font-size: 11px;
 font-weight: 600;
 color: var(--muted, #96a0ad);
 background: color-mix(in srgb, var(--panel, #0b1520), black 8%);
 border: 1px solid var(--border);
 border-radius: 999px;
 padding: 1px 8px;
}
.pinnedSitesToggle {
 background: transparent;
 border: 1px solid transparent;
 color: var(--muted, var(--color-text-dim, #8888aa));
 border-radius: 6px;
 padding: 2px 6px;
 cursor: pointer;
 font-size: 10px;
 opacity: .6;
 transition: opacity .15s ease, transform .15s ease, background .15s ease;
}
.pinnedSitesToggle:hover { opacity: 1; background: color-mix(in srgb, var(--panel), black 12%); }
.pinnedSitesToggle.open i { transform: rotate(180deg); display: inline-block; }
.pinnedSitesList {
 margin-top: 6px;
 padding: 4px 6px 4px 18px;
 border-left: 1px dashed color-mix(in srgb, var(--border), transparent 30%);
 display: flex; flex-direction: column; gap: 2px;
}
.pinnedSite {
 font-size: 12px;
 display: inline-flex; align-items: center; gap: 4px;
}

/* Bulk-mark button in the sub-group header */
.pinnedBulkBtn {
 background: transparent;
 border: 1px solid transparent;
 color: var(--muted, var(--color-text-dim, #8888aa));
 border-radius: 6px;
 padding: 2px 6px;
 cursor: pointer;
 font-size: 12px;
 opacity: .55;
 transition: opacity .15s ease, background .15s ease, border-color .15s ease;
 margin-left: 4px;
}
.pinnedBulkBtn:hover {
 opacity: 1;
 background: color-mix(in srgb, var(--panel, var(--color-bg-elevated, #16161e)), black 10%);
 border-color: var(--border);
 color: var(--text, var(--color-text, #e8e8f0));
}
.pinnedRuleLabelDanger {
 background: color-mix(in srgb, var(--red, #ff4d6d), transparent 75%);
 color: var(--red, #ff4d6d);
 border: 1px solid color-mix(in srgb, var(--red, #ff4d6d), transparent 60%);
}
.pinnedRuleLabelSusp {
 background: color-mix(in srgb, var(--yg, #ffb700), transparent 78%);
 color: var(--yg, #ffb700);
 border: 1px solid color-mix(in srgb, var(--yg, #ffb700), transparent 60%);
}

/* Screens tab row + flow dropdown */
.scrTabsRow {
 display:flex; align-items:center; gap:12px;
 flex-wrap:wrap; margin: 8px 0;
}
.scrTabsRow .tabs { display:flex; gap:6px; flex-wrap:wrap; flex: 1 1 auto; }
.scrFlowWrap {
 position:relative; flex: 0 0 auto; min-width:200px;
 margin-left:auto;
}
.scrFlowSelect {
 appearance:none; -webkit-appearance:none; -moz-appearance:none;
 width:100%;
 background: color-mix(in srgb, var(--panel), black 8%);
 color: var(--text);
 border: 1px solid var(--border);
 border-radius: 8px;
 padding: 8px 36px 8px 12px;
 font: inherit; font-size: 13px;
 cursor: pointer;
 transition: border-color .15s ease, box-shadow .15s ease, background .15s ease;
}
.scrFlowSelect:hover {
 border-color: color-mix(in srgb, var(--accent), transparent 50%);
 background: color-mix(in srgb, var(--panel), black 4%);
}
.scrFlowSelect:focus {
 outline: none;
 border-color: color-mix(in srgb, var(--accent), white 10%);
 box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent), transparent 80%);
}
.scrFlowSelect option { background: var(--panel); color: var(--text); }
.scrFlowChev {
 position:absolute; right:12px; top:50%;
 width:8px; height:8px; pointer-events:none;
 border-right:2px solid var(--muted);
 border-bottom:2px solid var(--muted);
 transform: translateY(-70%) rotate(45deg);
 transition: border-color .15s ease;
}
.scrFlowSelect:hover + .scrFlowChev,
.scrFlowSelect:focus + .scrFlowChev { border-color: var(--accent); }

@media (max-width: 720px) {
 .scrTabsRow { flex-direction: column; align-items: stretch; }
 .scrFlowWrap { margin-left: 0; width: 100%; }
}

/* Scan-extras chips on the report header — mirrors the dashboard row chips so
   styling stays consistent across views. Same selectors as in app.css. */
.scanExtraChip { display: inline-flex; align-items: center; gap: 4px; padding: 1px 6px; margin-right: 6px; border-radius: 999px; font-size: .65rem; font-weight: 600; line-height: 1.4; vertical-align: middle; border: 1px solid transparent; }
.scanExtraChip.hdr { background: rgba(0, 229, 212, .12); color: #00e5d4; border-color: rgba(0, 229, 212, .35); }
.scanExtraChip.cty { background: rgba(120, 180, 255, .14); color: #9bbcff; border-color: rgba(120, 180, 255, .35); }

/* ── Module dependency map — launch card ─────────────────────────────── */
/* The graph itself moved to /dependencies/{code} (dependencies.php) on   */
/* 2026-05-07 — the inline cytoscape canvas was too heavy for view_report */
/* to carry. What remains here is the small launch card on this page:    */
/* count chips + an Open button. Theme matches the rest of the report —  */
/* cyan accent, dark backgrounds, off-white text.                        */

/* Counts in the section title, inline-prose style ("· N modules with M
   edges"). Reads as secondary text so the section name stays primary. */
.depMapTitleCounts {
  font-weight: 400;
  color: var(--muted, var(--color-text-dim, #8888aa));
  margin-left: 6px;
  font-size: 0.92em;
}

/* Single-row body of the launch card: counts on the left, Open button
   on the right. Wraps on narrow screens. */
.depMapLaunchRow {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 12px;
}
.depMapStats {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}
.depMapStat {
  display: inline-flex;
  align-items: baseline;
  gap: 5px;
  padding: 3px 10px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 500;
  letter-spacing: .02em;
  background: rgba(255,255,255,0.03);
  border: 1px solid rgba(255,255,255,0.08);
  color: var(--muted, var(--color-text-dim, #8888aa));
}
.depMapStat strong { color: var(--text, var(--color-text, #e8e8f0)); font-weight: 700; }
.depMapStatReactive    { border-color: rgba(0,229,212,0.35);  color: #66f0e0; }
.depMapStatTraditional { border-color: rgba(255,183,0,0.35);  color: #ffd47a; }
.depMapStatOffline     { border-color: rgba(255,77,109,0.35); color: #ffa3b1; }

/* Open-dependency-map call-to-action. Pill-shaped accent button — same
   visual weight as the action buttons in the report header so it reads
   as a primary action without dominating the page. */
.depMapLaunchBtn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 7px 16px;
  border-radius: 999px;
  background: rgba(0,229,212,0.14);
  border: 1px solid rgba(0,229,212,0.55);
  color: var(--accent, #00e5d4);
  font-size: 13px;
  font-weight: 600;
  text-decoration: none;
  cursor: pointer;
  transition: background .15s, border-color .15s, color .15s, transform .15s;
}
.depMapLaunchBtn:hover {
  background: rgba(0,229,212,0.22);
  border-color: rgba(0,229,212,0.85);
  color: #ffffff;
  transform: translateY(-1px);
}
.depMapLaunchBtn[aria-disabled="true"] {
  opacity: .5;
  pointer-events: none;
}
.depMapLaunchBtnArrow {
  font-size: 10px;
  opacity: .8;
}
.depMapLaunchHint {
  margin-top: 8px;
  font-size: 11.5px;
  color: var(--muted, var(--color-text-dim, #8888aa));
}


/* ── Per-screen screenshot (inline, inside a collapsible section) ───── */
/* The screenshot is rendered as a normal collapsible section in the
   screen card (matches Screen Variables / Roles / Data / etc). The
   section's slide animation + open/close behavior come from the
   shared section CSS; what's below is just the inner content (loading
   state, meta line, image wrapper, failure state). */

/* The wrapper that holds the inline content. Sits inside the
   section's .body — no separate panel surface needed (the section
   provides one). The initial content is a spinner that gets
   replaced before the slide animation completes; no static "click
   to load" hint (capture is automatic on first expand). */
.scrShotEmbed {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.scrShotMeta {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  font-size: 11px;
}
.scrShotChip {
  display: inline-flex;
  align-items: center;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  border: 1px solid rgba(0,229,212,0.35);
  background: rgba(0,229,212,0.08);
  color: var(--accent, #00e5d4);
}
.scrShotChip_mobile { /* default chip color is fine */ }
.scrShotChip_web {
  border-color: rgba(78,240,168,0.35);
  background: rgba(78,240,168,0.08);
  color: var(--green, #4ef0a8);
}

.scrShotLoading {
  display: flex;
  align-items: center;
  gap: 8px;
  color: var(--muted, var(--color-text-dim, #8888aa));
  font-size: 12px;
  padding: 8px 4px;
}
.scrShotLoading i { color: var(--accent, #00e5d4); }

.scrShotFailure {
  display: flex;
  align-items: center;
  gap: 8px;
  color: var(--red, #ff6d88);
  font-size: 12px;
  padding: 8px 4px;
}
.scrShotFailMsg {
  /* Wrap long Puppeteer/network error strings nicely instead of forcing
     a horizontal scrollbar on the screen card. */
  word-break: break-word;
  overflow-wrap: anywhere;
}

/* Outdated notice — deliberate refusal, not an error. Yellow palette
   distinguishes it from .scrShotFailure (red). One-liner inline form
   because per-screen sections are compact. */
.scrShotOutdated {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  color: var(--yellow, #ffb84d);
  font-size: 12px;
  padding: 8px 4px;
}
.scrShotOutdated i { color: var(--yellow, #ffb84d); }
.scrShotOutdatedMsg {
  color: var(--text, var(--color-text, #e8e8f0));
  word-break: break-word;
  overflow-wrap: anywhere;
}
.scrShotOutdatedCta {
  display: inline-flex; align-items: center; gap: 4px;
  margin-left: 4px;
  color: var(--yellow, #ffb84d);
  text-decoration: underline;
  text-decoration-color: rgba(255,184,77,0.5);
  font-weight: 600;
}
.scrShotOutdatedCta:hover { text-decoration-color: var(--yellow, #ffb84d); }

/* Image wrapper — center the screenshot, cap its rendered size so a
   tall mobile capture (390×844 × deviceScaleFactor=2 = 780×1688 actual
   pixels) doesn't dominate the page. The image keeps its full natural
   resolution; we just limit display size. */
.scrShotImageWrap {
  display: flex;
  justify-content: center;
  align-items: flex-start;
  overflow: hidden;
  border-radius: 8px;
  background: rgba(0,0,0,0.22);
  padding: 8px;
}
.scrShotImage {
  max-width: 100%;
  height: auto;
  width: auto;
  border-radius: 6px;
  box-shadow: 0 4px 14px rgba(0,0,0,0.35);
}
/* Mobile capture — narrow + tall, render at phone-ish dimensions so
   the user perceives it as a phone screen, not a small thumbnail. */
.scrShotImageWrap_mobile .scrShotImage {
  max-height: 560px;
  border-radius: 14px;
  box-shadow: 0 8px 24px rgba(0,0,0,0.45), 0 0 0 1px rgba(255,255,255,0.04);
}
/* Web capture — wide, render full-width. */
.scrShotImageWrap_web .scrShotImage {
  max-height: 480px;
}

/* ── Demo follow-up banner (top of /demo-report/{token}) ──────────────
   Inline expansion (NOT a modal) — banner stays glued to the top of
   the page; expanding doesn't occlude the report below. See
   view_report.js demoFollowUpBannerInit() for the wiring. */
#demoFollowUpBanner {
  background: linear-gradient(135deg, rgba(34,245,226,0.08) 0%, rgba(0,184,168,0.04) 100%);
  border-bottom: 1px solid rgba(34,245,226,0.22);
  color: #e8edf6;
  font-family: "Inter", system-ui, -apple-system, "Segoe UI", sans-serif;
}
#demoFollowUpBanner .dmFuInner {
  max-width: 1100px; margin: 0 auto;
  padding: 16px 24px;
}
#demoFollowUpBanner .dmFuLead {
  display: flex; align-items: center; gap: 14px;
}
#demoFollowUpBanner .dmFuIcon {
  width: 38px; height: 38px; border-radius: 9px;
  background: rgba(34,245,226,0.14);
  border: 1px solid rgba(34,245,226,0.35);
  display: flex; align-items: center; justify-content: center;
  color: #22f5e2; font-size: 1.1rem;
  flex-shrink: 0;
}
#demoFollowUpBanner .dmFuText { flex: 1 1 auto; min-width: 0; }
#demoFollowUpBanner .dmFuTitle {
  font-size: 1rem; font-weight: 700; color: #f0f4ff;
}
#demoFollowUpBanner .dmFuSub {
  font-size: 0.88rem; color: #b8c2d6; margin-top: 2px;
}
#demoFollowUpBanner .dmFuCta {
  background: #22f5e2; color: #0a1224;
  border: 0; border-radius: 8px;
  padding: 9px 18px; font-weight: 700; font-size: 0.92rem;
  cursor: pointer; transition: background 0.12s, transform 0.05s;
  display: inline-flex; align-items: center; gap: 8px;
  flex-shrink: 0;
}
#demoFollowUpBanner .dmFuCta:hover { background: #5cfee9; }
#demoFollowUpBanner .dmFuCta:active { transform: translateY(1px); }
#demoFollowUpBanner .dmFuClose {
  background: transparent; color: #8a99b6; border: 0;
  width: 30px; height: 30px; border-radius: 6px;
  cursor: pointer; flex-shrink: 0;
}
#demoFollowUpBanner .dmFuClose:hover { background: rgba(255,255,255,0.06); color: #e8edf6; }

#demoFollowUpBanner .dmFuForm {
  margin-top: 14px;
  padding-top: 14px;
  border-top: 1px solid rgba(34,245,226,0.18);
  animation: dmFuReveal 0.22s ease-out;
}
#demoFollowUpBanner .dmFuForm[hidden] { display: none; }
@keyframes dmFuReveal {
  from { opacity: 0; transform: translateY(-4px); }
  to   { opacity: 1; transform: translateY(0); }
}
#demoFollowUpBanner .dmFuLabel {
  display: block; font-size: 0.85rem; color: #b8c2d6;
  margin-bottom: 6px; margin-top: 4px;
}
#demoFollowUpBanner .dmFuOpt { color: #8a99b6; font-weight: 400; font-size: 0.78rem; }
#demoFollowUpBanner .dmFuTextarea,
#demoFollowUpBanner .dmFuInput {
  width: 100%; box-sizing: border-box;
  background: rgba(0,0,0,0.25);
  border: 1px solid rgba(255,255,255,0.12);
  border-radius: 6px; color: #e8edf6;
  padding: 10px 12px; font-size: 0.92rem;
  font-family: inherit; resize: vertical;
  margin-bottom: 10px;
}
#demoFollowUpBanner .dmFuTextarea:focus,
#demoFollowUpBanner .dmFuInput:focus {
  outline: none;
  border-color: rgba(34,245,226,0.55);
  background: rgba(34,245,226,0.04);
}
#demoFollowUpBanner .dmFuActions {
  display: flex; justify-content: flex-end; gap: 10px;
  margin-top: 6px;
}
#demoFollowUpBanner .dmFuCancel {
  background: transparent; color: #cfd6e3;
  border: 1px solid rgba(255,255,255,0.18);
  border-radius: 7px; padding: 8px 16px; cursor: pointer;
  font-size: 0.9rem;
}
#demoFollowUpBanner .dmFuCancel:hover { background: rgba(255,255,255,0.05); }
#demoFollowUpBanner .dmFuSubmit {
  background: #22f5e2; color: #0a1224;
  border: 0; border-radius: 7px;
  padding: 8px 20px; font-weight: 700; cursor: pointer;
  font-size: 0.9rem;
}
#demoFollowUpBanner .dmFuSubmit:hover:not(:disabled) { background: #5cfee9; }
#demoFollowUpBanner .dmFuSubmit:disabled { opacity: 0.55; cursor: not-allowed; }
#demoFollowUpBanner .dmFuError {
  margin-top: 8px;
  padding: 8px 12px;
  border-radius: 6px;
  background: rgba(255,77,109,0.12);
  border: 1px solid rgba(255,77,109,0.35);
  color: #ff8295; font-size: 0.85rem;
}

#demoFollowUpBanner .dmFuDone {
  padding: 8px 0;
  color: #cfd6e3; font-size: 0.95rem;
}
#demoFollowUpBanner .dmFuDone i { color: #00e5a0; margin-right: 6px; font-size: 1.05rem; }
#demoFollowUpBanner .dmFuDone strong { color: #f0f4ff; }

@media (max-width: 640px) {
  #demoFollowUpBanner .dmFuLead { flex-wrap: wrap; }
  #demoFollowUpBanner .dmFuCta { width: 100%; justify-content: center; }
  #demoFollowUpBanner .dmFuClose { position: absolute; top: 8px; right: 8px; }
  #demoFollowUpBanner .dmFuInner { position: relative; }
}

/* ── Rule popover (badge "?" click → inline explanation) ──────────────
   See view_report.js's ruleGuidePopoverInit() — replaces the old
   /security-guide#rule-X navigation with an inline popover so demo
   viewers (anonymous) and paid viewers get the same explanation
   without leaving the report. Data emitted as SECURITY_GUIDE_RULES
   in view_report.php. */
#ruleGuidePopover {
  position: absolute;
  z-index: 9999;
  max-width: 380px;
  background: #0b1520;
  border: 1px solid #2a3a52;
  border-radius: 10px;
  box-shadow: 0 16px 40px rgba(0, 0, 0, .55);
  color: #e8edf6;
  font-size: 0.92rem;
  line-height: 1.5;
  padding: 14px 16px 12px;
}
#ruleGuidePopover[hidden] { display: none; }
#ruleGuidePopover .ruleGuideClose {
  position: absolute;
  top: 4px;
  right: 6px;
  width: 26px;
  height: 26px;
  background: transparent;
  color: #8a99b6;
  border: 0;
  font-size: 1.2rem;
  line-height: 1;
  cursor: pointer;
  border-radius: 6px;
  padding: 0;
}
#ruleGuidePopover .ruleGuideClose:hover {
  background: rgba(255, 255, 255, .05);
  color: #e8edf6;
}
#ruleGuidePopover .ruleGuideHeader {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-right: 28px;
  margin-bottom: 4px;
}
#ruleGuidePopover .ruleGuideLabel {
  font-weight: 700;
  font-size: 1rem;
  color: #f0f4ff;
  letter-spacing: 0.02em;
  font-family: "Fira Code", ui-monospace, "SF Mono", Menlo, monospace;
}
#ruleGuidePopover .ruleGuideSeverity {
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  padding: 2px 7px;
  border-radius: 4px;
  text-transform: uppercase;
  background: rgba(255, 255, 255, .06);
  color: #cfd6e3;
}
#ruleGuidePopover .ruleGuideSeverity.sev-danger,
#ruleGuidePopover .ruleGuideSeverity.sev-high {
  background: rgba(255, 77, 109, .15);
  color: #ff8295;
}
#ruleGuidePopover .ruleGuideSeverity.sev-suspicious,
#ruleGuidePopover .ruleGuideSeverity.sev-medium {
  background: rgba(255, 184, 76, .15);
  color: #ffc97a;
}
#ruleGuidePopover .ruleGuideSeverity.sev-low {
  background: rgba(122, 200, 255, .12);
  color: #9cd0ff;
}
#ruleGuidePopover .ruleGuideGroup {
  font-size: 0.78rem;
  color: #8a99b6;
  margin-bottom: 10px;
}
#ruleGuidePopover .ruleGuideBody {
  color: #cfd6e3;
  white-space: pre-wrap;
}
#ruleGuidePopover .ruleGuideFix {
  margin-top: 12px;
  padding-top: 10px;
  border-top: 1px solid #1f2a44;
}
#ruleGuidePopover .ruleGuideFix[hidden] { display: none; }
#ruleGuidePopover .ruleGuideFixTitle {
  font-size: 0.78rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: #22f5e2;
  margin-bottom: 4px;
}
#ruleGuidePopover .ruleGuideFixBody {
  color: #cfd6e3;
  white-space: pre-wrap;
}


/* ── Action→flow modal (report-v2 "Flow" button) ──────────────────── */
.omlFlowModal { display:none; position:fixed; inset:0; z-index:10000; }
.omlFlowModal.open { display:block; }
.omlFlowBackdrop { position:absolute; inset:0; background:rgba(8,10,18,0.72); }
.omlFlowDialog {
 position:absolute; inset:3vh 3vw; background:var(--panel,#14141c);
 border:1px solid var(--border,#2a3440); border-radius:14px;
 box-shadow:0 24px 70px rgba(0,0,0,0.6); display:flex; flex-direction:column; overflow:hidden;
}
.omlFlowHead {
 display:flex; align-items:center; justify-content:space-between; gap:12px;
 padding:12px 18px; border-bottom:1px solid var(--border,#2a3440);
 background:color-mix(in srgb, var(--panel,#14141c), black 10%);
}
.omlFlowTitle { font-weight:700; font-size:14px; font-family:'Fira Code',ui-monospace,monospace; color:var(--text,#e8e8f0); }
.omlFlowClose { background:transparent; border:0; color:var(--muted,#96a0ad); font-size:24px; line-height:1; cursor:pointer; padding:0 6px; }
.omlFlowClose:hover { color:var(--text,#e8e8f0); }
.omlFlowBody { flex:1; overflow:auto; padding:0; min-height:0; }
.omlFlowLoading { padding:60px 20px; text-align:center; color:var(--muted,#96a0ad); font-size:15px; }
.omlFlowLoading i { margin-right:8px; }
.oafErr { padding:30px; color:#ff7a8e; font:14px Inter,sans-serif; }
/* The endpoint returns .oafFlow (canvas + Inputs/Outputs/Locals panel). */
.oafFlow { display:grid; grid-template-columns:1fr 320px; grid-template-rows:100%; gap:0; height:100%; min-height:0; }
.oafFlow.oafFlowNoVars { grid-template-columns:1fr; }
@media (max-width:820px){ .oafFlow { grid-template-columns:1fr; grid-template-rows:1fr auto; } }
/* The canvas cell fills the modal. The .flow-canvas-wrap from flow-diagram.php
   stretches edge-to-edge; the SVG fills the space ABOVE its node-details as a
   FIXED viewport (preserveAspectRatio fits the whole diagram into view, then
   pan/zoom/drag/Fit/Full/PNG — all wired by oml_viewer.js / window.AppScanFlow —
   navigate within it). Do NOT let the SVG grow to content height (height:auto on
   a tall flow makes it enormous with nothing to zoom out from — the old bug). */
.oafFlowCanvas { overflow:hidden; padding:0; min-width:0; min-height:0; display:flex; }
.oafFlowCanvas > .flow-canvas-wrap { flex:1; min-height:0; margin:0; border:0; border-radius:0; display:flex; flex-direction:column; }
.oafFlowCanvas > .flow-canvas-wrap > .flow-canvas { flex:1 1 auto; min-height:0; height:auto; }
.oafFlowCanvas > .flow-canvas-wrap > .flow-node-details { flex:0 0 auto; max-height:38%; overflow:auto; border-radius:0; }
/* Right rail = oml-view's Inputs/Outputs/Locals panel (.vars-panel etc. are
   styled by oml_viewer.css, which report-v2 loads). We only own the rail chrome. */
.oafVars { border-left:1px solid var(--border,#2a3440); padding:16px 18px; overflow:auto; background:color-mix(in srgb, var(--panel,#14141c), black 6%); }
.oafVars .vars-panel { margin-top:0; }
@media (max-width:820px){ .oafVars { border-left:0; border-top:1px solid var(--border,#2a3440); } }

/* "Flow" button on Server/Client Action List rows — right-aligned in the flex
   .saTop row so it doesn't crowd the action name / warning badges. */
.saItem .saTop .saFlowBtn { margin-left:auto; flex:0 0 auto; }
/* Icon-only variant for the dense Module Client Actions chip grid: sits at the
   right edge of each .chipCell without stealing room from the action name. */
.saFlowBtnIcon { flex:0 0 auto; padding:2px 7px; line-height:1; }
.chipWrap .chipCell > .saFlowBtnIcon { margin-left:auto; }
