/* regulae page styles.
 *
 * Sourcehut-inspired: flat, one background, hairline rules instead of cards,
 * plain bold headings, default-blue links, and a single dark-red accent used
 * only where selection state must be read across two panels. Hybrid type:
 * sans for prose, monospace for data, tables, labels and headings. */

:root {
  --bg: #ffffff;
  --ink: #1a1a1a;
  --muted: #5a5a5a;
  --line: #dcdcdc;
  --link: #0b4fd8;
  --accent: #8b1a1a;
  --accent-soft: #faf2f2;
  --hover: #f4f4f4;
  --warn: #8a5b12;
  --sans: system-ui, -apple-system, "Segoe UI", Roboto, Cantarell, "Noto Sans", sans-serif;
  --mono: ui-monospace, "SF Mono", "Cascadia Mono", Menlo, Consolas, "DejaVu Sans Mono", monospace;
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #161616;
    --ink: #e2e2e2;
    --muted: #a0a0a0;
    --line: #383838;
    --link: #8ab4ff;
    --accent: #d97b7b;
    --accent-soft: #2a1c1c;
    --hover: #222222;
    --warn: #d9bc72;
  }
}

* { box-sizing: border-box; }

/* Text for a screen reader only: read aloud, off-screen. Used to voice the
   numbers a bar draws and any control whose label is otherwise only visual. */
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}

/* A visible focus ring for keyboard navigation. The result surface is a set of
   activatable rows, columns and headers, and a keyboard user needs to see which
   one holds focus. */
:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font: 14.5px/1.5 var(--sans);
}

a { color: var(--link); text-decoration: none; }
a:hover { text-decoration: underline; }

.wrap { max-width: 1180px; margin: 0 auto; padding: 0 20px 80px; }

/* ---- header ---------------------------------------------------------- */

/* A plain bar: wordmark, version, links, with a hairline underneath. */
.top {
  display: flex;
  align-items: baseline;
  gap: 16px;
  margin: 0 -20px;
  padding: 10px 20px;
  border-bottom: 1px solid var(--line);
  flex-wrap: wrap;
}
.top h1 { font: 600 17px/1.2 var(--mono); margin: 0; }
.top .version { color: var(--muted); font-size: 12px; font-family: var(--mono); }
.top .spacer { flex: 1; }
.top a, .top button { font-size: 13.5px; }
.top button { border: 0; padding: 0; background: none; color: var(--link); }
.top button:hover { text-decoration: underline; }

.tagline { margin: 12px 0 0; font-size: 14.5px; color: var(--muted); }

/* A plain note: a bold lead and prose, set off only by hairlines. */
.status-banner {
  margin: 14px 0 0;
  padding: 8px 0;
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  font-size: 13.5px;
}
.status-banner strong { color: var(--ink); }

/* ---- the boundary block ---------------------------------------------- */

/* Two plain columns of prose with a single rule between them; the lists carry
   the content, no box around them. */
.boundary {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 24px;
  margin: 18px 0 0;
}
.boundary section { padding: 0; }
.boundary section + section { border-left: 1px solid var(--line); padding-left: 24px; }
.boundary h2 { margin: 0 0 6px; font: 600 13px/1.4 var(--mono); }
.boundary ul { margin: 0; padding-left: 18px; }
.boundary li { margin: 3px 0; font-size: 13.5px; }
.boundary .is-not li { color: var(--muted); }

/* ---- controls -------------------------------------------------------- */

.controls {
  display: flex;
  gap: 8px;
  align-items: center;
  margin: 20px 0 10px;
  flex-wrap: wrap;
}
select, button, input[type="file"]::file-selector-button {
  font: inherit;
  font-size: 13.5px;
  padding: 5px 10px;
  border: 1px solid var(--line);
  border-radius: 0;
  background: var(--bg);
  color: var(--ink);
  cursor: pointer;
}
select:hover, button:hover { border-color: var(--ink); }
select { max-width: 340px; }
button.primary { background: var(--ink); border-color: var(--ink); color: var(--bg); }
button.primary:hover { background: var(--accent); border-color: var(--accent); }
button:disabled { opacity: 0.45; cursor: default; }
button:disabled:hover { border-color: var(--line); }
.controls .spacer { flex: 1; }

/* ---- options and the segment preview --------------------------------- */

