| /* |
| * Android Platform R8 Configuration Analyzer — dashboard styles |
| * |
| * Organized in the same order as the rendered DOM, top to bottom: |
| * 1. Design tokens (CSS custom properties) |
| * 2. Base resets and element defaults |
| * 3. Header (branding, toolbar, sub-toolbar) |
| * 4. Main layout primitives (stacks, cards) |
| * 5. System view (platform totals, axis panels, offenders, system rules, scoring policy) |
| * 6. View intro (page heading shared by Builds + Rules views) |
| * 7. Builds table (head, rows, expansion) |
| * 8. Rules table |
| * 9. Empty / overflow states |
| * |
| * Naming: BEM-ish — block names use the section prefix (`axis-`, `builds-`, `rules-`, |
| * `sys-rules-`), modifiers use `.active` / `.open`. CSS custom properties live on :root |
| * so theme tweaks happen in one place. |
| */ |
| |
| /* ===== 1. DESIGN TOKENS ===== */ |
| :root { |
| /* Surfaces */ |
| --bg-body: #f8fafc; |
| --bg-card: #ffffff; |
| --bg-subtle: #f9fafb; |
| --bg-hover: #f3f4f6; |
| |
| /* Borders */ |
| --border: #e2e8f0; |
| --border-light: #f1f5f9; |
| --border-interactive: #d1d5db; |
| |
| /* Text */ |
| --text-main: #0f172a; |
| --text-subtle: #475569; |
| --text-muted: #64748b; |
| --text-gray-500: #6b7280; |
| --text-gray-900: #111827; |
| |
| /* Accents */ |
| --link: #2563eb; |
| --link-hover: #1d4ed8; |
| --red: #dc2626; |
| --orange: #c2410c; |
| --yellow: #a16207; |
| --green: #15803d; |
| |
| /* Effects */ |
| --shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05); |
| |
| /* Typography */ |
| --font-base: |
| -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, |
| sans-serif; |
| --font-mono: "SF Mono", Consolas, "Liberation Mono", Menlo, monospace; |
| } |
| |
| /* ===== 2. BASE ===== */ |
| * { |
| box-sizing: border-box; |
| } |
| |
| html, |
| body { |
| margin: 0; |
| padding: 0; |
| } |
| |
| body { |
| font-family: var(--font-base); |
| font-size: 14px; |
| line-height: 1.5; |
| background: var(--bg-body); |
| color: var(--text-main); |
| -webkit-font-smoothing: antialiased; |
| } |
| |
| a { |
| color: var(--link); |
| text-decoration: none; |
| } |
| |
| a:hover { |
| color: var(--link-hover); |
| text-decoration: underline; |
| } |
| |
| button { |
| font-family: inherit; |
| } |
| |
| code { |
| font-family: var(--font-mono); |
| } |
| |
| /* ===== 3. HEADER ===== */ |
| .report-header { |
| background: var(--bg-card); |
| border-bottom: 1px solid var(--border); |
| box-shadow: var(--shadow-sm); |
| z-index: 50; |
| } |
| |
| .header-top-row { |
| align-items: center; |
| border-bottom: 1px solid var(--border-light); |
| display: flex; |
| justify-content: space-between; |
| margin: 0 auto; |
| max-width: 1800px; |
| padding: 0.5rem 1.5rem; |
| } |
| |
| .header-branding { |
| display: flex; |
| flex-direction: column; |
| padding-right: 1rem; |
| } |
| |
| .header-title { |
| color: var(--text-main); |
| font-size: 1.25rem; |
| font-weight: 700; |
| letter-spacing: -0.025em; |
| margin: 0; |
| } |
| |
| .header-subtitle { |
| color: var(--text-subtle); |
| font-size: 0.8125rem; |
| margin-top: 2px; |
| } |
| |
| .header-stats { |
| display: flex; |
| gap: 2rem; |
| } |
| |
| .stat-item { |
| align-items: flex-start; |
| display: flex; |
| flex-direction: column; |
| } |
| |
| .stat-label { |
| color: var(--text-muted); |
| font-size: 0.7rem; |
| font-weight: 500; |
| text-transform: uppercase; |
| letter-spacing: 0.06em; |
| } |
| |
| .stat-value { |
| font-size: 1.05rem; |
| font-weight: 700; |
| font-variant-numeric: tabular-nums; |
| } |
| |
| /* Toolbar: primary view switcher + search */ |
| .header-toolbar { |
| background: var(--bg-card); |
| } |
| |
| .header-toolbar-inner { |
| align-items: center; |
| display: flex; |
| gap: 1rem; |
| height: 46px; |
| justify-content: space-between; |
| margin: 0 auto; |
| max-width: 1800px; |
| padding: 0 1.5rem; |
| width: 100%; |
| } |
| |
| .segmented-control { |
| background: var(--bg-hover); |
| border-radius: 0.375rem; |
| display: flex; |
| padding: 2px; |
| } |
| |
| .segment-btn { |
| align-items: center; |
| background: transparent; |
| border-radius: 0.25rem; |
| border: none; |
| color: var(--text-gray-500); |
| cursor: pointer; |
| display: flex; |
| font-size: 0.8125rem; |
| font-weight: 500; |
| height: 24px; |
| justify-content: center; |
| padding: 0 1rem; |
| transition: all 0.2s ease; |
| } |
| |
| .segment-btn:hover:not(.active) { |
| color: var(--text-gray-900); |
| } |
| |
| .segment-btn.active { |
| background: #ffffff; |
| box-shadow: var(--shadow-sm); |
| color: var(--link); |
| } |
| |
| .segment-count { |
| margin-left: 6px; |
| color: var(--text-muted); |
| font-variant-numeric: tabular-nums; |
| } |
| |
| .search-bar { |
| display: flex; |
| align-items: center; |
| gap: 0.375rem; |
| border-radius: 0.375rem; |
| border: 1px solid var(--border-interactive); |
| background: #ffffff; |
| padding: 0.25rem 0.5rem; |
| transition: all 0.2s; |
| } |
| |
| .search-bar:focus-within { |
| border-color: var(--link); |
| } |
| |
| .search-bar svg { |
| color: var(--text-gray-500); |
| width: 16px; |
| height: 16px; |
| flex-shrink: 0; |
| } |
| |
| .search-bar input { |
| border: none; |
| outline: none; |
| padding: 0.25rem; |
| font-family: inherit; |
| font-size: 0.8125rem; |
| width: 200px; |
| background: transparent; |
| color: var(--text-main); |
| } |
| |
| /* Sub-toolbar: per-view filters (size floor, rule lens, etc.) */ |
| .header-subtoolbar { |
| background: var(--bg-subtle); |
| border-top: 1px solid var(--border-light); |
| } |
| |
| .header-subtoolbar-inner { |
| align-items: center; |
| display: flex; |
| gap: 0.75rem; |
| height: 44px; |
| margin: 0 auto; |
| max-width: 1800px; |
| padding: 0 1.5rem; |
| width: 100%; |
| } |
| |
| .subtoolbar-spacer { |
| flex: 1; |
| } |
| |
| .subtoolbar-label { |
| font-size: 11px; |
| font-weight: 600; |
| text-transform: uppercase; |
| letter-spacing: 0.06em; |
| color: var(--text-muted); |
| } |
| |
| .multi-build-toggle, |
| .toggle-control { |
| display: inline-flex; |
| align-items: center; |
| gap: 6px; |
| font-size: 13px; |
| color: var(--text-subtle); |
| cursor: pointer; |
| user-select: none; |
| margin-left: 8px; |
| } |
| |
| .multi-build-toggle.active, |
| .toggle-control.active { |
| color: var(--text-main); |
| } |
| |
| .multi-build-toggle input, |
| .toggle-control input { |
| cursor: pointer; |
| } |
| |
| .multi-build-toggle .count, |
| .toggle-control .count { |
| color: var(--text-muted); |
| font-variant-numeric: tabular-nums; |
| } |
| |
| /* ===== 4. MAIN LAYOUT ===== */ |
| main { |
| max-width: 1800px; |
| margin: 0 auto; |
| padding: 28px 24px 64px; |
| } |
| |
| .stack { |
| display: flex; |
| flex-direction: column; |
| gap: 20px; |
| } |
| |
| .stack-sm { |
| display: flex; |
| flex-direction: column; |
| gap: 16px; |
| } |
| |
| .card { |
| background: var(--bg-card); |
| border: 1px solid var(--border); |
| border-radius: 12px; |
| overflow: hidden; |
| } |
| |
| .card-row { |
| padding: 12px 24px; |
| display: flex; |
| align-items: baseline; |
| justify-content: space-between; |
| gap: 12px; |
| border-bottom: 1px solid var(--border-light); |
| } |
| |
| .section-label { |
| font-size: 11px; |
| font-weight: 700; |
| text-transform: uppercase; |
| letter-spacing: 0.1em; |
| color: var(--text-muted); |
| } |
| |
| .muted { |
| color: var(--text-muted); |
| font-size: 12px; |
| } |
| |
| /* ===== 5. SYSTEM VIEW ===== */ |
| |
| /* Platform totals — three-up summary at the top of the System page */ |
| .totals-grid { |
| display: grid; |
| grid-template-columns: repeat(3, 1fr); |
| } |
| |
| .total-cell { |
| padding: 20px 24px; |
| } |
| |
| .total-cell + .total-cell { |
| border-left: 1px solid var(--border-light); |
| } |
| |
| .total-label { |
| font-size: 11px; |
| font-weight: 600; |
| color: var(--text-muted); |
| text-transform: uppercase; |
| letter-spacing: 0.08em; |
| } |
| |
| .total-value { |
| margin-top: 8px; |
| font-size: 28px; |
| font-weight: 700; |
| font-variant-numeric: tabular-nums; |
| line-height: 1.1; |
| } |
| |
| .total-sub { |
| margin-top: 4px; |
| font-size: 12px; |
| color: var(--text-subtle); |
| } |
| |
| /* Axis panels — Optimization vs Shrinking, each with classes/methods/fields facets */ |
| .axis-grid { |
| display: grid; |
| grid-template-columns: 1fr 1fr; |
| border-top: 1px solid var(--border-light); |
| } |
| |
| .axis-cell { |
| padding: 20px 24px; |
| } |
| |
| .axis-cell + .axis-cell { |
| border-left: 1px solid var(--border-light); |
| } |
| |
| .axis-header { |
| display: flex; |
| align-items: center; |
| justify-content: space-between; |
| gap: 12px; |
| } |
| |
| .axis-title-block { |
| min-width: 0; |
| } |
| |
| .axis-label { |
| font-size: 12px; |
| font-weight: 600; |
| text-transform: uppercase; |
| letter-spacing: 0.08em; |
| color: var(--text-subtle); |
| } |
| |
| .axis-detail { |
| margin-top: 2px; |
| font-size: 11px; |
| color: var(--text-muted); |
| font-variant-numeric: tabular-nums; |
| } |
| |
| .axis-pct { |
| font-size: 22px; |
| font-weight: 700; |
| font-variant-numeric: tabular-nums; |
| } |
| |
| .facet-rows { |
| margin-top: 14px; |
| display: flex; |
| flex-direction: column; |
| gap: 10px; |
| } |
| |
| .facet-row { |
| display: flex; |
| align-items: center; |
| gap: 12px; |
| } |
| |
| .facet-name { |
| width: 64px; |
| font-size: 12px; |
| color: var(--text-subtle); |
| } |
| |
| .facet-bar { |
| flex: 1; |
| height: 4px; |
| background: var(--border-light); |
| border-radius: 999px; |
| overflow: hidden; |
| } |
| |
| .facet-bar-fill { |
| height: 100%; |
| transition: width 220ms; |
| } |
| |
| .facet-pct { |
| width: 56px; |
| text-align: right; |
| font-size: 12px; |
| font-variant-numeric: tabular-nums; |
| color: var(--text-main); |
| font-weight: 500; |
| } |
| |
| .axis-card-header { |
| padding: 18px 24px 16px; |
| display: flex; |
| align-items: center; |
| justify-content: space-between; |
| } |
| |
| /* Offender cards — paired lists of worst builds per axis */ |
| .offenders-grid, |
| .rules-grid { |
| display: grid; |
| grid-template-columns: 1fr 1fr; |
| gap: 20px; |
| } |
| |
| .offender-head { |
| padding: 16px 20px; |
| display: flex; |
| align-items: center; |
| justify-content: space-between; |
| border-bottom: 1px solid var(--border-light); |
| } |
| |
| .offender-row { |
| padding: 12px 20px; |
| display: flex; |
| align-items: center; |
| justify-content: space-between; |
| gap: 16px; |
| border-bottom: 1px solid var(--border-light); |
| } |
| |
| .offender-row:last-child { |
| border-bottom: none; |
| } |
| |
| .offender-link { |
| font-size: 13px; |
| overflow: hidden; |
| text-overflow: ellipsis; |
| white-space: nowrap; |
| min-width: 0; |
| } |
| |
| .offender-metric { |
| font-size: 13px; |
| font-weight: 600; |
| font-variant-numeric: tabular-nums; |
| white-space: nowrap; |
| } |
| |
| .offender-metric .label { |
| color: var(--text-muted); |
| font-weight: 400; |
| } |
| |
| .link-btn { |
| background: none; |
| border: none; |
| color: var(--link); |
| cursor: pointer; |
| font-family: inherit; |
| font-size: 12px; |
| font-weight: 500; |
| padding: 0; |
| } |
| |
| /* System rules card — global keep rules ranked by impact across builds */ |
| .sys-rules-row { |
| padding: 12px 20px; |
| display: grid; |
| grid-template-columns: 1fr 120px 120px; |
| align-items: center; |
| gap: 16px; |
| border-bottom: 1px solid var(--border-light); |
| } |
| |
| .sys-rules-row:last-child { |
| border-bottom: none; |
| } |
| |
| .sys-rule-src { |
| font-family: var(--font-mono); |
| font-size: 12px; |
| color: var(--red); |
| overflow: hidden; |
| text-overflow: ellipsis; |
| white-space: nowrap; |
| min-width: 0; |
| } |
| |
| .sys-rule-builds { |
| text-align: right; |
| font-size: 12px; |
| color: var(--text-subtle); |
| font-variant-numeric: tabular-nums; |
| } |
| |
| .sys-rule-total { |
| text-align: right; |
| font-size: 13px; |
| font-weight: 600; |
| color: var(--text-main); |
| font-variant-numeric: tabular-nums; |
| } |
| |
| .sys-rule-total .share { |
| color: var(--text-muted); |
| font-weight: 400; |
| } |
| |
| /* Scoring policy — explanatory footer reminding readers what excludes from rankings */ |
| .scoring-policy { |
| background: var(--bg-card); |
| border: 1px solid var(--border); |
| border-radius: 12px; |
| padding: 16px 24px; |
| display: flex; |
| align-items: flex-start; |
| gap: 12px; |
| } |
| |
| .scoring-policy p { |
| margin: 0; |
| font-size: 13px; |
| color: var(--text-subtle); |
| line-height: 1.6; |
| } |
| |
| .scoring-policy strong { |
| color: var(--text-main); |
| font-weight: 500; |
| } |
| |
| .tooltip { |
| display: inline-flex; |
| align-items: center; |
| justify-content: center; |
| width: 18px; |
| height: 18px; |
| border-radius: 999px; |
| border: 1px solid var(--border); |
| color: var(--text-muted); |
| font-size: 11px; |
| font-weight: 600; |
| cursor: help; |
| background: var(--bg-card); |
| flex-shrink: 0; |
| } |
| |
| /* ===== 6. VIEW INTRO ===== */ |
| .view-intro { |
| display: flex; |
| align-items: baseline; |
| gap: 16px; |
| padding: 4px 4px 0; |
| } |
| |
| .view-intro .primary { |
| font-size: 18px; |
| font-weight: 600; |
| color: var(--text-main); |
| } |
| |
| .view-intro .secondary { |
| font-size: 13px; |
| color: var(--text-subtle); |
| } |
| |
| .view-intro strong { |
| color: var(--text-main); |
| } |
| |
| /* ===== 7. BUILDS TABLE ===== */ |
| .builds-head, |
| .builds-row { |
| display: grid; |
| grid-template-columns: 32px minmax(280px, 2fr) 110px 110px 110px 110px 200px; |
| gap: 12px; |
| align-items: center; |
| } |
| |
| .builds-head { |
| padding: 10px 20px; |
| font-size: 11px; |
| font-weight: 600; |
| text-transform: uppercase; |
| letter-spacing: 0.06em; |
| color: var(--text-muted); |
| border-bottom: 1px solid var(--border-light); |
| background: var(--bg-subtle); |
| } |
| |
| .builds-row { |
| padding: 12px 20px; |
| } |
| |
| .builds-row-wrap { |
| border-bottom: 1px solid var(--border-light); |
| } |
| |
| .builds-row-wrap:last-child { |
| border-bottom: none; |
| } |
| |
| /* Sortable column header — shared by builds and rules tables */ |
| .sort-header { |
| background: none; |
| border: none; |
| padding: 0; |
| cursor: pointer; |
| font-family: inherit; |
| font-size: 11px; |
| font-weight: 600; |
| text-transform: uppercase; |
| letter-spacing: 0.06em; |
| color: var(--text-muted); |
| display: flex; |
| align-items: center; |
| gap: 4px; |
| justify-content: flex-end; |
| } |
| |
| .sort-header.left { |
| justify-content: flex-start; |
| text-align: left; |
| } |
| |
| .sort-header.active { |
| color: var(--text-main); |
| } |
| |
| .sort-arrow { |
| font-size: 9px; |
| opacity: 0.3; |
| width: 8px; |
| } |
| |
| .sort-header.active .sort-arrow { |
| opacity: 1; |
| } |
| |
| /* Row chrome: expand caret, build name + meta, numeric cells, severity pills */ |
| .expand-btn { |
| background: none; |
| border: none; |
| cursor: pointer; |
| padding: 0; |
| font-size: 11px; |
| color: var(--text-muted); |
| display: flex; |
| align-items: center; |
| justify-content: center; |
| width: 20px; |
| height: 20px; |
| border-radius: 4px; |
| transition: transform 120ms; |
| } |
| |
| .expand-btn[disabled] { |
| color: var(--border); |
| cursor: default; |
| } |
| |
| .expand-btn.open { |
| transform: rotate(90deg); |
| } |
| |
| .build-name-cell { |
| min-width: 0; |
| } |
| |
| .build-name { |
| display: block; |
| font-size: 13px; |
| font-weight: 500; |
| color: var(--link); |
| overflow: hidden; |
| text-overflow: ellipsis; |
| white-space: nowrap; |
| } |
| |
| .build-meta { |
| margin-top: 2px; |
| font-size: 11px; |
| color: var(--text-muted); |
| font-variant-numeric: tabular-nums; |
| } |
| |
| .num-cell { |
| text-align: right; |
| } |
| |
| .num-cell .value { |
| font-size: 13px; |
| font-weight: 600; |
| color: var(--text-main); |
| font-variant-numeric: tabular-nums; |
| } |
| |
| .num-cell .sub { |
| font-size: 11px; |
| color: var(--text-muted); |
| font-variant-numeric: tabular-nums; |
| } |
| |
| .pills { |
| display: flex; |
| gap: 4px; |
| justify-content: flex-end; |
| flex-wrap: wrap; |
| } |
| |
| .pill { |
| display: inline-flex; |
| align-items: center; |
| gap: 4px; |
| padding: 2px 8px; |
| border-radius: 999px; |
| font-size: 10px; |
| font-weight: 700; |
| letter-spacing: 0.04em; |
| background: var(--bg-subtle); |
| border: 1px solid var(--border); |
| color: var(--text-muted); |
| font-variant-numeric: tabular-nums; |
| } |
| |
| .pill.active { |
| background: #fff; |
| } |
| |
| .pill.opt.active { |
| border-color: var(--orange); |
| color: var(--orange); |
| } |
| |
| .pill.shr.active { |
| border-color: var(--red); |
| color: var(--red); |
| } |
| |
| /* Expansion drawer beneath a build row — shows the rules pinning that build */ |
| .build-expand { |
| padding: 4px 20px 16px 52px; |
| background: var(--bg-subtle); |
| } |
| |
| .build-expand-label { |
| font-size: 10px; |
| font-weight: 600; |
| text-transform: uppercase; |
| letter-spacing: 0.06em; |
| color: var(--text-muted); |
| margin: 6px 0; |
| } |
| |
| .rule-lines { |
| display: flex; |
| flex-direction: column; |
| gap: 4px; |
| } |
| |
| .rule-line { |
| display: flex; |
| align-items: flex-start; |
| gap: 10px; |
| font-size: 12px; |
| } |
| |
| .rule-line .count { |
| display: inline-block; |
| min-width: 64px; |
| padding: 1px 8px; |
| border-radius: 4px; |
| background: var(--bg-subtle); |
| border: 1px solid var(--border-light); |
| text-align: right; |
| color: var(--text-main); |
| font-variant-numeric: tabular-nums; |
| font-weight: 500; |
| flex-shrink: 0; |
| } |
| |
| .rule-line .src { |
| font-family: var(--font-mono); |
| color: var(--red); |
| word-break: break-all; |
| line-height: 1.6; |
| } |
| |
| /* ===== 8. RULES TABLE ===== */ |
| .rules-head, |
| .rules-row { |
| display: grid; |
| grid-template-columns: 44px 1fr 140px 160px; |
| gap: 16px; |
| align-items: center; |
| } |
| |
| .rules-head { |
| padding: 10px 20px; |
| font-size: 11px; |
| font-weight: 600; |
| text-transform: uppercase; |
| letter-spacing: 0.06em; |
| color: var(--text-muted); |
| border-bottom: 1px solid var(--border-light); |
| background: var(--bg-subtle); |
| } |
| |
| .rules-row { |
| padding: 14px 20px; |
| border-bottom: 1px solid var(--border-light); |
| align-items: flex-start; |
| } |
| |
| .rules-row:last-child { |
| border-bottom: none; |
| } |
| |
| .rank-cell { |
| display: flex; |
| align-items: center; |
| justify-content: flex-end; |
| gap: 6px; |
| padding-top: 2px; |
| } |
| |
| .rank-dot { |
| width: 8px; |
| height: 8px; |
| border-radius: 999px; |
| display: inline-block; |
| flex-shrink: 0; |
| } |
| |
| .rank-num { |
| font-size: 12px; |
| color: var(--text-muted); |
| font-variant-numeric: tabular-nums; |
| } |
| |
| .rule-source { |
| font-family: var(--font-mono); |
| font-size: 12px; |
| color: var(--red); |
| word-break: break-all; |
| line-height: 1.6; |
| display: block; |
| } |
| |
| .rule-builds-list { |
| margin-top: 6px; |
| display: flex; |
| flex-wrap: wrap; |
| gap: 4px; |
| } |
| |
| .rule-build-chip { |
| font-size: 11px; |
| padding: 2px 8px; |
| border-radius: 4px; |
| background: #eff6ff; |
| color: var(--link); |
| max-width: 280px; |
| overflow: hidden; |
| text-overflow: ellipsis; |
| white-space: nowrap; |
| } |
| |
| .rule-build-toggle { |
| font-size: 11px; |
| padding: 2px 8px; |
| border-radius: 4px; |
| background: var(--bg-subtle); |
| color: var(--text-subtle); |
| border: none; |
| cursor: pointer; |
| font-family: inherit; |
| } |
| |
| .rule-num-cell { |
| text-align: right; |
| font-size: 13px; |
| color: var(--text-main); |
| font-variant-numeric: tabular-nums; |
| font-weight: 500; |
| } |
| |
| .rule-total-cell { |
| text-align: right; |
| } |
| |
| .rule-total-cell .value { |
| font-size: 13px; |
| font-weight: 600; |
| color: var(--text-main); |
| font-variant-numeric: tabular-nums; |
| } |
| |
| .rule-bar { |
| margin-top: 6px; |
| height: 4px; |
| width: 100%; |
| background: var(--border-light); |
| border-radius: 999px; |
| overflow: hidden; |
| } |
| |
| .rule-bar-fill { |
| height: 100%; |
| background: var(--orange); |
| } |
| |
| /* ===== 9. EMPTY / OVERFLOW ===== */ |
| .rules-overflow { |
| padding: 12px 20px; |
| font-size: 12px; |
| color: var(--text-muted); |
| } |
| |
| .empty { |
| background: var(--bg-card); |
| border: 1px solid var(--border); |
| border-radius: 10px; |
| padding: 48px; |
| text-align: center; |
| color: var(--text-muted); |
| font-size: 13px; |
| } |