/* =====================================
   Machine learning pages (/ml/...)
   ===================================== */

/* Training, validation and test: the first three categorical slots of the validated reference
   palette (they separate for every pair, also with colour blindness), stepped for each theme.
   Each set also has its own shape, so the colour is never the only cue. */
:root {
    --ml-train: #2a78d6;
    --ml-val: #eb6834;
    --ml-test: #1baf7a;
    --ml-curve: #0b0b0b;
}

:root.dark {
    --ml-train: #3987e5;
    --ml-val: #d95926;
    --ml-test: #199e70;
    --ml-curve: #f0efec;
}

.ml-controls {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 10px 20px;
    margin: 12px 0;
}

.ml-controls label {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 0;
}

.ml-controls label span {
    white-space: nowrap;
}

.ml-slider input {
    width: 160px;
}

.ml-slider output {
    min-width: 2ch;
    font-weight: bold;
    font-variant-numeric: tabular-nums;
}

.ml-legend {
    display: flex;
    flex-wrap: wrap;
    gap: 6px 18px;
    padding: 0;
    margin: 6px 0 10px;
    list-style: none;
    font-size: 0.9rem;
    color: var(--text-muted);
}

.ml-legend li {
    display: flex;
    align-items: center;
    gap: 6px;
}

.ml-legend li[hidden] {
    display: none;
}

.ml-legend svg {
    width: 14px;
    height: 14px;
}

.ml-legend svg[viewBox="0 0 16 12"] {
    width: 18px;
}

.ml-chart {
    position: relative;
    max-width: 720px;
}

#mlv_chart {
    display: block;
    width: 100%;
    height: auto;
}

.ml-gridline {
    stroke: var(--border);
    stroke-width: 1;
    opacity: 0.6;
}

.ml-axis {
    stroke: var(--text-muted);
    stroke-width: 1;
}

.ml-tick {
    fill: var(--text-muted);
    font-size: 11px;
}

.ml-tick-y {
    text-anchor: end;
}

.ml-tick-x {
    text-anchor: middle;
}

.ml-train {
    fill: var(--ml-train);
}

.ml-val {
    fill: var(--ml-val);
}

.ml-test {
    fill: var(--ml-test);
}

.ml-point {
    stroke: var(--card-bg);
    stroke-width: 2;
}

/* Locked test points: only their outline, they are not to be looked at yet */
.ml-test.locked {
    fill: none;
    stroke: var(--ml-test);
    stroke-width: 1.5;
    stroke-dasharray: 2 2;
}

.ml-curve {
    fill: none;
    stroke: var(--ml-curve);
    stroke-width: 2;
}

.ml-final {
    fill: none;
    stroke: var(--ml-test);
    stroke-width: 2.5;
    stroke-dasharray: 6 4;
}

.ml-hit {
    fill: transparent;
}

.ml-tooltip {
    position: absolute;
    padding: 5px 9px;
    border: 1px solid var(--border);
    border-radius: 6px;
    background: var(--card-bg);
    color: var(--text);
    box-shadow: 0 4px 10px rgba(0, 0, 0, 0.12);
    font-size: 0.85rem;
    white-space: nowrap;
    pointer-events: none;
}

.ml-verdict {
    min-height: 1.4em;
    font-weight: bold;
}

.ml-details {
    margin-top: 10px;
}

.ml-details summary {
    cursor: pointer;
    color: var(--accent);
}

.ml-mono {
    font-family: Consolas, Menlo, monospace;
    font-size: 0.88rem;
    word-break: break-word;
}

.ml-table {
    margin-top: 8px;
    border-collapse: collapse;
    font-variant-numeric: tabular-nums;
}

.ml-table th,
.ml-table td {
    padding: 2px 16px 2px 0;
    text-align: right;
}

/* --- The folds --- */
.ml-swatch {
    display: inline-block;
    width: 12px;
    height: 12px;
    border-radius: 2px;
}

.fold-val {
    background: var(--ml-val);
}

.fold-train {
    background: var(--ml-train);
    opacity: 0.35;
}

.ml-folds {
    display: grid;
    gap: 6px;
    max-width: 760px;
}

