Spaces:
Running
Running
| /* 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; } | |
| } | |