/* The knobs that change a claim the tables make, folded away so the first
   screen is the data and the Run. Quiet: a visitor finds them when looking. */
.options { margin: 10px 0 0; }
.options > summary {
  list-style: none; cursor: pointer; display: inline-flex; align-items: center; gap: 6px;
  font: 12.5px var(--mono); color: var(--muted); padding: 4px 0;
}
.options > summary::-webkit-details-marker { display: none; }
.options > summary::before { content: "▸"; font-size: 10px; }
.options[open] > summary::before { content: "▾"; }
.options .opt-note { color: var(--warn); }
.options-body {
  display: flex; flex-direction: column; gap: 9px;
  margin: 8px 0 2px; padding: 12px 0 4px; border-top: 1px solid var(--line);
  font-size: 13px; color: var(--muted); font-family: var(--mono);
}
.options-body .opt-row { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.options-body label { color: var(--muted); }
.options-body select { max-width: 240px; font-family: var(--mono); font-size: 12.5px; }
.options-body .check { display: inline-flex; align-items: baseline; gap: 7px; cursor: pointer; flex-wrap: wrap; }
.options-body .check input { cursor: pointer; }
.options-body .slow { font-size: 12px; color: var(--warn); }
.options-body .hint-inline { font-size: 12px; color: var(--muted); }
/* A gated option: the box is disabled and this says why, so an unavailable
   diagnostic reads as a stated gap rather than a dead control. */
.options-body .check.disabled { opacity: 0.55; cursor: default; }
.options-body .check.disabled input { cursor: default; }
.options-body .unavailable { font-size: 12px; color: var(--warn); }

/* The input-format selector sits with the run controls, not the options, since
   it changes how the corpus is read rather than a claim the tables make. */
.controls .format { font-size: 12.5px; color: var(--muted); font-family: var(--mono); }
#format { max-width: 280px; }

.segment-tool {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 8px 0 0;
  flex-wrap: wrap;
}
.segment-tool label { font-size: 12.5px; color: var(--muted); font-family: var(--mono); white-space: nowrap; }
.segment-tool input {
  font: 13px/1.5 var(--mono);
  padding: 5px 9px;
  border: 1px solid var(--line);
  border-radius: 0;
  background: var(--bg);
  color: var(--ink);
  min-width: 220px;
}
.segment-tool input:focus { border-color: var(--ink); outline: none; }
/* The graphemes the form breaks into, dotted apart the way a class row writes a
   segment, so the preview and the results read in one alphabet. */
.segment-preview { display: flex; gap: 4px; flex-wrap: wrap; align-items: center;
  font-family: var(--mono); font-size: 13px; min-height: 1.6em; }
.segment-preview.bad { color: var(--warn); }
.segment-preview .grapheme {
  padding: 1px 6px;
  border: 1px solid var(--line);
  border-radius: 0;
}

textarea {
  width: 100%;
  min-height: 180px;
  resize: vertical;
  font: 13px/1.5 var(--mono);
  padding: 10px;
  border: 1px solid var(--line);
  border-radius: 0;
  background: var(--bg);
  color: var(--ink);
  tab-size: 12;
}
textarea:focus { border-color: var(--ink); outline: none; }

.example-note {
  margin: 6px 0 0;
  font-size: 13.5px;
  color: var(--muted);
}
.example-note.blocked { color: var(--warn); }

/* What the corpus publishes, as against what the note says it is for. Set
   apart from the prose because it is generated: scripts/corpora.py reads it
   off the trained model, so it cannot disagree with the run below it. */
.example-stats {
  margin: 4px 0 0;
  font-size: 12.5px;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
  font-family: var(--mono);
}
.example-stats:empty { display: none; }

/* ---- progress -------------------------------------------------------- */

.progress { margin: 12px 0 0; display: none; }
.progress.active { display: block; }
.progress .bar {
  height: 3px;
  background: var(--line);
  overflow: hidden;
}
.progress .fill { height: 100%; width: 0; background: var(--accent); }
.progress .label { margin-top: 5px; font-size: 12.5px; color: var(--muted); font-family: var(--mono); }

/* Errors and the baseline verdicts are plain prose set between hairlines,
   like the status banner: stated, not boxed. */
.error {
  margin: 14px 0 0;
  padding: 8px 0;
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
}
.error .what { font-weight: 600; color: var(--accent); }
.error .detail { color: var(--muted); font-size: 13.5px; margin-top: 4px; }

/* ---- results --------------------------------------------------------- */

.results { display: none; margin-top: 24px; }
.results.active { display: block; }

.summary {
  display: flex;
  gap: 20px;
  flex-wrap: wrap;
  padding: 10px 0;
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  font-size: 13.5px;
}
.summary b { font-family: var(--mono); font-weight: 600; }
.summary span { color: var(--muted); }

/* The shuffled-baseline verdict, when it was run. Prose between hairlines,
   a caveat on how far to trust the tables rather than a table itself. */
.baseline {
  margin-top: 16px;
  padding: 10px 0;
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
}
.baseline[hidden] { display: none; }
.baseline h2 { font: 600 13px/1.4 var(--mono); margin: 0 0 5px; }
.baseline p { margin: 0; font-size: 13.5px; }

/* Held-out prediction. Same treatment as the baseline verdict, with a short
   table under the prose. */
.predictive[hidden] { display: none; }
.predictive .scroll { max-height: 32vh; margin-top: 10px; }
.predictive table.classes td.num, .predictive table.classes th:not(:first-child) {
  text-align: right; font-variant-numeric: tabular-nums; font-family: var(--mono); white-space: nowrap;
}
.predictive tr.trained td { font-weight: 600; }
.predictive tr.trained td:first-child { color: var(--accent); }

/* The provenance block: closed by default, since it is reference rather than
   result. Its rows are label/value pairs read straight off the model. */
.provenance { margin-top: 16px; border-top: 1px solid var(--line);
  font-size: 13px; }
.provenance > summary { padding: 8px 0; cursor: pointer; color: var(--muted); }
.provenance dl { margin: 0; padding: 0 0 12px; display: grid;
  grid-template-columns: auto 1fr; gap: 4px 16px; }
.provenance dt { color: var(--muted); }
.provenance dd { margin: 0; font-family: var(--mono); font-size: 12px; word-break: break-all; }

.panels { display: grid; grid-template-columns: minmax(0, 5fr) minmax(0, 4fr); gap: 24px; margin-top: 20px; }
.panel h2 { font: 600 13px/1.4 var(--mono); margin: 0 0 8px; }
.panel .hint { font-size: 13px; color: var(--muted); margin: -2px 0 8px; }

.scroll { max-height: 62vh; overflow: auto; border: 1px solid var(--line); }

.panel.events { margin-top: 22px; }
.panel.events .scroll { max-height: 30vh; }
.panel.events .unnamed { color: var(--muted); }
.panel.events .displacement { color: var(--accent); }

/* Cross-dimensional rules, hidden entirely on the corpora that have none so the
   pane is never an empty promise. */
.panel.crossdim { margin-top: 22px; }
.panel.crossdim[hidden] { display: none; }
.panel.crossdim .scroll { max-height: 34vh; }
.panel.crossdim .unnamed { color: var(--warn); }

/* The sets the correspondences do not explain. Shorter than the panels above
   it because it is read from the top: the ranking is the point, not the tail. */
.panel.residue { margin-top: 22px; }
.panel.residue .scroll { max-height: 34vh; }
.panel.residue tr.apart td { color: var(--warn); }
.panel.residue td.z, .panel.residue td.cost, .panel.residue td.conf {
  text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap;
}
.panel.residue td.conf { color: var(--muted); }
/* The confidence column is hidden on an unweighted corpus, where every set is
   at 1.0 and the column carries nothing. */
table.classes.hide-conf .conf-col { display: none; }

/* The filter and chips above the classes table. A chip shows its state with
   the accent; there is no other decoration. */
.table-tools {
  display: flex; align-items: center; gap: 6px 12px; flex-wrap: wrap;
  margin: -2px 0 8px;
}
.table-tools input {
  font: 13px/1.5 var(--mono); padding: 4px 8px; border: 1px solid var(--line);
  border-radius: 0; background: var(--bg); color: var(--ink); min-width: 200px; flex: 1;
}
.table-tools input:focus { border-color: var(--ink); outline: none; }
.chips { display: flex; gap: 4px; flex-wrap: wrap; }
.chip {
  font: 12.5px var(--mono); padding: 2px 8px; border: 1px solid var(--line);
  border-radius: 0; background: var(--bg); color: var(--muted); cursor: pointer;
}
.chip:hover { border-color: var(--ink); color: var(--ink); }
.chip.on { border-color: var(--accent); color: var(--accent); }
.table-tools .count { font-size: 12px; color: var(--muted); font-family: var(--mono);
  font-variant-numeric: tabular-nums; margin-left: auto; }

th.sortable { cursor: pointer; user-select: none; }
th.sortable:hover { color: var(--ink); }
th.sortable.num { text-align: right; }
/* The arrow the current sort draws, so the direction is not a guess. */
th.sorted::after { content: " ▲"; font-size: 10px; color: var(--accent); }
th.sorted.desc::after { content: " ▼"; }

/* An empty row after filtering: not the same as a corpus that found nothing,
   so it says the filter is what emptied the table. */
tr.no-match td { color: var(--muted); text-align: center; padding: 18px; }

table.classes { width: 100%; border-collapse: collapse; font-size: 13.5px; }
table.classes th {
  position: sticky; top: 0; background: var(--bg); text-align: left;
  font: 600 12px/1.4 var(--mono); color: var(--muted);
  padding: 7px 10px; border-bottom: 1px solid var(--line); z-index: 1;
}
table.classes td { padding: 6px 10px; border-bottom: 1px solid var(--line); vertical-align: top; }
table.classes tr { cursor: pointer; }
table.classes tr:hover td { background: var(--hover); }
table.classes tr.selected td { background: var(--accent-soft); box-shadow: inset 2px 0 0 var(--accent); }
/* Dimmed, not erased: 0.35 dropped the un-selected rows below a legible
   contrast, so a reader scanning for the selection lost the rest of the table.
   0.55 keeps them readable while the selection still stands out. */
table.classes tr.dimmed { opacity: 0.55; }
td.corr { font-family: var(--mono); white-space: nowrap; }
td.count, td.sets { font-family: var(--mono); text-align: right; width: 1%; }
td.sets { color: var(--muted); }
.env { display: block; font-size: 12px; color: var(--muted); font-family: var(--mono);
  white-space: normal; margin-top: 3px; }

/* The caret that opens a row's evidence drawer. Sits before the correspondence,
   quiet until hovered, and does not select the row. */
.caret {
  border: 0; background: none; color: var(--muted); cursor: pointer;
  font-size: 11px; padding: 0 6px 0 0; line-height: 1;
}
.caret:hover { color: var(--accent); }

/* The evidence drawer: a full-width row under the class it belongs to, set off
   from the table by a left rule in the accent so it reads as attached to the
   row above rather than as another class. */
tr.evidence-row td { background: var(--accent-soft); padding: 0; border-bottom: 1px solid var(--line); }
.evidence { padding: 10px 14px 12px 24px; border-left: 2px solid var(--accent);
  font-size: 13px; display: grid; gap: 4px; }
.ev-line { font-family: var(--mono); font-size: 12px; color: var(--muted); }
.ev-score { color: var(--ink); }
.ev-stands { color: var(--accent); font-weight: 600; }
.ev-within { color: var(--muted); }
.ev-unmeasured { color: var(--muted); font-style: italic; }
.ev-confound { color: var(--warn); }
.ev-sets { display: flex; gap: 8px; align-items: baseline; white-space: normal; }
.ev-sets span { flex: 1; word-break: break-word; }
.ev-copy {
  border: 1px solid var(--line); background: var(--bg); color: var(--muted);
  font: inherit; font-size: 11px; padding: 1px 8px; border-radius: 0; cursor: pointer;
  white-space: nowrap;
}
.ev-copy:hover { border-color: var(--accent); color: var(--accent); }

/* The rate a class applies at and the interval around it. The bar sits on a
   0-1 track so intervals compare down the column; it goes muted for the Wilson
   default and takes the accent once bootstrap has resampled it, which is the
   one visible sign the option did anything. */
td.rate { width: 128px; }
td.rate .point { font-family: var(--mono); font-variant-numeric: tabular-nums;
  font-size: 12px; color: var(--muted); }
.ci { position: relative; display: block; height: 3px; margin-top: 5px;
  background: var(--line); }
.ci-bar { position: absolute; top: 0; bottom: 0; background: var(--muted); opacity: 0.5; }
.ci.boot .ci-bar { background: var(--accent); opacity: 0.75; }
.ci-tick { position: absolute; top: -2px; width: 2px; height: 7px;
  background: var(--ink); transform: translateX(-1px); }

/* The lect-pair selector above the alignments, shown only past two lects. */
.lect-pair-wrap { display: flex; align-items: center; gap: 8px; margin: -2px 0 8px; }
.lect-pair-wrap[hidden] { display: none; }
.lect-pair-wrap label { font-size: 12.5px; color: var(--muted); font-family: var(--mono); }
#lect-pair { max-width: 220px; }

.alignments { padding: 4px 0; }
.alignment { padding: 7px 12px; border-bottom: 1px solid var(--line); }
.alignment.hidden { display: none; }
.alignment .gloss { font-size: 12px; color: var(--muted); font-family: var(--mono); }
.alignment .pair { font-size: 11px; color: var(--muted); font-family: var(--mono); }
.cols { display: flex; gap: 3px; margin-top: 4px; flex-wrap: wrap; }
.col {
  display: grid;
  grid-template-rows: auto auto;
  gap: 1px;
  padding: 2px 5px;
  border-radius: 0;
  font-family: var(--mono);
  font-size: 13px;
  border: 1px solid transparent;
  cursor: pointer;
}
.col span { text-align: center; min-width: 1ch; }
.col .b { color: var(--muted); }
.col.gap span { color: var(--line); }
.col:hover { border-color: var(--ink); }
.col.lit { background: var(--accent-soft); border-color: var(--accent); }
.col.lit .b { color: var(--ink); }

.empty { padding: 22px; color: var(--muted); font-size: 13.5px; text-align: center; }

/* ---- guide ----------------------------------------------------------- */

.guide {
  position: fixed; top: 0; right: 0; bottom: 0; width: min(560px, 92vw);
  background: var(--bg); border-left: 1px solid var(--line);
  transform: translateX(100%); transition: transform 150ms ease;
  display: flex; flex-direction: column; z-index: 20;
}
.guide.open { transform: none; }
.guide header { display: flex; align-items: center; gap: 10px; padding: 12px 18px;
  border-bottom: 1px solid var(--line); }
.guide header h2 { font: 600 14px/1.4 var(--mono); margin: 0; flex: 1; }
.guide .body { padding: 16px 18px; overflow: auto; flex: 1; }
.guide .body h3 { font: 600 14px/1.4 var(--mono); margin: 16px 0 6px; }
.guide .body pre { border: 1px solid var(--line);
  padding: 10px; overflow: auto; font-size: 12px; }
.guide .body code { font-family: var(--mono); font-size: 0.92em; }
.guide .steps { display: flex; gap: 6px; padding: 10px 18px; border-top: 1px solid var(--line);
  flex-wrap: wrap; }
.guide .steps button { padding: 3px 8px; font-size: 12px; font-family: var(--mono); }
.guide .steps button.current { background: var(--accent); border-color: var(--accent); color: var(--bg); }

/* ---- empty-state onboarding ------------------------------------------ */

/* Before the first run the results area carries the boundary and the three
   steps; it is replaced by results, not stacked above them. */
.empty-state { margin-top: 20px; }
.empty-state[hidden] { display: none; }
.empty-state .status-banner { margin-top: 0; }
.empty-state .boundary { margin-top: 18px; }

.steps-guide {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px;
  margin: 22px 0 0; padding-top: 18px; border-top: 1px solid var(--line);
}
.steps-guide .step .n { font: 600 12px/1 var(--mono); color: var(--accent); }
.steps-guide .step h3 { margin: 6px 0 3px; font: 600 13px/1.3 var(--mono); }
.steps-guide .step p { margin: 0; font-size: 13px; color: var(--muted); }

/* ---- results tabs ---------------------------------------------------- */

.tabs {
  display: flex; gap: 2px; margin: 16px 0 0; border-bottom: 1px solid var(--line);
  overflow-x: auto; scrollbar-width: thin;
}
.tabs button {
  font: 13px var(--mono); white-space: nowrap; padding: 8px 12px;
  border: 0; border-bottom: 2px solid transparent; background: none; color: var(--muted); cursor: pointer;
}
.tabs button:hover { color: var(--ink); }
.tabs button.on { color: var(--accent); border-bottom-color: var(--accent); }
.tabs button[hidden] { display: none; }
.tabs button .c {
  color: var(--muted); font-size: 11px; font-variant-numeric: tabular-nums;
  margin-left: 4px; padding: 0 4px; border: 1px solid var(--line);
}
.tabs button.on .c { color: var(--accent); border-color: var(--accent); }

.tabpane { display: none; margin-top: 18px; }
.tabpane.on { display: block; }
.tabpane .panel + .panel { margin-top: 22px; }

.download-bar { margin-top: 22px; padding-top: 12px; border-top: 1px solid var(--line); }
.download-note { margin-top: 6px; }
.stats-empty { font-size: 13.5px; color: var(--muted); margin: 4px 0 0; }
.stats-empty:empty { display: none; }

/* ---- alignments tab -------------------------------------------------- */

.aln-head { display: flex; align-items: center; gap: 12px; margin: 2px 0 8px; flex-wrap: wrap; }
.aln-head .spacer { flex: 1; }
.aln-view { display: inline-flex; border: 1px solid var(--line); }
.aln-view button {
  font: 12.5px var(--mono); padding: 3px 10px; border: 0; border-right: 1px solid var(--line);
  background: var(--bg); color: var(--muted); cursor: pointer;
}
.aln-view button:last-child { border-right: 0; }
.aln-view button.on { background: var(--accent); border-color: var(--accent); color: var(--bg); }

/* The banner naming the current selection, and the way back to all sets. */
.aln-selection {
  display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap;
  margin: 0 0 10px; padding: 8px 12px; background: var(--accent-soft);
  box-shadow: inset 2px 0 0 var(--accent); font-size: 13px;
}
.aln-selection[hidden] { display: none; }
.aln-selection .aln-sel-label { font-family: var(--mono); font-size: 12.5px; }
.aln-selection .aln-sel-clear {
  margin-left: auto; font: 12.5px var(--mono); color: var(--link);
  border: 0; background: none; padding: 0; cursor: pointer;
}
.aln-selection .aln-sel-clear:hover { text-decoration: underline; }

/* The alignments list is the scroll surface itself now that it fills a tab. */
.alignments {
  max-height: 66vh; overflow: auto; border: 1px solid var(--line); padding: 2px 0;
}
.alignments .alignment { overflow-x: auto; }

/* The ribbon is the default; columns are the compact toggle over the same data. */
.alignments .ribbon { display: block; }
.alignments .alignment .cols { display: none; }
.alignments.show-cols .ribbon { display: none; }
.alignments.show-cols .alignment .cols { display: flex; }

/* ---- the ribbon ------------------------------------------------------ */

svg.ribbon { display: block; margin: 4px 0 2px; }
svg.ribbon text { font-family: var(--mono); }
.rib-ch { fill: var(--bg); stroke: var(--line); }
.rib-ch.chg { fill: var(--accent-soft); stroke: var(--accent); }
.rib-tx { fill: var(--ink); font-size: 13px; }
.rib-tx.b { fill: var(--muted); }
.rib-nul { fill: var(--muted); font-size: 13px; }
.rib-brk { fill: none; stroke: var(--accent); stroke-width: 1.3; }
.ln { fill: none; stroke: var(--muted); stroke-width: 1.4; opacity: 0.75; }
.ln.chg { stroke: var(--accent); stroke-width: 1.6; opacity: 1; }
.ln.gap { stroke: var(--muted); stroke-dasharray: 2 3; opacity: 0.8; }

/* A ribbon link is operable like a column: it reveals its class. Its whole
   group lights when its class is selected. */
.rib-link { cursor: pointer; }
.rib-link:hover .rib-ch { stroke: var(--ink); }
.rib-link.lit .rib-ch { stroke: var(--accent); fill: var(--accent-soft); }
.rib-link.lit .rib-tx.b { fill: var(--ink); }
.rib-link.lit .ln { stroke: var(--accent); opacity: 1; }
/* When something is selected, the alignments are already filtered to the sets
   that realise it; within a shown set the un-selected links stay quiet. */
.alignments .alignment .rib-link:not(.lit) { opacity: 1; }

@media (max-width: 900px) {
  .boundary { grid-template-columns: 1fr; }
  .boundary section { padding: 0; }
  .boundary section + section { border-left: 0; padding-left: 0; border-top: 1px solid var(--line); padding-top: 14px; margin-top: 14px; }
  .steps-guide { grid-template-columns: 1fr; gap: 14px; }
  .alignments { max-height: none; }
}