.ml-fold {
    display: grid;
    grid-template-columns: 4.5em 1fr 90px 3.5em;
    align-items: center;
    gap: 10px;
    transition: opacity 0.3s ease;
}

.ml-fold.waiting {
    opacity: 0.12;
}

.ml-fold-label,
.ml-fold-value {
    font-size: 0.85rem;
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
}

.ml-fold-strip {
    display: grid;
    grid-template-columns: repeat(32, 1fr);
    gap: 2px;
}

.ml-fold-cell {
    height: 14px;
    border-radius: 2px;
}

.ml-fold-bar {
    height: 10px;
    border-radius: 0 4px 4px 0;
    background: var(--surface-2);
}

.ml-fold-bar span {
    display: block;
    height: 100%;
    border-radius: 0 4px 4px 0;
    background: var(--ml-val);
}

@media (max-width: 520px) {
    .ml-fold {
        grid-template-columns: 3.6em 1fr 3.2em;
    }

    .ml-fold-bar {
        display: none;
    }
}

/* --- The grid search heatmap --- */
.ml-grid-wrap {
    overflow-x: auto;
}

.ml-grid {
    border-collapse: separate;
    border-spacing: 2px;
    font-variant-numeric: tabular-nums;
}

.ml-grid th {
    padding: 2px 6px;
    font-size: 0.8rem;
    font-weight: normal;
    color: var(--text-muted);
    white-space: nowrap;
}

.ml-grid td {
    padding: 0;
}

.ml-grid-cell {
    width: 58px;
    padding: 6px 0;
    border-radius: 4px;
    font-size: 0.78rem;
    font-weight: 600;
}

.ml-grid-cell:hover {
    filter: brightness(0.92);
}

.ml-grid-cell.best {
    box-shadow: 0 0 0 3px var(--ml-val);
}

.ml-grid-cell.current {
    outline: 2px solid var(--text);
    outline-offset: 1px;
}

.ml-scale {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 0.85rem;
    color: var(--text-muted);
}

.ml-ramp {
    display: inline-block;
    width: 140px;
    height: 10px;
    border-radius: 3px;
    background: linear-gradient(90deg, #cde2fb, #6da7ec, #2a78d6, #184f95, #0d366b);
}

/* --- Regression: two panels side by side, the residuals and the path on the error surface --- */
.ml-panels {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
    gap: 14px;
    margin: 10px 0;
}

.ml-panel {
    padding: 10px;
    border: 1px solid var(--border);
    border-radius: 8px;
    background-color: var(--card-bg);
}

.ml-panel h3 {
    margin: 0 0 6px;
    font-size: 1rem;
}

.ml-svg {
    display: block;
    width: 100%;
    height: auto;
}

.ml-clickable {
    cursor: crosshair;
}

.ml-residual {
    stroke: var(--text-muted);
    stroke-width: 1;
    opacity: 0.7;
}

.ml-path {
    fill: none;
    stroke: var(--ml-val);
    stroke-width: 2;
    stroke-linejoin: round;
}

.ml-path-dot {
    fill: var(--ml-val);
}

.ml-path-now {
    fill: var(--ml-val);
    stroke: var(--card-bg);
    stroke-width: 2;
}

.ml-exact {
    fill: none;
    stroke: var(--ml-curve);
    stroke-width: 2.5;
}

.ml-floor {
    stroke: var(--ml-curve);
    stroke-width: 1;
    stroke-dasharray: 4 4;
    opacity: 0.6;
}

.ml-legend .ml-scale {
    margin: 0;
}

.ml-axis-name {
    fill: var(--text-muted);
    font-size: 11px;
    font-weight: bold;
    text-anchor: middle;
}

/* --- Bias and variance: many thin models, their average and the truth; the error split --- */
.ml-fit-thin {
    fill: none;
    stroke: var(--ml-train);
    stroke-width: 1;
    opacity: 0.35;
}

.ml-mean {
    fill: none;
    stroke: var(--ml-train);
    stroke-width: 3;
}

.ml-truth {
    fill: none;
    stroke: var(--ml-curve);
    stroke-width: 2;
    stroke-dasharray: 5 4;
}

.ml-sample {
    fill: var(--text-muted);
    opacity: 0.6;
}

.ml-bias-line,
.ml-variance-line,
.ml-total-line {
    fill: none;
    stroke-width: 2;
}

.ml-bias-line { stroke: var(--ml-train); }
.ml-variance-line { stroke: var(--ml-val); }
.ml-total-line { stroke: var(--ml-curve); stroke-width: 2.5; }
.ml-bias-line-dot { fill: var(--ml-train); }
.ml-variance-line-dot { fill: var(--ml-val); }
.ml-total-line-dot { fill: var(--ml-curve); }

.ml-now {
    stroke: var(--text-muted);
    stroke-width: 1;
    stroke-dasharray: 3 3;
}

.ml-end-label {
    fill: var(--text);
    font-size: 11px;
}

/* --- Regularisation: the weights as bars, and each weight's path over λ --- */
.ml-weight {
    fill: var(--ml-train);
}

.ml-zero {
    fill: var(--text-muted);
    font-size: 12px;
    font-weight: bold;
    text-anchor: middle;
}

.ml-weight-path {
    fill: none;
    stroke: var(--ml-train);
    stroke-width: 1.5;
    opacity: 0.7;
}

/* --- Decision trees: the cuts, and the tree as boxes --- */
.ml-cut {
    stroke: var(--ml-val);
    stroke-width: 1;
    stroke-dasharray: 3 3;
    opacity: 0.7;
}

.ml-tree-wrap {
    overflow-x: auto;
}

#mlt_tree {
    min-width: 320px;
}

