/* Vivarium stylesheet — a dark, calm, faintly bioluminescent look.
   No frameworks; just hand-written CSS with a small custom-property palette. */

:root {
  --bg: #060a10;
  --bg-panel: #0c131c;
  --bg-panel-2: #111a26;
  --ink: #dce7f2;
  --ink-dim: #8299b0;
  --ink-faint: #5a6f85;
  --accent: #62c8ff;
  --accent-2: #5adc96;
  --line: #1b2836;
  --radius: 12px;
  /* The chart's y-axis gutter (v1.41). The three stacked figures share an
     x-axis, so they share this indent too — an axis that moved one of them
     would have split a figure the whole column reads as one. */
  --axis-gutter: 22px;
  --font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial,
    sans-serif;
  --mono: ui-monospace, "SF Mono", "JetBrains Mono", Menlo, Consolas, monospace;
}

* {
  box-sizing: border-box;
}

html,
body {
  margin: 0;
  padding: 0;
  background: radial-gradient(1200px 700px at 30% -10%, #0d1826 0%, var(--bg) 55%);
  color: var(--ink);
  font-family: var(--font);
  min-height: 100vh;
}

/* ---- Top bar ---- */
.topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 16px 22px;
  border-bottom: 1px solid var(--line);
  gap: 16px;
  flex-wrap: wrap;
}
.brand {
  display: flex;
  align-items: center;
  gap: 14px;
}
.logo {
  font-size: 34px;
  filter: drop-shadow(0 0 10px rgba(90, 220, 150, 0.5));
}
.brand h1 {
  margin: 0;
  font-size: 22px;
  letter-spacing: 0.5px;
}
.tagline {
  margin: 2px 0 0;
  color: var(--ink-dim);
  font-size: 13px;
}
.links {
  display: flex;
  gap: 18px;
}
.links a {
  color: var(--ink-dim);
  text-decoration: none;
  font-size: 14px;
  border-bottom: 1px solid transparent;
  transition: color 0.15s, border-color 0.15s;
}
.links a:hover {
  color: var(--accent);
  border-color: var(--accent);
}

/* ---- Scenarios strip ---- */
.scenarios {
  max-width: 1320px;
  margin: 0 auto;
  padding: 14px 22px 0;
  display: flex;
  align-items: center;
  gap: 12px;
}
.scenarios-label {
  color: var(--ink-dim);
  font-size: 13px;
  flex: 0 0 auto;
}
.scenario-chips {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}
.scenario-chips button {
  flex: 0 0 auto;
  background: var(--bg-panel);
  border: 1px solid var(--line);
  color: var(--ink);
  border-radius: 20px;
  padding: 6px 13px;
  font-size: 13px;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  transition: border-color 0.15s, background 0.15s, transform 0.05s;
}
.scenario-chips button:hover {
  border-color: var(--accent);
  background: var(--bg-panel-2);
}
.scenario-chips button:active {
  transform: translateY(1px);
}
.scenario-chips button.active {
  border-color: var(--accent);
  background: #12293a;
}

