/* Design tokens for the public CVD site. These mirror
* red.anthropic.com so the disclosure pages read as a native section
* of that site. No rounded corners, no box shadows, and no transitions
* are used anywhere; engagement is delivered through the figures, not
* the chrome. */
:root {
--bg: #fff;
--fg: rgba(0, 0, 0, 0.8);
--fg-bright: #000;
--fg-muted: rgba(0, 0, 0, 0.6);
--fg-kicker: rgba(0, 0, 0, 0.65);
--hairline: rgba(0, 0, 0, 0.1);
--hairline-faint: rgba(0, 0, 0, 0.05);
--stroke-strong: #000;
--divider: #d8d8d8;
--surface-note: #f9f8f8;
--surface-paper: #ebdccc;
--accent: #ff0000;
--link: #004276;
--sev-critical: #cc0000;
--sev-high: #e66e3c;
--sev-medium: #f0a878;
--sev-low: #f5d3b8;
/* Darker text-only variants of the severity ramp. The fill tokens
* above are tuned for area-chart bands and badges and do not meet the
* 4.5:1 WCAG AA text-contrast threshold on the light background; the
* ``-text`` tokens are used for ``color`` only so the inline severity
* labels in tables and identifier cards remain readable. */
--sev-critical-text: #cc0000;
--sev-high-text: #a13816;
--sev-medium-text: #9e4f25;
--sev-low-text: #8a5530;
--diff-add: #1a7f37;
/* Headline-flowchart tokens. The firm-reviewed branch reuses the
* high-severity orange so the diagram reads in the existing palette;
* the direct-disclosure branch is the only blue on the page so the
* two streams are distinguishable at a glance. */
--flow-line: rgba(0, 0, 0, 0.4);
--flow-firm-line: #e66e3c;
--flow-firm-fill: rgba(230, 110, 60, 0.07);
--flow-direct-line: #4a7dbd;
--flow-direct-fill: rgba(74, 125, 189, 0.09);
}
/* Dark-mode token overrides. The attribute selector lets the preview
* iframe force a theme via ?theme= without depending on the system
* preference; an explicit data-theme="light" opts out of the media
* query so the system preference can be overridden in both
* directions. The token block is duplicated because plain CSS has no
* mixin facility. */
:root[data-theme="dark"] {
--bg: #1a1a1a;
--fg: rgba(255, 255, 255, 0.86);
--fg-bright: #ededed;
--fg-muted: rgba(255, 255, 255, 0.6);
--fg-kicker: rgba(255, 255, 255, 0.5);
--hairline: rgba(255, 255, 255, 0.14);
--hairline-faint: rgba(255, 255, 255, 0.07);
--stroke-strong: #ededed;
--divider: #3a3a3a;
--surface-note: #232323;
--surface-paper: #2b241d;
--link: #7fb6e0;
--sev-critical-text: #ff5c5c;
--sev-high-text: #e66e3c;
--sev-medium-text: #f0a878;
--sev-low-text: #f5d3b8;
--diff-add: #3fb950;
--flow-line: rgba(255, 255, 255, 0.45);
--flow-firm-fill: rgba(230, 110, 60, 0.14);
--flow-direct-line: #7fb6e0;
--flow-direct-fill: rgba(127, 182, 224, 0.14);
}
@media (prefers-color-scheme: dark) {
:root:not([data-theme="light"]) {
--bg: #1a1a1a;
--fg: rgba(255, 255, 255, 0.86);
--fg-bright: #ededed;
--fg-muted: rgba(255, 255, 255, 0.6);
--fg-kicker: rgba(255, 255, 255, 0.5);
--hairline: rgba(255, 255, 255, 0.14);
--hairline-faint: rgba(255, 255, 255, 0.07);
--stroke-strong: #ededed;
--divider: #3a3a3a;
--surface-note: #232323;
--surface-paper: #2b241d;
--link: #7fb6e0;
--sev-critical-text: #ff5c5c;
--sev-high-text: #e66e3c;
--sev-medium-text: #f0a878;
--sev-low-text: #f5d3b8;
--diff-add: #3fb950;
--flow-line: rgba(255, 255, 255, 0.45);
--flow-firm-fill: rgba(230, 110, 60, 0.14);
--flow-direct-line: #7fb6e0;
--flow-direct-fill: rgba(127, 182, 224, 0.14);
}
}
/* Distill-style named grid. Prose sits in the ``text`` track and
* figures break out to the slightly wider ``page`` track so a chart
* can use more horizontal room while its left edge stays aligned with
* the text gutter. */
body {
font-family:
-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans",
"Helvetica Neue", Arial, sans-serif;
display: grid;
grid-template-columns:
[screen-start] 1fr [page-start text-start] minmax(0, 700px)
[text-end] minmax(0, 160px) [page-end] 1fr [screen-end];
margin: 100px 0;
color: var(--fg);
background: var(--bg);
line-height: 1.6;
font-size: 16px;
}
body > * {
grid-column: text;
}
/* The ```` and ```` landmarks wrap the page content for
* assistive technology; ``display: contents`` promotes their children
* to grid items of ``body``. Selector matching operates on the DOM
* tree rather than the box tree, so the children also need an explicit
* ``grid-column`` placement because ``body > *`` does not reach them. */
main,
aside {
display: contents;
}
main > *,
aside > * {
grid-column: text;
}
.figure {
grid-column: text;
}
@media (max-width: 768px) {
body {
display: block;
padding: 0 16px;
margin: 40px 0;
}
.ledger th:nth-child(n + 5),
.ledger td:nth-child(n + 5) {
display: none;
}
}
@media (min-width: 1024px) {
body {
grid-template-columns:
[screen-start] 1fr [page-start] minmax(0, 80px)
[text-start] minmax(0, 700px) [text-end] minmax(0, 80px)
[page-end] 1fr [screen-end];
}
}
h1,
h2,
h3 {
color: var(--fg-bright);
}
h1 {
font-size: 42px;
font-weight: 700;
margin-top: 0;
}
h1 .red {
color: var(--accent);
}
h2 {
font-size: 28px;
font-weight: 600;
border-bottom: 1px solid var(--hairline);
padding-bottom: 1rem;
margin-top: 80px;
}
/* The Subscribe heading is an ```` so the heading order is
* contiguous after the page ````; the visual size matches the
* previous ```` so the layout is unchanged. */
aside > h2 {
font-size: 1.17em;
border-bottom: none;
padding-bottom: 0;
margin-top: 0;
}
a {
color: var(--link);
}
.marker {
font-size: 13px;
font-weight: 700;
color: var(--fg-bright);
border-bottom: 1px solid var(--fg-bright);
display: inline-block;
margin-top: 60px;
}
.section-intro {
color: var(--fg-muted);
font-size: 15px;
margin: 12px 0 24px;
max-width: 640px;
}
.about-section {
max-width: none;
color: var(--fg);
font-size: 16px;
}
.about-section p {
max-width: 640px;
}
.about-section table th:first-child {
white-space: nowrap;
}
.site-nav {
font-size: 13px;
margin: 8px 0 24px;
display: flex;
align-items: center;
gap: 8px;
}
.site-nav a {
color: var(--link);
}
.theme-toggle {
margin-left: auto;
display: inline-flex;
gap: 4px;
}
.theme-toggle button {
font-family: inherit;
font-size: 12px;
padding: 2px 8px;
background: var(--bg);
color: var(--fg-muted);
border: 1px solid var(--hairline);
cursor: pointer;
}
.theme-toggle button.is-active {
color: var(--fg-bright);
border-color: var(--stroke-strong);
}
.last-updated {
margin: 0 0 24px;
}
.filters {
display: flex;
flex-direction: column;
gap: 12px;
margin: 24px 0;
padding: 12px 14px;
background: var(--surface-note);
border-bottom: 1px solid var(--divider);
font-size: 13px;
}
.filter-row {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 8px;
}
.filters-label {
color: var(--fg-muted);
font-size: 12px;
text-transform: uppercase;
letter-spacing: 0.5px;
margin-left: 8px;
}
.filters-label:first-child {
margin-left: 0;
}
.filter-chip,
.filter-reset {
font-family: inherit;
font-size: 13px;
padding: 4px 10px;
background: var(--bg);
color: var(--fg-muted);
border: 1px solid var(--hairline);
cursor: pointer;
}
.filter-chip.is-on {
color: var(--fg-bright);
border-color: var(--stroke-strong);
}
.filters input[type="date"] {
font-family: inherit;
font-size: 13px;
padding: 4px 6px;
background: var(--bg);
color: var(--fg);
border: 1px solid var(--hairline);
}
.filter-note {
font-family: inherit;
font-size: 12px;
font-weight: 400;
text-transform: none;
color: var(--fg-muted);
margin-left: 12px;
}
.model-chip,
.verdict-chip,
.sev-chip {
display: inline-block;
padding: 2px 8px;
background: var(--surface-note);
border: 1px solid var(--hairline);
font-size: 13px;
margin-right: 6px;
}
.sev-chip {
margin-right: 0;
border-color: currentColor;
}
.verdict-tp {
color: var(--diff-add);
}
.verdict-fp {
color: var(--sev-critical-text);
}
.verdict-dup {
color: var(--fg-muted);
}
.verdict-wont_fix {
color: #9a6700;
}
.verdict-more_info {
color: var(--link);
}
.id-record-list {
margin: 16px 0;
}
.archive-list {
list-style: none;
padding: 0;
margin: 16px 0;
}
.archive-list li {
margin: 0 0 8px;
}
.archive-list .card {
display: block;
}
.id-record {
display: block;
margin-bottom: 1px;
}
.id-record-id {
font-family: ui-monospace, "SF Mono", Menlo, monospace;
font-size: 14px;
font-weight: 600;
}
.id-record-meta {
display: block;
font-size: 13px;
color: var(--fg-muted);
margin-top: 2px;
}
.id-record-title {
display: block;
font-size: 13px;
margin-top: 4px;
}
/* Pager row that follows an id-record-list. The ledger dashboard scopes
* its own pager under ``.ledger-dash`` so the rules here cover the CVE
* and GHSA card lists, which sit directly under the page main and have
* no such ancestor. */
.id-record-list + .pager {
display: flex;
align-items: center;
justify-content: center;
gap: 12px;
padding: 12px 0;
border-top: 1px solid var(--hairline);
}
.id-record-list + .pager .id-record-page {
color: var(--fg-muted);
font-size: 12px;
}
.id-record-list + .pager button {
background: transparent;
border: 1px solid var(--hairline);
color: var(--fg);
padding: 6px 14px;
cursor: pointer;
font-size: 12px;
font-family: inherit;
}
.id-record-list + .pager button:disabled {
opacity: 0.35;
cursor: default;
}
.id-record-list + .pager button:not(:disabled):hover {
border-color: var(--link);
color: var(--link);
}
.kicker {
color: var(--fg-kicker);
font-size: 14px;
}
.card {
background: var(--surface-note);
padding: 14px 16px;
border-bottom: 1px solid var(--divider);
text-decoration: none;
color: var(--fg-bright);
}
.card:hover {
padding-left: 14px;
border-left: 2px solid var(--stroke-strong);
}
.cards {
margin: 24px 0;
}
.card-row {
display: grid;
grid-template-columns: repeat(5, 1fr);
gap: 12px;
grid-column: text;
margin: 24px 0;
}
.card-row > .card {
min-width: 0;
}
/* The headline flowchart. A seven-column grid interleaves four box
* tracks with three fixed-width connector tracks so every connector is
* anchored to the boxes it joins rather than to pixel positions; the
* column-centre offsets used by the convergence connectors are derived
* from the same 26px connector-track width, so the lines stay attached
* at every container width. The firm-reviewed branch and the
* direct-disclosure branch fork out of the candidate box and re-join
* above the bottom row, where the two streams sum to the total
* reported figure. */
#stat-flow {
grid-column: text;
margin: 24px 0;
display: grid;
grid-template-columns:
minmax(0, 1fr) 26px minmax(0, 1fr) 26px minmax(0, 1fr) 26px
minmax(0, 1fr);
grid-template-rows: auto auto 16px auto 40px auto auto auto;
}
.flow-box {
display: block;
border: 1.5px solid var(--divider);
background: var(--surface-note);
padding: 9px 10px;
text-align: center;
text-decoration: none;
color: var(--fg-bright);
min-width: 0;
}
.flow-box .n {
display: block;
font-size: 17px;
font-weight: 700;
}
.flow-box .l {
display: block;
font-size: 11.5px;
line-height: 1.45;
color: var(--fg-muted);
margin-top: 2px;
}
.flow-box .sub {
display: block;
font-size: 10.5px;
font-style: italic;
color: var(--fg-kicker);
margin-top: 2px;
}
.flow-firm {
border-color: var(--flow-firm-line);
background: var(--flow-firm-fill);
}
.flow-direct {
border-color: var(--flow-direct-line);
background: var(--flow-direct-fill);
}
/* The active severity selection, stated once at the top-left of the
* diagram and rewritten by ``figures.js`` when the filter changes. It
* shares the first grid row with the stage labels: the label hugs the
* top edge and the stage labels carry enough top padding to clear its
* single line, so the two never overlap without reserving a dedicated
* track. The styling mirrors the counts-as-of caption at the
* bottom-right. */
.flow-scope {
grid-column: 1 / -1;
grid-row: 1;
align-self: start;
text-align: left;
font-size: 11px;
color: var(--fg-muted);
margin-bottom: 12px;
}
.flow-stage {
font-size: 11px;
font-weight: 600;
letter-spacing: 0.08em;
text-transform: uppercase;
text-align: center;
color: var(--fg-muted);
opacity: 0.65;
grid-row: 1;
align-self: end;
padding: 28px 0 8px;
}
.flow-stage-discovered {
grid-column: 1;
}
.flow-stage-triaged {
grid-column: 3 / span 5;
}
.flow-stage-disclosed,
.flow-stage-remediated {
grid-row: 6;
align-self: end;
padding: 10px 0 8px;
}
.flow-stage-disclosed {
grid-column: 1 / span 3;
}
.flow-stage-remediated {
grid-column: 5 / span 3;
}
.flow-pos-candidate {
grid-column: 1;
grid-row: 2 / span 3;
align-self: center;
}
.flow-pos-triaged {
grid-column: 3;
grid-row: 2;
}
.flow-pos-verified {
grid-column: 5;
grid-row: 2;
}
.flow-pos-confirmed {
grid-column: 7;
grid-row: 2;
}
.flow-pos-direct {
grid-column: 3 / span 3;
grid-row: 4;
}
.flow-no-firm .flow-pos-direct {
grid-row: 2;
}
.flow-pos-disclosed {
grid-column: 1;
grid-row: 7;
}
.flow-pos-acked {
grid-column: 3;
grid-row: 7;
}
.flow-pos-patched {
grid-column: 5;
grid-row: 7;
}
.flow-pos-advisories {
grid-column: 7;
grid-row: 7;
}
/* Horizontal connector: a centred rule with a right-pointing head. */
.flow-arrow {
position: relative;
align-self: center;
height: 9px;
}
.flow-arrow::before {
content: "";
position: absolute;
left: 0;
right: 5px;
top: 4px;
border-top: 1.5px solid var(--flow-line);
}
.flow-arrow::after {
content: "";
position: absolute;
right: 0;
top: 0;
width: 0;
height: 0;
border: 4.5px solid transparent;
border-right-width: 0;
border-left: 6px solid var(--flow-line);
}
.flow-arrow-firm::before {
border-top-color: var(--flow-firm-line);
}
.flow-arrow-firm::after {
border-left-color: var(--flow-firm-line);
}
.flow-pos-arrow-tv {
grid-column: 4;
grid-row: 2;
}
.flow-pos-arrow-vc {
grid-column: 6;
grid-row: 2;
}
.flow-pos-arrow-da {
grid-column: 2;
grid-row: 7;
}
.flow-pos-arrow-ap {
grid-column: 4;
grid-row: 7;
}
.flow-pos-arrow-pa {
grid-column: 6;
grid-row: 7;
}
/* The fork out of the candidate box. The two halves occupy the
* connector track beside the firm row and the direct row and extend
* 8px into the 16px spacer row between them, so their vertical
* segments meet at the candidate box's right edge. */
.flow-fork {
position: relative;
grid-column: 2;
}
.flow-fork-up {
grid-row: 2;
}
.flow-fork-down {
grid-row: 4;
}
.flow-no-firm .flow-fork-down {
grid-row: 2;
}
.flow-fork-up::before {
content: "";
position: absolute;
left: 0;
right: 5px;
top: 50%;
bottom: -8px;
border-left: 1.5px solid var(--flow-firm-line);
border-top: 1.5px solid var(--flow-firm-line);
}
.flow-fork-down::before {
content: "";
position: absolute;
left: 0;
right: 5px;
top: -8px;
bottom: 50%;
border-left: 1.5px solid var(--flow-direct-line);
border-bottom: 1.5px solid var(--flow-direct-line);
}
.flow-no-firm .flow-fork-down::before {
top: 50%;
bottom: auto;
height: 0;
border-left: none;
border-bottom: none;
border-top: 1.5px solid var(--flow-direct-line);
}
.flow-fork::after {
content: "";
position: absolute;
right: 0;
top: calc(50% - 4.5px);
width: 0;
height: 0;
border: 4.5px solid transparent;
border-right-width: 0;
border-left: 6px solid var(--flow-firm-line);
}
.flow-fork-down::after {
border-left-color: var(--flow-direct-line);
}
/* The firm branch's return path. A single full-width overlay spans
* from the bottom edge of the reported-to-maintainers box down to the
* top edge of the bottom row, and one child element draws the descent
* and the leftward run as the right and bottom borders of the same
* box, so the corner between them is mitred by the renderer and the
* two segments cannot land on different device pixels. The drop into
* the total-reported box reuses the same left expression as that box,
* so the second corner is exact for the same reason. The column-centre
* offsets mirror the grid-template-columns expression above; the
* descent's right edge sits half a stroke beyond the seventh column's
* centre so the 1.5px stroke is centred on the column like every
* other connector. */
.flow-drop {
grid-column: 1 / -1;
grid-row: 3 / span 4;
position: relative;
pointer-events: none;
}
.flow-drop > span {
position: absolute;
}
/* The convergence band. Both branches turn toward the first column's
* centre and drop side by side into the total-reported box. The
* column-centre offsets mirror the grid-template-columns expression
* above. Both horizontal runs are anchored a fixed distance above the
* bottom row so the firm run always sits below the direct run
* regardless of how tall the stage-label row renders. */
.flow-converge {
grid-column: 1 / -1;
grid-row: 5 / span 2;
position: relative;
min-height: 40px;
pointer-events: none;
}
.flow-converge > span {
position: absolute;
}
.fc-firm {
top: 0;
bottom: 47px;
left: calc(12.5% - 3.75px);
right: calc(12.5% - 10.5px);
border-right: 1.5px solid var(--flow-firm-line);
border-bottom: 1.5px solid var(--flow-firm-line);
}
.fc-firm-drop {
bottom: 0;
height: 47px;
left: calc(12.5% - 3.75px);
width: 0;
border-left: 1.5px solid var(--flow-firm-line);
}
.fc-direct {
top: 0;
bottom: 55px;
left: calc(12.5% - 15.75px);
right: calc(62.5% + 3.25px);
border-right: 1.5px solid var(--flow-direct-line);
border-bottom: 1.5px solid var(--flow-direct-line);
}
.fc-direct-drop {
bottom: 0;
height: 55px;
left: calc(12.5% - 15.75px);
width: 0;
border-left: 1.5px solid var(--flow-direct-line);
}
.flow-no-firm .fc-direct-drop {
left: calc(12.5% - 9.75px);
}
.flow-no-firm .fc-direct {
right: calc(62.5% + 9.75px);
left: calc(12.5% - 9.75px);
}
.fc-firm-drop::after,
.fc-direct-drop::after {
content: "";
position: absolute;
bottom: 0;
left: -3.75px;
width: 0;
height: 0;
border: 4.5px solid transparent;
border-bottom-width: 0;
border-top: 6px solid var(--flow-firm-line);
}
.fc-direct-drop::after {
border-top-color: var(--flow-direct-line);
}
.flow-caption {
grid-column: 1 / -1;
grid-row: 8;
text-align: right;
font-size: 11px;
color: var(--fg-muted);
margin-top: 12px;
}
/* Narrow screens stack the pipeline vertically in reading order; the
* fork and convergence connectors are hidden and the inter-box arrows
* point downward. */
@media (max-width: 768px) {
.card-row {
grid-template-columns: 1fr;
}
#stat-flow {
display: flex;
flex-direction: column;
gap: 8px;
}
.flow-fork,
.flow-drop,
.flow-converge {
display: none;
}
.flow-stage {
text-align: left;
padding: 10px 0 0;
}
.flow-arrow {
align-self: center;
width: 9px;
height: 18px;
margin: -2px 0;
}
.flow-arrow::before {
left: 4px;
right: auto;
top: 0;
bottom: 5px;
width: 0;
border-top: none;
border-left: 1.5px solid var(--flow-line);
}
.flow-arrow::after {
left: 0;
right: auto;
top: auto;
bottom: 0;
border: 4.5px solid transparent;
border-bottom-width: 0;
border-top: 6px solid var(--flow-line);
}
.flow-arrow-firm::before {
border-left-color: var(--flow-firm-line);
}
.flow-arrow-firm::after {
border-top-color: var(--flow-firm-line);
}
.flow-stage-discovered {
order: 1;
}
.flow-pos-candidate {
order: 2;
}
.flow-stage-triaged {
order: 3;
}
.flow-pos-triaged {
order: 4;
}
.flow-pos-arrow-tv {
order: 5;
}
.flow-pos-verified {
order: 6;
}
.flow-pos-arrow-vc {
order: 7;
}
.flow-pos-confirmed {
order: 8;
}
.flow-pos-direct {
order: 9;
}
.flow-stage-disclosed {
order: 10;
}
.flow-pos-disclosed {
order: 11;
}
.flow-pos-arrow-da {
order: 12;
}
.flow-pos-acked {
order: 13;
}
.flow-pos-arrow-ap {
order: 14;
}
.flow-stage-remediated {
order: 15;
}
.flow-pos-patched {
order: 16;
}
.flow-pos-arrow-pa {
order: 17;
}
.flow-pos-advisories {
order: 18;
}
.flow-caption {
order: 19;
text-align: left;
}
}
.table-scroll {
overflow-x: auto;
}
.muted {
color: var(--fg-muted);
}
.figure {
background: var(--surface-paper);
padding: 22px 16px;
margin: 24px 0;
}
figcaption {
font-size: 12px;
color: var(--fg-muted);
margin-top: 8px;
display: block;
}
table {
border-collapse: collapse;
width: 100%;
}
th,
td {
text-align: left;
padding: 8px 12px;
border-bottom: 1px solid var(--hairline-faint);
}
th {
font-weight: 600;
font-size: 13px;
color: var(--fg-muted);
}
table.sortable th {
cursor: pointer;
user-select: none;
}
table.sortable th.sort-asc::after {
content: " \25B2";
font-size: 9px;
}
table.sortable th.sort-desc::after {
content: " \25BC";
font-size: 9px;
}
.hash {
word-break: break-all;
font-size: 12px;
}
.hash.full {
font-family: ui-monospace, "SF Mono", Menlo, monospace;
font-size: 11px;
color: var(--fg-muted);
}
.empty {
color: var(--fg-muted);
font-style: italic;
}
footer {
margin-top: 100px;
border-top: 1px solid var(--hairline);
padding-top: 20px;
font-size: 13px;
color: var(--fg-muted);
}
footer p {
margin: 4px 0;
}
/* Figure colours. The fill classes are shared between the area chart
* bands, the heatmap legend, and inline severity labels. */
.sev-critical {
fill: var(--sev-critical);
color: var(--sev-critical-text);
}
.sev-high {
fill: var(--sev-high);
color: var(--sev-high-text);
}
.sev-medium {
fill: var(--sev-medium);
color: var(--sev-medium-text);
}
.sev-low {
fill: var(--sev-low);
color: var(--sev-low-text);
}
.sev-unknown {
fill: var(--hairline);
color: var(--fg-muted);
}
.axis {
font-size: 11px;
fill: var(--fg-muted);
}
/* A thin background-coloured stroke separates adjacent area-chart bands
* so the boundary between two pale fills (in particular ``--sev-low``
* against ``--surface-paper``) is visible without relying on hue
* contrast alone. */
.band {
stroke: var(--bg);
stroke-width: 1px;
}
.band.dim {
opacity: 0.2;
}
.heat-cell {
cursor: default;
}
#heat-tooltip {
position: fixed;
background: #000;
color: #fff;
font-size: 12px;
padding: 4px 8px;
pointer-events: none;
}
/* Per-finding card. The badges, timeline, and diff blocks reuse the
* surface tokens above so a card reads as a section of the same site
* rather than a distinct document. */
.sev-badge {
display: inline-block;
font-size: 13px;
font-weight: 700;
text-transform: uppercase;
padding: 2px 10px;
border: 1px solid currentColor;
margin-left: 12px;
vertical-align: middle;
}
.id-badges {
margin: 8px 0 0;
}
.id-badge {
display: inline-block;
font-family: ui-monospace, "SF Mono", Menlo, monospace;
font-size: 13px;
background: var(--surface-note);
border-bottom: 1px solid var(--divider);
padding: 4px 10px;
margin-right: 8px;
text-decoration: none;
color: var(--fg-bright);
}
.id-badge:hover {
border-left: 2px solid var(--stroke-strong);
padding-left: 8px;
}
.attribution {
color: var(--fg-muted);
font-size: 14px;
margin: 12px 0 0;
}
.sev-compare {
margin: 12px 0 0;
font-size: 14px;
}
.sev-compare-label {
color: var(--fg-muted);
font-size: 12px;
text-transform: uppercase;
letter-spacing: 0.5px;
margin-right: 4px;
}
.sev-compare-sep {
color: var(--fg-muted);
margin: 0 8px;
}
.sev-compare-item {
font-weight: 600;
}
.vendor-analysis {
display: grid;
grid-template-columns: max-content 1fr;
column-gap: 16px;
row-gap: 6px;
margin: 16px 0;
font-size: 14px;
}
.vendor-analysis dt {
color: var(--fg-muted);
}
.vendor-analysis dd {
margin: 0;
}
.timeline {
list-style: none;
display: flex;
margin: 0;
padding: 0;
}
.timeline-pt {
flex: 1;
position: relative;
padding: 0 6px;
text-align: center;
}
.timeline-pt::before {
content: "";
position: absolute;
top: 6px;
left: 0;
right: 0;
height: 1px;
background: var(--stroke-strong);
}
.timeline-pt:first-child::before {
left: 50%;
}
.timeline-pt:last-child::before {
right: 50%;
}
.timeline-dot {
display: block;
width: 12px;
height: 12px;
background: var(--stroke-strong);
margin: 0 auto;
position: relative;
}
.timeline-date {
display: block;
font-family: ui-monospace, "SF Mono", Menlo, monospace;
font-size: 12px;
margin-top: 8px;
}
.timeline-label {
display: block;
font-size: 12px;
color: var(--fg-muted);
}
.report-body {
background: var(--surface-note);
border-bottom: 1px solid var(--divider);
padding: 20px 24px;
font-size: 14px;
line-height: 1.6;
overflow-x: auto;
margin: 16px 0;
}
.report-body h1,
.report-body h2,
.report-body h3 {
margin-top: 24px;
border: 0;
padding: 0;
}
.report-body h1 {
font-size: 22px;
}
.report-body h2 {
font-size: 18px;
}
.report-body pre {
background: rgba(0, 0, 0, 0.05);
padding: 12px;
overflow-x: auto;
font-size: 12px;
}
.report-body code {
font-family: ui-monospace, "SF Mono", Menlo, monospace;
}
.diff-block {
margin: 16px 0;
min-width: 0;
}
.diff {
background: var(--surface-note);
border-bottom: 1px solid var(--divider);
padding: 12px;
font-family: ui-monospace, "SF Mono", Menlo, monospace;
font-size: 11px;
line-height: 1.4;
overflow-x: auto;
margin: 0;
}
.diff code {
display: block;
}
.diff-h {
color: var(--fg-muted);
}
.diff-a {
color: var(--diff-add);
}
.diff-d {
color: var(--sev-critical-text);
}
.diff-c {
color: var(--fg);
}
/* HubSpot subscribe-form container. The v2 embed renders the form
* inside an iframe whose document the site stylesheet cannot reach, so
* the labels, consent line, and inputs keep the embed's default
* dark-on-light colours regardless of the active token set. Under the
* dark theme the container is given a light surface so those defaults
* remain readable; the light theme needs no override because the page
* background already matches the embed's assumption. */
:root[data-theme="dark"] #hubspot-form-container {
background: #fff;
color: #1a1a1a;
padding: 20px 24px;
}
@media (prefers-color-scheme: dark) {
:root:not([data-theme="light"]) #hubspot-form-container {
background: #fff;
color: #1a1a1a;
padding: 20px 24px;
}
}