.ml-split {
    fill: var(--surface-2);
    stroke: var(--ml-train);
    stroke-width: 1.5;
}

.ml-leaf {
    fill: var(--ml-train);
    stroke: var(--ml-train);
}

.ml-node-text {
    fill: var(--text);
    font: bold 10px Consolas, Menlo, monospace;
    text-anchor: middle;
}

.ml-leaf + .ml-node-text {
    fill: #fff;
}

.ml-node-n {
    fill: var(--text-muted);
    font-size: 9px;
    text-anchor: middle;
}

#mlt_tree {
    margin: 0 auto;
}

.ml-tree-edge {
    stroke: var(--border);
    stroke-width: 1.5;
}

/* --- Classification: probability shading (diverging: blue "no", neutral, orange "yes") --- */
.ml-p { stroke: none; shape-rendering: crispEdges; }
.ml-p0 { fill: var(--ml-train); opacity: 0.42; }
.ml-p1 { fill: var(--ml-train); opacity: 0.32; }
.ml-p2 { fill: var(--ml-train); opacity: 0.22; }
.ml-p3 { fill: var(--ml-train); opacity: 0.13; }
.ml-p4 { fill: var(--ml-train); opacity: 0.05; }
.ml-p5 { fill: var(--ml-val); opacity: 0.05; }
.ml-p6 { fill: var(--ml-val); opacity: 0.13; }
.ml-p7 { fill: var(--ml-val); opacity: 0.22; }
.ml-p8 { fill: var(--ml-val); opacity: 0.32; }
.ml-p9 { fill: var(--ml-val); opacity: 0.42; }

.ml-plane-panel {
    max-width: 560px;
}

.ml-faint {
    opacity: 0.35;
}

.ml-boundary {
    stroke: var(--ml-curve);
    stroke-width: 2.5;
    stroke-dasharray: 7 4;
}

.ml-mistake {
    fill: none;
    stroke: var(--error);
    stroke-width: 2;
}

/* --- The confusion matrix and the measures --- */
.ml-confusion {
    width: 100%;
    border-collapse: separate;
    border-spacing: 4px;
}

.ml-confusion th {
    padding: 4px;
    font-size: 0.8rem;
    font-weight: normal;
    color: var(--text-muted);
}

.ml-confusion th.axis {
    text-align: center;
}

.ml-cell {
    padding: 10px 6px;
    border-radius: 6px;
    text-align: center;
}

.ml-cell strong {
    display: block;
    font-size: 1.6rem;
}

