carbon-demo / assets /styles /section-tree.css
tfrere's picture
tfrere HF Staff
Demo polish: colorblind-safe §6 strand; §5 completion-fold; §1 helix occlusion; §7 score chip; logo SVG; §8 evals refresh
f5d37e0
/* section-tree.css, §7 Species tree (Carbon-derived phylogeny).
Layout mirrors §6's editorial card. The grid is a 2-column structure:
left = SVG dendrogram spine (Bezier elbows), right = aligned data
tracks (italic name + kingdom chip + log count bar + NCBI agreement).
Every row gets a subtle kingdom background tint so the eye reads
coherent blocks without us drawing extra lines. */
.tree-toolbar {
display: flex; align-items: center; flex-wrap: wrap;
gap: 12px;
font-family: "JetBrains Mono", monospace; font-size: 11px;
color: #666;
margin-bottom: 14px;
}
.tree-toolbar .spacer { flex: 1; }
/* Pill sizing + spacing live in controls.css now (canonical across demos);
we only override the casing here because §7's vocabulary, `ward`,
`upgma`, `kingdom-level`, `sister-level`, reads better lowercase than
in the global uppercase + tracked treatment. */
.tree-toolbar .pills .pill {
text-transform: lowercase;
letter-spacing: 0;
}
/* Headline agreement metric for §7: a percentage in Carbon green next to
the raw ratio, with a discrete uppercase caption underneath naming what
the score compares against (e.g. "match · ncbi kingdom"). Pure typography,
no chrome, no progress bar — sits in the toolbar as a quiet stat block. */
.tree-score {
display: inline-flex; flex-direction: column;
align-items: flex-end; gap: 2px;
font-family: "JetBrains Mono", monospace;
color: #1f1f1d;
}
.tree-score-headline {
display: flex; align-items: baseline; gap: 8px;
}
.tree-score-pct {
font-size: 17px; font-weight: 700;
line-height: 1;
color: #317f3f;
font-variant-numeric: tabular-nums;
letter-spacing: -0.01em;
}
.tree-score-ratio {
font-size: 11px;
color: #888;
font-variant-numeric: tabular-nums;
white-space: nowrap;
}
.tree-score-label {
font-size: 9px; color: #888;
text-transform: uppercase; letter-spacing: 1.2px;
}
/* Main grid : SVG spine on the left, aligned tracks on the right.
The spine's height matches exactly N * row_h so each leaf lands on
its track row. We never use grid here (rows differ in semantics);
just two columns of equal-height children rendered in JS. */
.tree-grid {
display: grid;
grid-template-columns: minmax(280px, 1.5fr) minmax(0, 1.6fr);
gap: 0;
margin-top: 6px;
background: #fff;
border: 1px solid #e5e3da;
}
.tree-spine {
position: relative;
padding: 12px 0 28px 12px;
}
.tree-spine svg {
display: block; width: 100%; height: 100%;
overflow: visible;
}
/* Inline labels at each tip, only used in mobile (where the .tree-rows
panel stacks below). On desktop they're rendered but hidden so we
don't have to invalidate the SVG on viewport changes. */
.tree-spine svg .leaf-svg-label,
.tree-spine svg .leaf-svg-chip { display: none; }
.tree-spine svg .leaf-svg-label {
font-family: "JetBrains Mono", monospace;
font-size: 11px; font-style: italic;
dominant-baseline: middle;
}
.tree-spine .axis-label {
position: absolute; bottom: 6px; left: 12px;
font-family: "JetBrains Mono", monospace;
font-size: 9px; color: #888;
text-transform: uppercase; letter-spacing: 1.2px;
}
.tree-rows {
display: flex; flex-direction: column;
padding: 12px 0 28px 0;
}
.tree-row {
display: grid;
/* chip · name · bar · ncbi, name column is FIXED width so every
row's bar starts at the exact same X. (max-content gets broken
here by .tree-name's overflow:hidden, which makes each cell
size to its own content instead of the column's longest item.) */
grid-template-columns: 10px 115px minmax(60px, 1fr) 24px;
gap: 10px;
align-items: center;
padding: 0 14px 0 12px;
height: 22px; /* must equal ROW_H in the JS tree renderer */
transition: background 0.12s ease-out;
cursor: default;
}
.tree-row:hover { background: rgba(31, 31, 29, 0.04); }
.tree-row.dim { opacity: 0.35; }
/* Subtle background stripe by kingdom, matches the §6 palette */
.tree-row[data-kingdom="vertebrates"] { background-image: linear-gradient(to right, rgba(31, 31, 29, 0.04), transparent 40px); }
.tree-row[data-kingdom="invertebrates"] { background-image: linear-gradient(to right, rgba(122, 98, 66, 0.07), transparent 40px); }
.tree-row[data-kingdom="plants"] { background-image: linear-gradient(to right, rgba(49, 127, 63, 0.07), transparent 40px); }
.tree-row[data-kingdom="fungi"] { background-image: linear-gradient(to right, rgba(169, 118, 47, 0.07), transparent 40px); }
.tree-row[data-kingdom="bacteria"] { background-image: linear-gradient(to right, rgba(176, 0, 32, 0.07), transparent 40px); }
.tree-row[data-kingdom="viruses"] { background-image: linear-gradient(to right, rgba(44, 90, 160, 0.07), transparent 40px); }
.tree-row .tree-name {
font-family: "JetBrains Mono", monospace;
font-size: 12px; font-style: italic;
color: #1f1f1d; white-space: nowrap;
overflow: hidden; text-overflow: ellipsis;
}
.tree-row[data-kingdom="vertebrates"] .tree-name { color: #1f1f1d; }
.tree-row[data-kingdom="invertebrates"] .tree-name { color: #7a6242; }
.tree-row[data-kingdom="plants"] .tree-name { color: #317f3f; }
.tree-row[data-kingdom="fungi"] .tree-name { color: #a9762f; }
.tree-row[data-kingdom="bacteria"] .tree-name { color: #b00020; }
.tree-row[data-kingdom="viruses"] .tree-name { color: #2c5aa0; }
.tree-row .tree-chip {
width: 10px; height: 10px; border-radius: 2px;
}
.tree-row .tree-bar {
/* Two-column inner grid so the rail always spans 1fr (= same start
AND same end across rows), and the count sits in a fixed-width
right column → chiffres et fin de rail s'alignent partout. */
display: grid;
grid-template-columns: 1fr 46px;
gap: 8px;
align-items: center;
height: 22px;
}
.tree-row .tree-bar .bar-track {
position: relative; height: 6px;
background: #efece1; border-radius: 1.5px;
overflow: hidden;
}
.tree-row .tree-bar .bar-fill {
position: absolute; left: 0; top: 0; bottom: 0;
background: #c8c4b3; border-radius: 1.5px;
}
.tree-row .tree-bar .bar-num {
font-family: "JetBrains Mono", monospace;
font-size: 9px; color: #888;
font-variant-numeric: tabular-nums;
white-space: nowrap; text-align: right;
}
.tree-row .tree-ncbi {
text-align: center;
font-family: "JetBrains Mono", monospace;
font-size: 14px; font-weight: 700;
line-height: 1; user-select: none;
}
.tree-row .tree-ncbi[data-state="match"] { color: #317f3f; }
.tree-row .tree-ncbi[data-state="mismatch"] { color: #b00020; }
.tree-row .tree-ncbi[data-state="solo"] { color: #c8c5b9; }
/* Tooltip floats over the grid on row hover, fed with top-3 NN. */
.tree-tooltip {
position: absolute;
background: #1f1f1d; color: #f7f5ee;
font-family: "JetBrains Mono", monospace;
font-size: 10px; padding: 8px 11px; border-radius: 3px;
pointer-events: none; z-index: 50;
box-shadow: 0 4px 14px rgba(0, 0, 0, 0.18);
opacity: 0; transition: opacity 0.1s ease-out;
line-height: 1.5; white-space: nowrap;
}
.tree-tooltip.show { opacity: 1; }
.tree-tooltip .tt-title {
text-transform: uppercase; letter-spacing: 1.2px;
font-size: 9px; color: #888;
margin-bottom: 4px;
}
.tree-tooltip .tt-pair {
display: flex; gap: 10px; align-items: baseline;
font-variant-numeric: tabular-nums;
}
.tree-tooltip .tt-glyph { color: #888; width: 14px; }
.tree-tooltip .tt-name { color: #f7f5ee; }
.tree-tooltip .tt-name.expected { color: #317f3f; font-weight: 600; }
.tree-tooltip .tt-dist { color: #888; margin-left: auto; }
.tree-frame { position: relative; } /* anchor for the tooltip */
/* Footer legend strip + scoping caption */
.tree-legend {
display: flex; gap: 18px; flex-wrap: wrap;
margin-top: 10px;
font-family: "JetBrains Mono", monospace;
font-size: 10px; color: #666;
}
.tree-legend-item { display: flex; align-items: center; gap: 5px; }
.tree-legend-swatch { width: 9px; height: 9px; border-radius: 2px; }
.tree-legend-glyph { font-size: 12px; font-weight: 700; line-height: 1; }
.tree-caption {
margin-top: 6px;
font-family: "JetBrains Mono", monospace;
font-size: 10px; color: #999;
line-height: 1.6;
}
@media (max-width: 720px) {
.tree-grid { grid-template-columns: 1fr; }
.tree-spine { border-bottom: 1px solid #e5e3da; padding-right: 12px; }
.tree-spine svg .leaf-svg-label,
.tree-spine svg .leaf-svg-chip { display: inline; }
.tree-row { grid-template-columns: 10px 110px minmax(60px, 1fr) 22px; padding: 0 10px; }
}