/* ---- Layout ---- */
.layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 320px;
  gap: 20px;
  padding: 20px 22px;
  align-items: start;
  max-width: 1320px;
  margin: 0 auto;
}
.left-col {
  display: flex;
  flex-direction: column;
  gap: 20px;
  min-width: 0;
}
/* Present to a screen reader, absent to everything else. The pond's spoken
   channel (see src/describe.js) has no visual form — the Chronicle feed below
   the canvas already shows a sighted reader the same lines. Clipped rather than
   `display: none`, which would remove it from the accessibility tree too. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  border: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
}

.stage {
  position: relative;
  border-radius: var(--radius);
  overflow: hidden;
  border: 1px solid var(--line);
  background: #04070b;
  box-shadow: 0 10px 40px rgba(0, 0, 0, 0.5), inset 0 0 60px rgba(10, 30, 50, 0.3);
}

/* ---- Chronicle ---- */
.chronicle {
  background: var(--bg-panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 14px 16px;
  display: flex;
  flex-direction: column;
  min-height: 200px;
}
.chronicle-head {
  display: flex;
  align-items: baseline;
  gap: 12px;
  flex-wrap: wrap;
  margin-bottom: 10px;
}
.chronicle-head h2 {
  margin: 0;
  font-size: 17px;
  font-weight: 600;
}
.chronicle-sub {
  color: var(--ink-faint);
  font-size: 12.5px;
}
.chronicle-feed {
  list-style: none;
  margin: 0;
  padding: 0;
  overflow-y: auto;
  max-height: 340px;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.chronicle-feed li {
  display: flex;
  align-items: baseline;
  gap: 10px;
  padding: 6px 8px;
  border-radius: 7px;
  font-size: 13.5px;
  color: var(--ink);
  border-left: 2px solid transparent;
}
.chronicle-feed li:nth-child(odd) {
  background: rgba(255, 255, 255, 0.018);
}
.chronicle-feed li.fresh {
  animation: chron-in 0.5s ease;
}
@keyframes chron-in {
  from {
    background: rgba(98, 200, 255, 0.16);
  }
}
.chronicle-feed .c-icon {
  font-size: 15px;
  flex: 0 0 auto;
}
.chronicle-feed .c-when {
  flex: 0 0 auto;
  font-family: var(--mono);
  font-size: 11px;
  color: var(--ink-faint);
  min-width: 62px;
}
.chronicle-feed .c-msg {
  flex: 1;
}
.chronicle-feed .chronicle-empty {
  color: var(--ink-faint);
  font-style: italic;
}
/* Category accents on the left border. */
.chronicle-feed li.cat-crash { border-left-color: #e0555f; }
.chronicle-feed li.cat-predation { border-left-color: #ff7a4d; }
.chronicle-feed li.cat-death { border-left-color: #b0524a; }
.chronicle-feed li.cat-lineage { border-left-color: #9a7bff; }
.chronicle-feed li.cat-pop { border-left-color: #62c8ff; }
.chronicle-feed li.cat-recover { border-left-color: #5adc96; }
.chronicle-feed li.cat-brain,
.chronicle-feed li.cat-learning { border-left-color: #78beff; }
.chronicle-feed li.cat-longevity { border-left-color: #d8c26a; }
.chronicle-feed li.cat-diversity { border-left-color: #5adc96; }
.chronicle-feed li.cat-night { border-left-color: #8a93e8; }
#world {
  display: block;
  max-width: 100%;
  height: auto;
  cursor: crosshair;
  /* Without this the browser owns every touch on the pond and the camera is
     unreachable on a phone: a pinch zooms the *page*, a drag scrolls it. But
     `none` everywhere would trap a reader behind a canvas that fills their
     screen, so the two states are split. At zoom 1 there is nothing to pan
     anyway, and `pan-y` keeps a one-finger swipe scrolling the page while still
     handing us anything multi-touch — which is how a pinch can get us out of
     zoom 1 in the first place. Once zoomed in, main.js swaps this for `none` so
     a drag pans in both axes. */
  touch-action: pan-y;
  /* A press-and-hold on a canvas otherwise raises a text-selection loupe. */
  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none;
}

/* ---- Panel ---- */
.panel {
  display: flex;
  flex-direction: column;
  gap: 16px;
}
.controls,
.stats,
.mortality,
.chartwrap,
.inspector {
  background: var(--bg-panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 14px;
}
.controls {
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.btn-row {
  display: flex;
  gap: 8px;
}
.kbd-hint {
  margin: 2px 0 0;
  font-size: 11.5px;
  line-height: 1.5;
  color: var(--ink-faint);
}
/* Two hints for the same four affordances, because "scroll to zoom" is not
   advice a phone can take. `pointer: coarse` is the input, not the screen
   width: a small window on a laptop still has a wheel. */
.coarse-only {
  display: none;
}
@media (pointer: coarse) {
  .fine-only {
    display: none;
  }
  .coarse-only {
    display: block;
  }
}
.kbd-hint kbd {
  font-family: var(--font);
  font-size: 11px;
  color: var(--ink-dim);
  background: var(--bg-panel-2);
  border: 1px solid var(--line);
  border-radius: 4px;
  padding: 0 4px;
}
button {
  flex: 1;
  background: var(--bg-panel-2);
  color: var(--ink);
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 9px 10px;
  font-size: 13px;
  font-family: var(--font);
  cursor: pointer;
  transition: background 0.15s, border-color 0.15s, transform 0.05s;
}
button:hover {
  background: #17222f;
  border-color: #29435c;
}
button:active {
  transform: translateY(1px);
}
button.primary {
  border-color: #2a5a7a;
  background: #12293a;
}
button.mini {
  flex: 0 0 auto;
  padding: 6px 9px;
}

.field {
  display: flex;
  flex-direction: column;
  gap: 6px;
  font-size: 13px;
  color: var(--ink-dim);
}
.field b {
  color: var(--ink);
  font-weight: 600;
}
.field .inline {
  display: flex;
  gap: 6px;
}
input[type="number"] {
  flex: 1;
  background: var(--bg);
  border: 1px solid var(--line);
  color: var(--ink);
  border-radius: 8px;
  padding: 8px;
  font-family: var(--mono);
}
input[type="range"] {
  width: 100%;
  accent-color: var(--accent);
}
.check {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  color: var(--ink-dim);
  cursor: pointer;
}
details {
  border-top: 1px solid var(--line);
  padding-top: 10px;
}
details summary {
  cursor: pointer;
  color: var(--ink-dim);
  font-size: 13px;
  margin-bottom: 8px;
  user-select: none;
}
details .field {
  margin-top: 10px;
}

/* ---- Stats grid ----
   A description list since v1.51: `dt` is the name, `dd` is the live number.
   The tiles look exactly as they did — the only thing that changed is that the
   pairing is now stated rather than implied by being adjacent. */
.stats {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 10px 8px;
  margin: 0;
}
.stat {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.stat dt {
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.6px;
  color: var(--ink-faint);
}
.stat dd {
  margin: 0;
  font-family: var(--mono);
  font-size: 16px;
  font-weight: 700;
  color: var(--ink);
}

/* ---- Mortality ---- */
.mortality {
  padding: 12px 14px;
}
.mort-head {
  font-size: 11px;
  color: var(--ink-dim);
  margin-bottom: 8px;
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 8px;
}
.mort-head span {
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.6px;
  color: var(--ink-faint);
}
/* Three segments in a row; widths are set from the death mix each frame, and a
   cause with no deaths collapses to nothing rather than leaving a sliver. */
.mort-bar {
  display: flex;
  height: 10px;
  border-radius: 5px;
  overflow: hidden;
  background: rgba(255, 255, 255, 0.06);
}
.mort-bar i {
  display: block;
  width: 0;
  transition: width 0.4s ease;
}
/* The three cause colours are not written here. They live in src/palette.js,
   where a test can measure them, and main.js paints them onto these segments —
   the bar and the chart's death strip are then the same three colours by
   construction rather than by two people remembering to update two files. */
.mort-legend {
  margin-top: 7px;
  font-size: 11px;
  color: var(--ink-faint);
  font-family: var(--mono);
}
.mort-legend b {
  color: var(--ink-dim);
  font-weight: 600;
}
/* The bar animates its widths; with reduced motion it just snaps. */
@media (prefers-reduced-motion: reduce) {
  .mort-bar i {
    transition: none;
  }
}

/* ---- Chart ---- */
.chartwrap {
  padding: 12px 14px;
}
.chart-legend {
  font-size: 11px;
  color: var(--ink-faint);
  margin-bottom: 6px;
  display: flex;
  align-items: center;
  gap: 6px;
}
.chart-legend .dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  display: inline-block;
}
.chart-legend .dot.pop {
  background: #78beff;
}
.chart-legend .dot.food {
  background: #5ac88c;
  margin-left: 8px;
}
.chart-legend .scope-btn {
  flex: 0 0 auto; /* the global button rule is flex:1; this one hugs its label */
  margin-left: auto;
  font: inherit;
  color: var(--ink-faint);
  background: transparent;
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 1px 8px;
  cursor: pointer;
}
.chart-legend .scope-btn:hover {
  color: var(--ink);
  border-color: var(--ink-faint);
}
.chart-legend .scope-btn[aria-pressed="true"] {
  color: #78beff;
  border-color: #78beff;
}
#chart {
  width: 100%;
  height: 90px;
  display: block;
}
/* The y-axis numbers (v1.41). They live in a gutter beside the plot rather than
   over it: a label on top of the figure covers whatever the pond was doing
   underneath, and this project's own rule is that nothing the pond did is
   hidden under a piece of furniture. They are DOM text, not canvas text (the
   backing store is stretched to the column's width, three times over on a
   phone), and they are positioned as a percentage of the plot's own height, so
   a label stays level with its gridline at any size. The colour is set from
   src/palette.js — the population line's, since these are its numbers. */
.chart-plot {
  position: relative;
  padding-left: var(--axis-gutter);
}
.chart-ticks {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: var(--axis-gutter);
  pointer-events: none;
  font-family: var(--mono);
  font-size: 9px;
  line-height: 1;
}
.chart-ticks span {
  position: absolute;
  right: 4px;
  white-space: nowrap;
  transform: translateY(-50%);
}
.chart-legend .scale {
  font-family: var(--mono);
  margin-left: 3px;
}
/* The death strip: same width and x-axis as the chart above it, sitting on the
   chart's baseline so the two read as one figure. */
.deaths-strip {
  width: calc(100% - var(--axis-gutter));
  margin-left: var(--axis-gutter);
  height: 24px;
  display: block;
  border-top: 1px solid var(--line);
}
.deaths-legend {
  font-size: 10px;
  color: var(--ink-faint);
  margin-top: 5px;
  display: flex;
  align-items: center;
  gap: 4px;
}
.deaths-legend .dot {
  width: 8px;
  height: 8px;
  border-radius: 2px;
  display: inline-block;
}
.deaths-legend .dot:not(:first-child) {
  margin-left: 6px;
}
/* The power strip sits under the death strip on the same x-axis, and its legend
   swatches are line segments rather than dots — the two lines it draws differ by
   being continuous and dashed, so the swatches have to as well. Both are painted
   from src/palette.js at startup. */
.power-strip {
  width: calc(100% - var(--axis-gutter));
  margin-left: var(--axis-gutter);
  height: 28px;
  display: block;
  border-top: 1px solid var(--line);
}
.deaths-legend .line {
  width: 14px;
  height: 2px;
  display: inline-block;
}
.deaths-legend .line:not(:first-child) {
  margin-left: 6px;
}
.deaths-legend b {
  margin-left: auto;
  font-weight: 500;
  font-family: var(--mono);
  color: var(--ink-faint);
}
.chart-range {
  margin-left: var(--axis-gutter);
}
.chart-range,
.phylo-range {
  font-size: 10px;
  color: var(--ink-faint);
  font-family: var(--mono);
  margin-top: 4px;
  min-height: 12px;
}

/* ---- Inspector ---- */
.inspector {
  min-height: 90px;
}
.inspector.empty .hint {
  color: var(--ink-faint);
  font-size: 13px;
  text-align: center;
  padding: 18px 8px;
}
.insp-row {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 10px;
}
.swatch {
  width: 14px;
  height: 14px;
  border-radius: 4px;
  display: inline-block;
  box-shadow: 0 0 8px currentColor;
}
/* A description list since v1.51, for the same reason the stats grid is one:
   every row here is a name and a value, and `dt`/`dd` is the pairing said out
   loud. `dd` carries the bold `b` used to bring with it. */
.insp-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
  margin: 0 0 12px;
}
.insp-grid div {
  display: flex;
  flex-direction: column;
}
.insp-grid .insp-wide {
  grid-column: 1 / -1;
}
.insp-grid dt {
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--ink-faint);
}
.insp-grid dd {
  margin: 0;
  font-family: var(--mono);
  font-size: 14px;
  font-weight: 700;
}
.insp-grid a {
  color: var(--accent);
  text-decoration: none;
}
.insp-grid a:hover {
  text-decoration: underline;
}
/* Ancestry chain: one pip per species in a creature's descent, tinted with
   that species' inherited hue. Extinct ancestors are hollow. */
.ancestry {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 3px;
  margin: 4px 0 0;
}
.anc {
  font-family: var(--mono);
  font-size: 11px;
  line-height: 1;
  padding: 3px 6px;
  border-radius: 20px;
  cursor: pointer;
  color: #06121c;
  background: hsl(var(--anc-hue), 70%, 62%);
  border: 1px solid hsl(var(--anc-hue), 70%, 62%);
  transition: box-shadow 0.15s, transform 0.15s;
}
.anc:hover {
  transform: translateY(-1px);
  box-shadow: 0 0 8px hsla(var(--anc-hue), 70%, 62%, 0.6);
}
.anc.gone {
  background: transparent;
  color: hsl(var(--anc-hue), 45%, 62%);
  border-style: dashed;
  border-color: hsla(var(--anc-hue), 45%, 62%, 0.6);
}
.anc.current {
  box-shadow: 0 0 0 2px var(--accent);
}
.anc-arrow {
  color: var(--ink-faint);
  font-size: 11px;
}
/* A caption, not a `label` — it names a figure, and the figure carries its own
   accessible name (v1.51). */
.brainwrap .fig-label {
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--ink-faint);
  display: block;
  margin: 0;
}
.brainwrap .learned-label {
  margin-top: 8px;
  color: var(--accent);
}
.braingraph {
  display: block;
  margin-top: 6px;
  /* Painted from src/palette.js at startup — see applyInspectorColours(). The
     literal here is the same colour, kept only so the plate is never white
     before the script runs. */
  background: var(--braingraph-bg, #05080d);
  border: 1px solid var(--line);
  border-radius: 8px;
}
.genome {
  display: flex;
  flex-wrap: wrap;
  gap: 1px;
  margin-top: 6px;
}
.genome span {
  width: 6px;
  height: 10px;
  border-radius: 1px;
  /* Each cell's bar and track arrive together as one gradient (v1.49) — this
     is only what an empty strip looks like. See src/palette.js weightMark(). */
  background: var(--insp-track, #142130);
}

/* The brain diagram's key. Three neuron roles and two connection signs, in the
   colours the diagram actually draws — v1.14's rule that a mechanic isn't
   finished until a watcher can tell what it is saying, applied to a figure
   that had been unlabelled since v1.5. */
.bg-key {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 10px;
  margin-top: 5px;
  font-size: 10px;
  color: var(--ink-dim);
}
.bg-chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
}
.bg-chip i {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  display: inline-block;
}
.bg-chip i.bg-pos,
.bg-chip i.bg-neg {
  width: 12px;
  height: 2px;
  border-radius: 0;
}
.bg-chip i.bg-pos {
  background: var(--weight-pos);
}
.bg-chip i.bg-neg {
  background: var(--weight-neg);
}

/* ---- Season badge ---- */
.season-badge {
  position: absolute;
  top: 12px;
  left: 12px;
  display: flex;
  align-items: center;
  gap: 7px;
  background: rgba(8, 14, 22, 0.72);
  border: 1px solid var(--line);
  color: var(--ink);
  padding: 5px 12px 5px 10px;
  border-radius: 20px;
  font-size: 12.5px;
  pointer-events: none;
  backdrop-filter: blur(3px);
}
.season-badge .icon {
  font-size: 15px;
}
.season-badge .tod {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding-left: 9px;
  margin-left: 2px;
  border-left: 1px solid var(--line);
}
.season-badge .yr {
  color: var(--ink-faint);
  font-family: var(--mono);
  font-size: 11px;
}

/* ---- Zoom / follow badge ----
   Only present while the view is something other than the whole pond, so the
   default screen stays as uncluttered as it has always been. */
.zoom-badge {
  position: absolute;
  top: 12px;
  right: 12px;
  display: flex;
  align-items: center;
  gap: 7px;
  background: rgba(8, 14, 22, 0.72);
  border: 1px solid var(--line);
  color: var(--ink);
  padding: 5px 12px 5px 10px;
  border-radius: 20px;
  font-size: 12.5px;
  font-family: var(--mono);
  pointer-events: none;
  backdrop-filter: blur(3px);
}
.zoom-badge.hidden {
  display: none;
}
.zoom-badge .following {
  padding-left: 9px;
  border-left: 1px solid var(--line);
  color: var(--ink-faint);
}

/* ---- Minimap ---- */
/* Only ever on screen while the view is zoomed in, so the default pond stays
   as uncluttered as it has always been. */
.minimap {
  position: absolute;
  left: 12px;
  bottom: 12px;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: rgb(7, 12, 19);
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.45);
  cursor: crosshair;
  touch-action: none;
}
.minimap.hidden {
  display: none;
}

/* ---- Flash message ---- */
.flash {
  position: absolute;
  left: 50%;
  bottom: 18px;
  transform: translateX(-50%) translateY(10px);
  background: rgba(10, 20, 30, 0.9);
  border: 1px solid var(--line);
  color: var(--ink);
  padding: 8px 16px;
  border-radius: 20px;
  font-size: 13px;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.25s, transform 0.25s;
}
.flash.show {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}

/* ---- Phylogeny / Tree of Life ---- */
.phylo {
  max-width: 1320px;
  margin: 4px auto 0;
  padding: 4px 22px 0;
}
.phylo-head {
  display: flex;
  align-items: center;
  gap: 14px;
}
.phylo-head h2 {
  margin: 0;
  font-size: 17px;
  font-weight: 600;
}
.phylo-info {
  color: var(--ink-dim);
  font-size: 13px;
  font-family: var(--mono);
}
.btn-clear {
  margin-left: auto;
}
.hidden {
  display: none !important;
}
.phylo-sub {
  color: var(--ink-faint);
  font-size: 12.5px;
  margin: 6px 0 10px;
  max-width: 780px;
  line-height: 1.5;
}
#muller {
  display: block;
  width: 100%;
  height: 170px;
  background: #04070b;
  border: 1px solid var(--line);
  border-radius: var(--radius);
}
/* An x-axis under a figure: the Tree of Life's (v1.54) and the population
   chart's (v1.58). The numbers are DOM text, positioned by fraction of the
   figure's width, because these canvases are stretched to whatever the column
   is and a stacked plot has no background for a gridline to sit on — see
   `mullerAxis` in src/mullerplot.js and `chartAxis` in src/chart.js. The Tree
   of Life's row is inset by the canvas's own 1px border, so half-way along it
   is half-way through the drawing. */
.phylo-ticks,
.chart-xticks {
  position: relative;
  height: 15px;
  margin: 0 1px;
  font-family: var(--mono);
  font-size: 9px;
  color: var(--ink-faint);
  pointer-events: none;
}
/* The population chart's x-axis (v1.58) is the same row of numbers under a
   different figure, so it shares every rule here and differs in one thing: it
   sits under three stacked canvases that are inset by the y-axis gutter, and it
   has to start and end exactly where they do or it labels the wrong columns. */
.chart-xticks {
  margin: 0 0 0 var(--axis-gutter);
}
.phylo-ticks span,
.chart-xticks span {
  position: absolute;
  top: 5px;
  white-space: nowrap;
  transform: translateX(-50%);
}
/* The mark: a short rule joining each number to the column it names, in the
   number's own colour so the two read as one thing. */
.phylo-ticks span::before,
.chart-xticks span::before {
  content: "";
  position: absolute;
  left: 50%;
  top: -5px;
  width: 1px;
  height: 4px;
  background: currentColor;
}
/* The end marks anchor to the figure's edges rather than to their own centres,
   so the first and last numbers stay inside it. */
.phylo-ticks .tick-start,
.chart-xticks .tick-start {
  transform: none;
}
.phylo-ticks .tick-start::before,
.chart-xticks .tick-start::before {
  left: 0;
}
.phylo-ticks .tick-end,
.chart-xticks .tick-end {
  transform: translateX(-100%);
}
.phylo-ticks .tick-end::before,
.chart-xticks .tick-end::before {
  left: auto;
  right: 0;
}
.legend {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 10px;
}
/* A `button` since v1.51 — it always behaved like one — which means the global
   `button { flex: 1 }` rule now reaches it and would stretch six chips across
   the whole width of the page. Same correction the scope button carries, for
   the same reason; the chip hugs its species name as it always did. */
.legend .chip {
  display: inline-flex;
  flex: 0 0 auto;
  align-items: center;
  gap: 6px;
  background: var(--bg-panel);
  border: 1px solid var(--line);
  border-radius: 20px;
  padding: 4px 10px 4px 6px;
  font-family: inherit;
  font-size: 12px;
  margin: 0;
  color: var(--ink-dim);
  cursor: pointer;
  transition: border-color 0.15s, background 0.15s;
  user-select: none;
}
.legend .chip:hover {
  border-color: #34506a;
  background: var(--bg-panel-2);
}
.legend .chip.active {
  border-color: var(--accent);
  color: var(--ink);
}
/* Two pixels wider than it was, so the band's hatch (v1.46) has room to show a
   direction. The background is written from `mullerplot.js#textureCss`. */
.legend .chip .dot {
  width: 14px;
  height: 14px;
  border-radius: 50%;
  box-shadow: 0 0 6px currentColor;
}
.legend .chip .n {
  font-family: var(--mono);
  color: var(--ink-faint);
}

/* ---- App page slim footer ---- */
.appfoot {
  max-width: 1320px;
  margin: 40px auto 0;
  padding: 20px 22px 44px;
  border-top: 1px solid var(--line);
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 12px;
  font-size: 13.5px;
  color: var(--ink-faint);
}
.appfoot .home-link {
  color: var(--accent);
  text-decoration: none;
  font-weight: 600;
}
.appfoot .home-link:hover {
  text-decoration: underline;
}
.appfoot-links a {
  color: var(--ink-dim);
  text-decoration: none;
}
.appfoot-links a:hover {
  color: var(--accent);
}

/* ---- Showcase / learn-more (legacy; kept for reference) ---- */
.learn {
  max-width: 1000px;
  margin: 0 auto;
  padding: 10px 22px 0;
}
.learn-hero {
  border-top: 1px solid var(--line);
  margin-top: 34px;
  padding-top: 48px;
  text-align: center;
}
.learn-hero h2 {
  font-size: clamp(24px, 4vw, 38px);
  margin: 0 0 18px;
  letter-spacing: 0.2px;
  background: linear-gradient(180deg, var(--ink) 0%, var(--accent) 220%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
.learn-hero p {
  max-width: 720px;
  margin: 0 auto;
  color: var(--ink-dim);
  font-size: 16px;
  line-height: 1.7;
}
.learn-hero strong,
.learn-block strong {
  color: var(--ink);
}
.learn-hero em,
.learn-block em {
  color: var(--accent-2);
  font-style: normal;
}
.learn-block {
  margin-top: 56px;
}
.learn-block h3 {
  font-size: 22px;
  margin: 0 0 18px;
  padding-bottom: 10px;
  border-bottom: 1px solid var(--line);
}
.learn-block .lead {
  color: var(--ink-dim);
  font-size: 15.5px;
  line-height: 1.7;
  max-width: 760px;
}
.learn-block p {
  color: var(--ink-dim);
  font-size: 15px;
  line-height: 1.7;
  max-width: 760px;
}
.learn-block a {
  color: var(--accent);
  text-decoration: none;
}
.learn-block a:hover {
  text-decoration: underline;
}

/* Feature cards */
.cards {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 14px;
}
.card {
  background: var(--bg-panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 18px;
  transition: border-color 0.15s, transform 0.15s;
}
.card:hover {
  border-color: #29435c;
  transform: translateY(-2px);
}
.card-ico {
  font-size: 24px;
  margin-bottom: 8px;
}
.card h4 {
  margin: 0 0 6px;
  font-size: 16px;
  color: var(--ink);
}
.card p {
  margin: 0;
  font-size: 13.5px;
  color: var(--ink-dim);
  line-height: 1.6;
}

/* How-it-works steps */
.steps {
  counter-reset: step;
  list-style: none;
  padding: 0;
  margin: 18px 0;
  display: grid;
  gap: 10px;
  max-width: 820px;
}
.steps li {
  position: relative;
  padding: 12px 14px 12px 52px;
  background: var(--bg-panel);
  border: 1px solid var(--line);
  border-radius: 10px;
  color: var(--ink-dim);
  font-size: 14.5px;
  line-height: 1.55;
}
.steps li b {
  color: var(--ink);
}
.steps li::before {
  counter-increment: step;
  content: counter(step);
  position: absolute;
  left: 14px;
  top: 12px;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  background: #12293a;
  border: 1px solid #2a5a7a;
  color: var(--accent);
  font-family: var(--mono);
  font-size: 13px;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* Version timeline */
.timeline {
  list-style: none;
  padding: 0;
  margin: 18px 0;
}
.timeline li {
  display: flex;
  gap: 16px;
  padding: 11px 0;
  border-bottom: 1px solid var(--line);
  align-items: baseline;
}
.timeline .v {
  flex: 0 0 46px;
  font-family: var(--mono);
  font-size: 13px;
  color: var(--accent);
}
.timeline .vt {
  color: var(--ink-dim);
  font-size: 14.5px;
  line-height: 1.55;
}
.timeline .vt b {
  color: var(--ink);
}

/* Roadmap list */
.road {
  padding-left: 0;
  list-style: none;
  margin: 16px 0;
  display: grid;
  gap: 10px;
  max-width: 820px;
}
.road li {
  padding: 12px 16px;
  background: var(--bg-panel);
  border: 1px solid var(--line);
  border-left: 3px solid #2a5a7a;
  border-radius: 8px;
  color: var(--ink-dim);
  font-size: 14px;
  line-height: 1.6;
}
.road li b {
  color: var(--ink);
}

/* ---- Footer ---- */
.foot {
  max-width: 1320px;
  margin: 56px auto 0;
  padding: 22px 0 48px;
  border-top: 1px solid var(--line);
  color: var(--ink-faint);
  font-size: 13.5px;
  line-height: 1.7;
}
.foot a {
  color: var(--ink-dim);
}
.foot a:hover {
  color: var(--accent);
}

/* ---- Responsive ---- */
@media (max-width: 960px) {
  .layout {
    grid-template-columns: 1fr;
  }
  .panel {
    order: 2;
  }
}