.ml-cell small {
    display: block;
    font-size: 0.75rem;
}

.ml-cell.right {
    background-color: rgba(76, 175, 80, 0.18);
}

.ml-cell.wrong {
    background-color: rgba(220, 53, 69, 0.16);
}

.ml-measures {
    display: grid;
    gap: 10px;
    margin: 0;
}

.ml-measure dt {
    display: flex;
    justify-content: space-between;
    font-weight: bold;
}

.ml-measure dd {
    margin: 2px 0 0;
}

.ml-measure-text {
    display: block;
    font-size: 0.85rem;
    color: var(--text-muted);
}

.ml-formula {
    display: block;
    font-size: 0.78rem;
    word-break: break-word;
}

.ml-auc {
    fill: var(--ml-val);
    opacity: 0.12;
}

.ml-panel-text {
    display: flex;
    align-items: center;
}

/* --- Support vector machines: the street, its middle and the support vectors --- */
.ml-svm-boundary {
    fill: none;
    stroke: var(--ml-curve);
    stroke-width: 2.5;
}

.ml-svm-margin {
    fill: none;
    stroke: var(--ml-curve);
    stroke-width: 1.5;
    stroke-dasharray: 5 4;
    opacity: 0.8;
}

.ml-support {
    fill: none;
    stroke: var(--ml-curve);
    stroke-width: 1.8;
}

.ml-radio-row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px 14px;
    margin: 0;
    padding: 0;
    border: none;
}

.ml-radio-row legend {
    float: left;
    margin-right: 6px;
    padding: 0;
}

.ml-radio-row label {
    display: flex;
    align-items: center;
    gap: 4px;
}

/* The site's inputs are full width; a radio button is not */
.ml-radio-row input {
    width: auto;
    margin: 0;
    padding: 0;
    accent-color: var(--accent);
}

/* --- Without labels: the PCA direction, the projections and the components --- */
.ml-direction {
    stroke: var(--ml-val);
    stroke-width: 2.5;
}

.ml-projection {
    stroke: var(--text-muted);
    stroke-width: 0.8;
    opacity: 0.6;
}

.ml-projected {
    fill: var(--ml-val);
}

.ml-pc {
    stroke: var(--ml-curve);
    stroke-width: 3;
    stroke-linecap: round;
}

.ml-faint-strong {
    opacity: 0.55;
}

.ml-check {
    display: flex;
    align-items: center;
    gap: 6px;
}

.ml-check input {
    width: auto;
    margin: 0;
    accent-color: var(--accent);
}

/* --- K-means: six groups, each with a colour (the reference categorical order) and a shape --- */
:root {
    --ml-c0: #2a78d6;
    --ml-c1: #eb6834;
    --ml-c2: #1baf7a;
    --ml-c3: #eda100;
    --ml-c4: #e87ba4;
    --ml-c5: #008300;
}

:root.dark {
    --ml-c0: #3987e5;
    --ml-c1: #d95926;
    --ml-c2: #199e70;
    --ml-c3: #c98500;
    --ml-c4: #d55181;
    --ml-c5: #008300;
}

.ml-c0 { fill: var(--ml-c0); }
.ml-c1 { fill: var(--ml-c1); }
.ml-c2 { fill: var(--ml-c2); }
.ml-c3 { fill: var(--ml-c3); }
.ml-c4 { fill: var(--ml-c4); }
.ml-c5 { fill: var(--ml-c5); }
.ml-c0-line, .ml-c0-ring { stroke: var(--ml-c0); }
.ml-c1-line, .ml-c1-ring { stroke: var(--ml-c1); }
.ml-c2-line, .ml-c2-ring { stroke: var(--ml-c2); }
.ml-c3-line, .ml-c3-ring { stroke: var(--ml-c3); }
.ml-c4-line, .ml-c4-ring { stroke: var(--ml-c4); }
.ml-c5-line, .ml-c5-ring { stroke: var(--ml-c5); }

.ml-assign {
    stroke-width: 0.8;
    opacity: 0.45;
}

.ml-unassigned {
    fill: var(--text-muted);
    opacity: 0.6;
}

