code-ranker-viewer 2.0.0

Code Ranker HTML viewer: self-contained interactive report with embedded snapshots.
Documentation
/* export.css: prompt-generator popup, collapsible diff summary — part of the split stylesheet; concatenated in lib.rs in source order to preserve the cascade. */
/* ── Export popup ───────────────────────────────────────────────────────────── */
#export-popup-overlay { position: fixed; inset: 0; z-index: 10001; background: rgba(0,0,0,.45);
                        display: flex; align-items: center; justify-content: center; }
#export-popup { background: #e9edf2; box-shadow: 0 8px 40px rgba(0,0,0,.25);
                display: flex; flex-direction: column; width: 100%; height: 100%; border-radius: 0; }
#export-popup-hdr { display: flex; align-items: center; gap: 10px; padding: 14px 18px 10px;
                    border-bottom: 1px solid #e8edf2; }
#export-popup-hdr h3 { margin: 0; font-size: 15px; font-weight: 700; color: #1a2f45; flex: 1; }
#export-popup-close { border: none; background: none; font-size: 18px; cursor: pointer;
                      color: #888; line-height: 1; padding: 2px 6px; border-radius: 4px; }
#export-popup-close:hover { background: #f0f0f0; }
.exp-modes { display: flex; gap: 0; padding: 10px 18px 6px; align-items: center; flex-wrap: nowrap; }
.exp-cb-group { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; flex: 1; }
.exp-conn-label { font-size: 13px; color: #2c3e50; font-weight: 600; }
.exp-mode-cb { display: flex; align-items: center; gap: 5px; font-size: 13px; color: #2c3e50;
               cursor: pointer; user-select: none; white-space: nowrap; }
.exp-mode-cb input { accent-color: #4d6f9c; width: 14px; height: 14px; cursor: pointer; margin: 0; }
/* A checkbox with nothing under it is disabled (it can't affect the output). */
.exp-mode-cb--off { opacity: .4; cursor: not-allowed; }
.exp-mode-cb--off input { cursor: not-allowed; }
.exp-sel-count, .exp-rec-count { font-weight: 700; color: #4d6f9c; }
/* Recommendation criterion (e.g. `hk > 25,000`) shown next to the count. */
.exp-sort-select { font-size: 13px; font-family: inherit; color: #2c3e50; cursor: pointer;
                   border: 1px solid #c8d4e0; border-radius: 4px; padding: 3px 6px; background: #fff; }
/* Count emphasis: warning zone gets a calm text-colour highlight (no alarming
   red); the info zone is left plain (no class added) to keep the UI low-key. */
.exp-rec-warn { color: #2c3e50; font-weight: 700; background: rgba(44,62,80,.10);
                border-radius: 4px; }
.exp-source-or { font-size: 11px; font-weight: 700; color: #aaa; letter-spacing: .06em;
                 white-space: nowrap; }
.exp-source-group { display: flex; gap: 12px; align-items: center; flex-wrap: nowrap; }
.exp-src-radio { display: flex; align-items: center; gap: 5px; font-size: 13px; color: #2c3e50;
                 cursor: pointer; user-select: none; white-space: nowrap; }
.exp-src-radio input { accent-color: #4d6f9c; cursor: pointer; margin: 0; }
.exp-rec-count { width: 52px; padding: 3px 6px; font-size: 13px; border: none;
                 background: transparent; text-align: center; color: #2c3e50; outline: none; }
.exp-textarea-wrap { position: relative; flex: 1; margin: 0 18px; display: flex;
                     min-height: 0; overflow: hidden; }
/* The raw markdown lives in a hidden textarea (still the Copy source); the user
   sees the snarkdown-rendered preview instead. It is a document, not an input —
   no field border/background, just a scrollable region. */
#export-textarea { display: none; }
/* A lighter (white) document card on the popup's soft-grey background, so the
   rendered markdown reads as a clean page rather than a form field. */
.exp-md-preview { flex: 1; padding: 14px 22px 22px; font-size: 13px; line-height: 1.5;
                  color: #1a2f45; background: #fff; border-radius: 8px;
                  box-shadow: 0 1px 4px rgba(0,0,0,.06); outline: none;
                  min-height: 0; overflow-y: auto; }
.exp-md-preview h1 { font-size: 18px; margin: 12px 0 8px; color: #15324f; }
.exp-md-preview h2 { font-size: 15px; margin: 14px 0 6px; color: #15324f;
                     border-bottom: 1px solid #e4ebf2; padding-bottom: 3px; }
.exp-md-preview p { margin: 6px 0; }
.exp-md-preview ul { margin: 6px 0; padding-left: 20px; }
.exp-md-preview li { margin: 2px 0; }
.exp-md-preview a { color: #2c6fad; text-decoration: none; }
.exp-md-preview a:hover { text-decoration: underline; }
.exp-md-preview code { font-family: ui-monospace,'SF Mono',monospace; font-size: 12px;
                       background: #eef2f7; border: 1px solid #e0e6ee; border-radius: 3px;
                       padding: 1px 4px; color: #b3801f; }
.exp-md-preview strong { color: #15324f; }
.exp-presets { padding: 8px 18px; border-top: 1px solid #edf1f5; }
.exp-presets-label { font-size: 11px; color: #888; text-transform: uppercase;
                     letter-spacing: .05em; margin-bottom: 6px; }
/* Equal-width preset buttons in a grid; cells stretch to equal height so a
   button with a count badge is the same size as one without. */
.exp-preset-btns { display: grid; grid-template-columns: repeat(auto-fit, minmax(70px, 1fr)); gap: 5px; }
.exp-preset-btn { padding: 3px 6px; font-size: 11px; font-family: inherit; border-radius: 4px;
                  border: 1px solid #c8d4e0; background: #f8fafc; color: #2c3e50; cursor: pointer;
                  display: flex; flex-direction: row; align-items: center; gap: 4px; text-align: left; }
.exp-preset-btn:hover { background: #dbe9f4; border-color: #4d6f9c; }
/* Low-sensitivity UI: presets get no button-level emphasis (border/colour) for
   info or warning — only the count badge differs. */
.exp-preset-btn--active { background: #2c6fad; border-color: #2c6fad; color: #fff; }
.exp-preset-btn--active:hover { background: #2259a0; border-color: #2259a0; }
/* Recommendation count badge. `--warn`: a filled pill in the text colour (a calm
   label/background, not red) with a light digit. `--info`: a plain right-aligned
   number — no pill, no highlight. Collapses to nothing when there is no count. */
.exp-preset-count { font-size: 10px; font-weight: 700; line-height: 16px; color: #fff;
                    display: inline-block; min-width: 16px; height: 16px; padding: 0 4px;
                    border-radius: 999px; text-align: center; margin-left: auto; }
.exp-preset-count:empty { display: none; }
.exp-preset-count--warn { background: #2c3e50; }
.exp-preset-count--info { background: none; color: inherit; min-width: 0; height: auto;
                          padding: 0; line-height: inherit; border-radius: 0; }
.exp-copy-btn { position: absolute; bottom: 10px; right: 10px;
                width: 150px; height: 36px; padding: 0;
                font-size: 13px; font-family: inherit; border-radius: 6px;
                border: none; background: #4d6f9c; color: #fff; cursor: pointer;
                box-shadow: 0 2px 8px rgba(0,0,0,.25); opacity: .92;
                display: flex; align-items: center; justify-content: center; gap: 6px; }
.exp-copy-btn:hover { background: #3a5a8a; opacity: 1; }
.exp-copy-icon { font-size: 22px; line-height: 1; }
.node-table-wrap.collapsed .node-table-body { display: none; }
/* Collapsed: show only the title + count, hide the search box + kind filters. */
.node-table-wrap.collapsed .nt-search-input,
.node-table-wrap.collapsed .nt-kind-filters { display: none; }

.node-table-container {
  overflow-x: auto; max-height: 760px; overflow-y: auto;
  border: 1px solid #ddd; border-radius: 6px; background: #fff;
}
.node-table {
  width: 100%; border-collapse: collapse;
  font-size: 12px; font-family: ui-monospace, 'SF Mono', 'Fira Code', monospace;
}
.node-table thead th {
  position: sticky; top: 0; z-index: 1;
  background: #f4f6f8; color: #555; font-weight: 600;
  font-size: 11px; text-transform: uppercase; letter-spacing: .05em;
  padding: 6px 10px; border-bottom: 2px solid #ddd;
  cursor: pointer; user-select: none; white-space: nowrap;
}
.node-table thead th:hover { background: #e8edf2; }
.node-table thead th.sort-asc::after  { content: ''; color: #1abc9c; }
.node-table thead th.sort-desc::after { content: ''; color: #1abc9c; }
.node-table td { padding: 4px 10px; border-bottom: 1px solid #f0f0f0; color: #333; white-space: nowrap; }
.node-table:not(.summary-table) { table-layout: fixed; }
.node-table:not(.summary-table) .nt-sel-th,
.node-table:not(.summary-table) .nt-sel-td { width: 28px; min-width: 28px; max-width: 28px; padding: 0; text-align: center; }
.nt-cb { cursor: pointer; margin: 0; accent-color: #4d6f9c; }
.node-table:not(.summary-table) th[data-col="name"] { width: 420px; }
.node-table:not(.summary-table) th[data-col]:not([data-col="name"]) { width: 54px; }
/* Tighter horizontal padding on the narrow metric columns (the Name column keeps
   the default padding). */
.node-table td[data-col]:not([data-col="name"]),
.node-table th[data-col]:not([data-col="name"]) { padding-left: 5px; padding-right: 5px; }
.node-table td[data-col="name"],
.node-table th[data-col="name"] { position: sticky; left: 0; z-index: 2; overflow: hidden; text-overflow: ellipsis; }
.node-table td[data-col="name"] { background: #fff; }
.node-table th[data-col="name"] { background: #f4f6f8; z-index: 3; }
/* "Too many nodes" guard shown instead of a slow large-graph render. */
.too-many { display: flex; flex-direction: column; align-items: center; justify-content: center;
            gap: 12px; height: 100%; min-height: 240px; text-align: center; color: #5c7a96; }
.too-many-title { font-size: 22px; font-weight: 700; color: #c0392b; font-family: ui-monospace,'SF Mono',monospace; }
.too-many-sub { font-size: 13px; color: #7a92a8; max-width: 360px; }
.too-many-btn { padding: 8px 18px; font-size: 13px; font-weight: 600; cursor: pointer;
                background: #4d6f9c; color: #fff; border: none; border-radius: 6px; }
.too-many-btn:hover { background: #3d5a82; }

.node-table tr:last-child td { border-bottom: none; }
/* Summary footer row: averages (numeric) / counts (text), pinned visual weight. */
.node-table tr.nt-foot td { border-top: 2px solid #ddd; font-weight: 600; background: #eef1f4; color: #2c3e50; }
.node-table tr.nt-foot td[data-col="name"] { background: #eef1f4; }
.node-table tr.nt-foot:hover td { background: #eef1f4; }
.node-table tr:hover td { background: transparent; }
.node-table .num { text-align: right; }
.node-table thead th.num { text-align: right; }


.cell-s-added     { color: #2a7a30; font-weight: 600; }
.cell-s-removed   { color: #b45309; font-weight: 600; }
.cell-s-affected  { color: #6b7280; }
.cell-s-unchanged { color: #aaa; }

.node-table td.nt-empty { text-align: center; color: #aaa; font-style: italic; padding: 16px; }

/* ── Diff summary popup (full-screen overlay) ───────────────────────────────── */
/* Matches the snapshot `toggle` control (.meta-mode) — same grey-blue chrome,
   deliberately not the accent green. */
.header-stats-btn { font: inherit; font-size: 13px; color: #ecf0f1;
                    white-space: nowrap; background: #455a73;
                    border: 0; border-radius: 4px; padding: 6px 14px; cursor: pointer;
                    transition: background .15s; }
.header-stats-btn:hover { background: #5d7593; }

/* Full-screen WHITE fill (the page header stays visible above it — its top offset
   is set in JS). The popup itself is content-width and vertically centred. */
#summary-overlay { position: fixed; inset: 0; z-index: 9000; background: #fff;
                   display: flex; align-items: center; justify-content: center;
                   overflow: auto; padding: 24px; box-sizing: border-box; }
#summary-popup { background: #fff; max-width: 95vw; max-height: 100%;
                 display: flex; flex-direction: column; overflow: hidden;
                 border: 1px solid #d0d8e4; border-radius: 8px;
                 box-shadow: 0 10px 40px rgba(20, 30, 42, .18); }
/* Header is a flex row: title, the stat radio, the export actions, then close. */
#summary-header { display: flex; align-items: center; gap: 12px; flex-shrink: 0;
                  padding: 14px 28px 12px; margin: 0; cursor: default; user-select: none;
                  border-bottom: 2px solid #1abc9c; font-size: 1.4rem; font-weight: 700;
                  color: #2c3e50; }
#summary-title { order: 0; }
/* Export controls in the header: small grey-blue icon buttons grouped per
   format (download + copy), pushed right next to the close button. The header
   sets a large bold font for the title — reset it here for the controls. */
.summary-exports { margin-left: auto; display: flex; align-items: center; gap: 18px;
                   font-size: 13px; font-weight: 400; }
.summary-export-grp { display: flex; align-items: center; gap: 5px; }
.summary-fl { color: #5c7a96; font-weight: 600; margin-right: 3px; }
.summary-ibtn { display: inline-flex; align-items: center; justify-content: center;
                width: 30px; height: 28px; padding: 0; color: #2c3e50; background: #eef2f6;
                border: 1px solid #c8d4e0; border-radius: 4px; cursor: pointer;
                transition: background .15s, color .15s, border-color .15s; }
.summary-ibtn:hover { background: #dfe7ef; }
.summary-ibtn.copied { color: #1abc9c; border-color: #1abc9c; background: #eafaf6; }
#summary-close { background: none; border: none;
                 font-size: 22px; color: #aaa; cursor: pointer; line-height: 1; padding: 0; }
#summary-close:hover { color: #333; }
#summary-body { flex: 1; overflow: auto; padding: 16px 28px 28px; }

/* Per-stat radio control — rendered as a full-width divider row in the table,
   between the "sum always" counts and the metric sections it drives. */
.summary-stat { display: inline-flex; gap: 16px; align-items: center; font-size: 12px; font-weight: 400; }
.summary-stat-opt { display: inline-flex; align-items: center; gap: 3px; cursor: pointer; color: #5c7a96; }
.summary-stat-opt input { cursor: pointer; margin: 0; }