.ml-centre {
    fill: var(--card-bg);
    stroke-width: 3.5;
}

.ml-centre-number {
    fill: var(--text);
    font-size: 12px;
    font-weight: bold;
    text-anchor: middle;
}

/* --- Neural networks: validation points outlined, the network as small pictures and weighted edges --- */
.ml-point.ml-holdout {
    stroke: var(--ml-curve);
    stroke-width: 1.5;
}

.ml-net {
    min-width: 320px;
    margin: 0 auto;
}

.ml-edge {
    opacity: 0.55;
    stroke-linecap: round;
}

.ml-edge-pos { stroke: var(--ml-val); }
.ml-edge-neg { stroke: var(--ml-train); }

.ml-neuron-frame {
    fill: none;
    stroke: var(--border);
    stroke-width: 1;
}

/* The pictures are small: stronger shading than the plane so on and off are easy to tell apart */
.ml-neuron .ml-p0 { opacity: 0.85; }
.ml-neuron .ml-p1 { opacity: 0.65; }
.ml-neuron .ml-p2 { opacity: 0.45; }
.ml-neuron .ml-p3 { opacity: 0.26; }
.ml-neuron .ml-p4 { opacity: 0.1; }
.ml-neuron .ml-p5 { opacity: 0.1; }
.ml-neuron .ml-p6 { opacity: 0.26; }
.ml-neuron .ml-p7 { opacity: 0.45; }
.ml-neuron .ml-p8 { opacity: 0.65; }
.ml-neuron .ml-p9 { opacity: 0.85; }

/* --- Convolution: an image to draw in, the filter's window, the maps as numbered cells --- */
.ml-panels-3 {
    grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
}

.ml-draw {
    touch-action: none;
    cursor: crosshair;
}

.ml-ink { fill: var(--ml-curve); }
.ml-paper { fill: var(--card-bg); stroke: var(--border); stroke-width: 0.5; }

.ml-pad {
    fill: var(--surface-2);
    stroke: var(--border);
    stroke-width: 0.5;
    stroke-dasharray: 2 2;
}

.ml-window {
    fill: none;
    stroke: var(--ml-val);
    stroke-width: 3;
}

.ml-window-thin { stroke-width: 0.2; }
.ml-cell-zero { fill: none; }

.ml-map-cell {
    stroke: var(--border);
    stroke-width: 0.5;
}

.ml-map-number {
    fill: var(--text);
    font-size: 11px;
    text-anchor: middle;
}

.ml-kernel { max-width: 240px; margin: 0 auto; }
.ml-kernel-number { font-size: 15px; font-weight: bold; }

.ml-hint {
    color: var(--text-muted);
    font-size: 0.85rem;
}

.ml-own {
    max-width: 220px;
    margin: 0 0 10px;
    border: 1px solid var(--border);
    border-radius: 8px;
}

.ml-own legend { font-size: 0.85rem; }

.ml-own-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 4px;
}

.ml-own-grid input {
    width: 100%;
    text-align: center;
}

.ml-examples {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
    gap: 10px;
}

.ml-example {
    margin: 0;
    padding: 6px;
    border: 1px solid var(--border);
    border-radius: 6px;
    background: var(--card-bg);
}

.ml-example figcaption {
    margin-top: 4px;
    font-size: 0.78rem;
}

.ml-example-frame {
    fill: none;
    stroke: var(--border);
    stroke-width: 0.1;
}

/* --- Recurrent networks: the network unrolled, one column per character --- */
.ml-unroll { min-width: 320px; }

.ml-carry {
    stroke: var(--text-muted);
    stroke-width: 2;
}

.ml-carry-off {
    stroke-dasharray: 3 3;
    opacity: 0.35;
}

.ml-step-char,
.ml-step-guess {
    fill: var(--text);
    font: bold 14px Consolas, Menlo, monospace;
    text-anchor: middle;
}

.ml-guess-bar { fill: var(--text-muted); opacity: 0.5; }

/* Right and wrong guesses: green and red, and the letter is there too, so not by colour alone */
.ml-guess-bar.ml-guess-right { fill: #2e7d32; opacity: 0.8; }
.ml-guess-bar.ml-guess-wrong { fill: var(--error); opacity: 0.8; }
.ml-step-guess.ml-guess-right { fill: #2e7d32; }
.ml-step-guess.ml-guess-wrong { fill: var(--error); }
:root.dark .ml-guess-bar.ml-guess-right { fill: #66bb6a; }
:root.dark .ml-step-guess.ml-guess-right { fill: #66bb6a; }

.ml-text {
    font-family: Consolas, Menlo, monospace;
    word-break: break-all;
}

.ml-text-big { font-size: 1.05rem; }

/* --- Semantic search: the ranked chunks, the question's vector, the prompt --- */
.ml-grow { flex: 1 1 260px; }
.ml-grow input { flex: 1; min-width: 0; }
.ml-chip { padding: 4px 10px; font-size: 0.85rem; }

#mlrag_text {
    width: 100%;
    margin-top: 8px;
    font: inherit;
}

.ml-hits {
    display: grid;
    gap: 8px;
    margin: 8px 0;
    padding: 0;
    list-style: none;
}

.ml-hit {
    padding: 8px 10px;
    border: 1px solid var(--border);
    border-radius: 8px;
    background: var(--card-bg);
}

.ml-hit-top { border-color: var(--ml-val); box-shadow: inset 3px 0 0 var(--ml-val); }
.ml-hit-none { opacity: 0.55; }

.ml-hit-head {
    display: flex;
    align-items: center;
    gap: 10px;
    font-size: 0.85rem;
}

.ml-hit-bar {
    flex: 0 1 160px;
    height: 8px;
    border-radius: 4px;
    background: var(--surface-2);
    overflow: hidden;
}

.ml-hit-fill {
    display: block;
    height: 100%;
    background: var(--ml-val);
}

.ml-hit-score { color: var(--text-muted); }

.ml-hit-text {
    margin: 6px 0 0;
    font-size: 0.9rem;
}

.ml-hit-text mark {
    padding: 0 2px;
    border-radius: 3px;
    background: rgba(235, 104, 52, 0.25);
    color: inherit;
}

.ml-terms {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin: 0 0 8px;
    padding: 0;
    list-style: none;
}

.ml-term {
    display: flex;
    gap: 6px;
    padding: 2px 8px;
    border: 1px solid var(--border);
    border-radius: 12px;
    font-size: 0.85rem;
}

.ml-map-dot-number {
    fill: #fff;
    font-size: 10px;
    font-weight: bold;
    text-anchor: middle;
}

.ml-star {
    fill: var(--ml-val);
    stroke: var(--card-bg);
    stroke-width: 1.5;
}

.ml-prompt {
    max-height: 320px;
    padding: 10px;
    border: 1px solid var(--border);
    border-radius: 8px;
    background: var(--surface-2);
    font-size: 0.82rem;
    white-space: pre-wrap;
    overflow: auto;
}

/* --- In practice: the encoded table, weights as bars, the list of tries --- */
.ml-table-wrap { overflow-x: auto; }

.ml-data-table {
    border-collapse: collapse;
    font-size: 0.82rem;
    white-space: nowrap;
}

.ml-data-table th,
.ml-data-table td {
    padding: 4px 8px;
    border: 1px solid var(--border);
    text-align: right;
}

.ml-data-table th { background: var(--th-bg); }
.ml-data-table .ml-raw { color: var(--text-muted); font-style: italic; }
.ml-data-table .ml-filled { background: rgba(235, 104, 52, 0.18); }
.ml-tries td:first-child { text-align: left; white-space: normal; }
.ml-tries .ml-best td { font-weight: bold; }
.ml-bar-pos { fill: var(--ml-val); }
.ml-bar-neg { fill: var(--ml-train); }

/* --- Pipelines and leakage: the steps in order, and what validation says against new data --- */
.ml-flow {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: 10px;
    margin: 12px 0;
    padding: 0;
    list-style: none;
    counter-reset: flow;
}

.ml-flow li {
    position: relative;
    padding: 10px 12px 10px 40px;
    border: 1px solid var(--border);
    border-radius: 8px;
    background: var(--card-bg);
    font-size: 0.9rem;
    counter-increment: flow;
}

.ml-flow li::before {
    content: counter(flow);
    position: absolute;
    top: 10px;
    left: 12px;
    width: 20px;
    height: 20px;
    border-radius: 50%;
    background: var(--accent);
    color: var(--accent-text);
    font-size: 0.8rem;
    font-weight: bold;
    line-height: 20px;
    text-align: center;
}

.ml-compare {
    display: grid;
    gap: 8px;
    max-width: 560px;
    margin: 10px 0;
}

.ml-compare-row {
    display: grid;
    grid-template-columns: 9em 1fr 7em;
    align-items: center;
    gap: 10px;
}

.ml-compare-bar { height: 14px; flex: none; }
.ml-fill-new { background: var(--ml-train); }

/* --- Ensembles: the voting models as thin coloured lines --- */
.ml-model-line {
    fill: none;
    stroke-width: 2;
    opacity: 0.85;
}

/* The vote in the text colour, apart from the three coloured models */
.ml-vote-line { fill: none; stroke: var(--ml-curve); stroke-width: 3; }
.ml-vote-bar { fill: var(--ml-curve); }

/* --- More than two classes: the plane in class colours, the boundaries, the clicked point --- */
.ml-region { opacity: 0.16; stroke: none; shape-rendering: crispEdges; }
.ml-boundary-k { fill: none; stroke-width: 2; }
.ml-boundary-pair { stroke: var(--text-muted); stroke-dasharray: 6 4; }
.ml-holdout-k { fill: var(--card-bg); stroke-width: 2; }
.ml-probe-dot { fill: var(--text); }

.ml-probe {
    margin: 0;
    padding-left: 18px;
    font-size: 0.85rem;
}

.ml-probe li { margin: 4px 0; }
.ml-probe-now { font-weight: bold; }
.ml-confusion-k .ml-cell { padding: 6px; }

/* --- Data & statistics: histogram bars, mean and median, the box plot, the summary numbers --- */
.dd-bar { fill: var(--ml-train); opacity: 0.75; }
.dd-bar-mode { opacity: 1; }
.dd-mean-line { stroke: var(--ml-val); stroke-width: 3; }
.dd-median-line { stroke: var(--ml-curve); stroke-width: 2.5; stroke-dasharray: 6 3; }
.dd-box { fill: var(--surface-2); stroke: var(--ml-curve); stroke-width: 1.5; }
.dd-whisker { stroke: var(--ml-curve); stroke-width: 1.5; }
.dd-outlier { fill: none; stroke: var(--ml-val); stroke-width: 2; }
.dd-normal-bar { fill: var(--text-muted); opacity: 0.5; }

.dd-numbers {
    display: grid;
    grid-template-columns: auto auto;
    gap: 4px 14px;
    margin: 0 0 10px;
    font-size: 0.9rem;
}

.dd-numbers dt { color: var(--text-muted); }
.dd-numbers dd { margin: 0; font-weight: bold; text-align: right; }

/* --- Correlation: Anscombe's four side by side, days shaded from cold to warm (one hue) --- */
.dc-quartet {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
    gap: 10px;
}

.dc-quartet-set {
    margin: 0;
    padding: 6px;
    border: 1px solid var(--border);
    border-radius: 8px;
    background: var(--card-bg);
}

.dc-quartet-set figcaption {
    font-size: 0.82rem;
    text-align: center;
}

.dc-t0 { fill: var(--ml-val); opacity: 0.25; }
.dc-t1 { fill: var(--ml-val); opacity: 0.45; }
.dc-t2 { fill: var(--ml-val); opacity: 0.65; }
.dc-t3 { fill: var(--ml-val); opacity: 0.82; }
.dc-t4 { fill: var(--ml-val); opacity: 1; }
.dc-far { stroke: var(--ml-curve); stroke-width: 2.5; }

/* --- Choosing a chart: radio buttons in a row, pie slices, the verdict's colour --- */
.ml-segmented {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px 14px;
}

.ml-segmented label { display: flex; align-items: center; gap: 4px; margin: 0; }
.dch-zero { stroke: var(--ml-curve); stroke-width: 1.5; }
.dch-slice { stroke: var(--card-bg); stroke-width: 2; }
.dch-icon { opacity: 0.85; }

.dch-slice-label {
    fill: #fff;
    font-size: 13px;
    font-weight: bold;
    text-anchor: middle;
}

#dch_verdict[data-fit="good"] { color: #2e7d32; }
#dch_verdict[data-fit="poor"] { color: var(--error); }
:root.dark #dch_verdict[data-fit="good"] { color: #66bb6a; }

/* --- Cleaning data: the steps as a numbered list, changed and empty cells marked --- */
.dcl-steps { margin: 6px 0 14px; padding-left: 22px; }
.dcl-steps li { margin: 4px 0; }
.dcl-steps li label { display: inline-flex; margin: 0; }
.dcl-count { color: var(--text-muted); }
.dcl-table td { text-align: left; font-family: Consolas, Menlo, monospace; }
.dcl-table .dcl-row { color: var(--text-muted); text-align: right; }
.ml-data-table .dcl-changed { background: rgba(235, 104, 52, 0.2); }
.ml-data-table .dcl-empty { background: repeating-linear-gradient(45deg, transparent 0 4px, var(--border) 4px 6px); }
.dcl-numbers th { text-align: left; }

/* Checkboxes and radio buttons keep their own size (style.css makes every input full width), and a
   label around one sits on a line with it */
input[type=checkbox],
input[type=radio] {
    width: auto;
    flex: none;
    margin: 0;
}

label:has(> input[type=checkbox]),
label:has(> input[type=radio]) {
    display: flex;
    align-items: baseline;
    gap: 6px;
}

/* --- Q-learning: the world's squares, the best move in each, the path taken --- */
.mlrl-cell { fill: var(--card-bg); stroke: var(--border); stroke-width: 1; }
.mlrl-wall { fill: var(--ml-curve); opacity: 0.75; }
.mlrl-danger { fill: var(--error); opacity: 0.55; }
.mlrl-goal { fill: #2e7d32; opacity: 0.75; }
:root.dark .mlrl-goal { fill: #66bb6a; }
.mlrl-label { fill: var(--text); font-weight: bold; font-size: 16px; text-anchor: middle; }
.mlrl-arrow { stroke: var(--ml-curve); stroke-width: 1.6; }
.mlrl-arrow-head { fill: var(--ml-curve); }
.mlrl-path { fill: none; stroke: var(--ml-train); stroke-width: 4; stroke-linejoin: round; opacity: 0.8; }
/* Value shading for the open squares, one hue from low to high (after .mlrl-cell, which it overrides) */
.mlrl-v0 { fill: var(--ml-val); fill-opacity: 0.08; }
.mlrl-v1 { fill: var(--ml-val); fill-opacity: 0.22; }
.mlrl-v2 { fill: var(--ml-val); fill-opacity: 0.4; }
.mlrl-v3 { fill: var(--ml-val); fill-opacity: 0.6; }
.mlrl-v4 { fill: var(--ml-val); fill-opacity: 0.82; }

/* --- Attention: keys sized by their weight, the grid of who looks at whom --- */
.mlat-link { stroke: var(--text-muted); opacity: 0.5; }
.mlat-key { stroke: var(--card-bg); stroke-width: 2; }
.mlat-cell { fill: var(--ml-val); stroke: var(--border); stroke-width: 0.5; }
.mlat-strong { font-weight: bold; fill: var(--text); }
.mlat-col { text-anchor: start; }
.mlat-row { stroke-width: 2; }
/* --- A real project, as an example under the pipeline --- */
.ml-real {
    margin: 18px 0;
    padding: 12px 16px;
    border: 1px solid var(--border);
    border-left: 4px solid var(--accent);
    border-radius: 8px;
    background: var(--card-bg);
}

.ml-real h3 { margin-top: 0; }
.ml-real-steps { margin: 6px 0; padding-left: 20px; }
.ml-real-steps li { margin: 4px 0; }
