/* CCM Network Lab — application shell, controls, and canvas viewport.
 *
 * Layout contract: the page is a viewport-height flex column
 * (topbar / shell / footer).  The shell is a grid of controls + workspace, and
 * the workspace is a flex column whose canvas is the only element that
 * absorbs leftover space.  Every ancestor of the canvas therefore sets
 * `min-height:0` so the flex/grid automatic minimum size cannot push the
 * canvas past the fold.  The canvas is absolutely positioned inside its wrap
 * so its intrinsic size never feeds back into layout.
 */

/* ---------------------------------------------------------------- tokens - */

:root {
  font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  color-scheme: dark;

  --bg: #0b1020;
  --panel: #11192b;
  --panel-2: #17223a;
  --border: #263653;
  --text: #e8eef9;
  --muted: #91a0bb;
  --accent: #7c8cff;
  --accent-2: #39d3b4;
  --warn: #f6b44f;
  --danger: #ff7183;
  --canvas: #0e1628;
  --shadow: 0 16px 45px #0005;

  /* Chrome heights are tokens so the drawer and any offset math stay in sync
   * with the real bars instead of repeating magic numbers. */
  --topbar-h: 64px;
  --footer-h: 41px;

  --sidebar-w: clamp(288px, 21vw, 352px);
  --workspace-pad: clamp(18px, 3vw, 38px);
  --workspace-gap: 15px;

  /* Floor for the canvas.  Capped against the viewport so a short window
   * shrinks the canvas instead of overflowing the page. */
  --canvas-min: min(440px, 46vh);
}

html[data-theme="light"] {
  color-scheme: light;
  --bg: #f4f7fb;
  --panel: #fff;
  --panel-2: #f0f4fa;
  --border: #d8e0ec;
  --text: #182237;
  --muted: #60708a;
  --canvas: #fbfcfe;
  --shadow: 0 16px 45px #31415b1c;
}

/* ------------------------------------------------------------------ base - */

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  background-image:
    radial-gradient(circle at 80% -10%, #586bda24, transparent 40%),
    radial-gradient(#ffffff08 1px, transparent 1px);
  background-size: auto, 24px 24px;

  /* A definite height, not min-height: the shell below resolves `flex:1`
   * against it, and without it the grid row sizes to the tall controls column
   * and pushes the canvas past the fold.  dvh keeps that height inside the
   * visible area when a mobile URL bar is showing; vh is the fallback.
   * Each column scrolls itself, so the page never does. */
  height: 100vh;
  height: 100dvh;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

button,
input,
select {
  font: inherit;
}

button {
  cursor: pointer;
}

button:disabled {
  cursor: not-allowed;
  opacity: .42;
}

/* ---------------------------------------------------------------- topbar - */

.topbar {
  flex: 0 0 auto;
  height: var(--topbar-h);
  padding: 0 clamp(16px, 3vw, 42px);
  border-bottom: 1px solid var(--border);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  background: color-mix(in srgb, var(--panel) 88%, transparent);
  backdrop-filter: blur(12px);
  position: sticky;
  top: 0;
  z-index: 5;
}

.brand {
  display: flex;
  align-items: baseline;
  gap: 9px;
  font-weight: 700;
  letter-spacing: .02em;
  min-width: 0;
}

.brand > span {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.brand small {
  color: var(--muted);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: .08em;
  text-transform: uppercase;
  white-space: nowrap;
}

.brand-mark {
  color: var(--accent-2);
  font-size: 24px;
  flex: 0 0 auto;
}

.top-actions {
  display: flex;
  align-items: center;
  gap: 10px;
  flex: 0 0 auto;
}

.top-nav {
  display: flex;
  align-items: center;
  gap: 2px;
  padding-right: 10px;
  border-right: 1px solid var(--border);
}

.engine-state {
  font-size: 12px;
  color: var(--muted);
  white-space: nowrap;
}

.engine-state.ready {
  color: var(--accent-2);
}

.engine-state.error {
  color: var(--danger);
}

.icon-button {
  border: 1px solid var(--border);
  background: var(--panel-2);
  color: var(--text);
  border-radius: 9px;
  width: 34px;
  height: 34px;
  flex: 0 0 auto;
}

/* ----------------------------------------------------------------- shell - */

.app-shell {
  flex: 1 1 auto;
  min-height: 0;
  display: grid;
  grid-template-columns: minmax(0, var(--sidebar-w)) minmax(0, 1fr);
  grid-template-rows: minmax(0, 1fr);
  /* Neither column may push the pair wider than the shell. */
  max-width: 100%;
  overflow: hidden;
}

/* The panel is a column of three: heading, a scrolling body, and a run bar
 * pinned to the bottom so "Run simulation" never scrolls out of reach. */
.controls {
  min-height: 0;
  min-width: 0;
  background: color-mix(in srgb, var(--panel) 95%, transparent);
  border-right: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.controls-body {
  flex: 1 1 auto;
  min-height: 0;
  overflow: auto;
  overscroll-behavior: contain;
  padding: 0 20px 12px;
}

.run-bar {
  flex: 0 0 auto;
  padding: 14px 20px 16px;
  border-top: 1px solid var(--border);
  background: var(--panel);
  box-shadow: 0 -10px 24px #0002;
}

.panel-scrim {
  display: none;
}

.panel-heading {
  flex: 0 0 auto;
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 12px;
  padding: 22px 20px 16px;
}

.eyebrow {
  color: var(--accent-2);
  font-size: 10px;
  font-weight: 750;
  letter-spacing: .15em;
  margin: 0 0 6px;
}

.panel-heading h1,
.workspace-head h2 {
  font-size: 20px;
  line-height: 1.2;
  margin: 0;
}

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

/* Sidebar tabs: run parameters and the algorithm notes share the panel. */
.panel-tabs {
  flex: 0 0 auto;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 4px;
  margin: 0 20px 12px;
  padding: 3px;
  border: 1px solid var(--border);
  border-radius: 9px;
  background: var(--panel-2);
}

.panel-tab {
  border: 0;
  border-radius: 6px;
  background: transparent;
  color: var(--muted);
  font-size: 12px;
  font-weight: 650;
  padding: 7px 8px;
  cursor: pointer;
}

.panel-tab:hover {
  color: var(--text);
}

.panel-tab[aria-selected="true"] {
  background: var(--accent);
  color: #fff;
}

.tab-pane[hidden] {
  display: none;
}

/* Each pane opens directly under the tabs, so its first rule is redundant. */
.tab-pane > .control-section:first-child {
  border-top: 0;
  padding-top: 4px;
}

/* The setup pane runs slightly smaller than the rest of the page so every
 * section, through saved executions, fits a laptop-height panel. */
#paramsPane .control-section {
  padding: 12px 0 6px;
}

#paramsPane .control-section h2 {
  font-size: 11px;
  margin-bottom: 6px;
}

#paramsPane .control-section label {
  font-size: 11px;
  gap: 4px;
  margin: 7px 0;
}

#paramsPane input[type=number],
#paramsPane select {
  font-size: 12.5px;
  padding: 6px 8px;
}

#paramsPane .two-col {
  row-gap: 0;
}

#paramsPane .secondary {
  padding: 8px 10px;
  font-size: 11.5px;
}

#paramsPane .help-note {
  font-size: 11px;
}

.control-section {
  border-top: 1px solid var(--border);
  padding: 16px 0 10px;
  min-width: 0;
}

.control-section h2 {
  display: flex;
  align-items: center;
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: .11em;
  color: var(--muted);
  margin: 0 0 12px;
}

/* Numbered steps: the sections read top to bottom in the order a run is set up. */
.step {
  display: inline-grid;
  place-items: center;
  width: 18px;
  height: 18px;
  margin-right: 8px;
  border-radius: 50%;
  border: 1px solid var(--accent);
  color: var(--accent);
  font-size: 10px;
  letter-spacing: 0;
}

.control-section label {
  position: relative;
  display: flex;
  flex-direction: column;
  min-width: 0;
  gap: 6px;
  font-size: 12px;
  color: var(--muted);
  margin: 10px 0;
}

/* The live slider value sits on the label's own line.  Taking it out of flow
 * beats the negative-margin pull it replaces: the range input below keeps its
 * natural position at every width. */
.control-section label > output {
  position: absolute;
  top: 0;
  right: 0;
  color: var(--text);
  font-size: 11px;
}

/* auto-fit collapses these to one column when the panel is narrow, so no
 * breakpoint has to know how many fields a row holds. */
.two-col {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(118px, 1fr));
  gap: 10px;
}

.two-col label {
  min-width: 0;
}

input[type=number],
select {
  width: 100%;
  border: 1px solid var(--border);
  border-radius: 7px;
  background: var(--panel-2);
  color: var(--text);
  padding: 8px 9px;
  outline: none;
}

input:focus,
select:focus,
button:focus-visible {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px #7c8cff30;
  outline: none;
}

input[type=range] {
  accent-color: var(--accent);
  width: 100%;
  /* The UA stylesheet puts a 2px margin on inputs. Combined with width:100%
     that is wider than the container, which gave the control panel a permanent
     horizontal scrollbar. */
  margin: 0;
  min-width: 0;
}

.checks {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(112px, 1fr));
  gap: 10px;
}

.checks label {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 7px;
  margin: 0;
  color: var(--text);
  font-size: 12px;
}

.checks input {
  accent-color: var(--accent);
  flex: 0 0 auto;
}

.file-actions {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
  gap: 8px;
  margin-bottom: 12px;
}

/* Run takes the width; the second button only needs to be findable. */
.run-actions {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 8px;
}

.run-actions .secondary {
  padding-inline: 18px;
}

.primary,
.secondary {
  border: 1px solid transparent;
  border-radius: 8px;
  padding: 10px 12px;
  font-size: 12px;
  font-weight: 700;
}

.primary {
  background: var(--accent);
  color: #fff;
}

.primary:hover {
  filter: brightness(1.1);
}

.secondary {
  background: var(--panel-2);
  color: var(--text);
  border-color: var(--border);
}

.secondary:hover {
  border-color: var(--accent);
}

.file-button {
  text-align: center;
  cursor: pointer;
}

.file-button input {
  display: none;
}

.message {
  min-height: 2.9em;
  margin: 10px 0 0;
  color: var(--muted);
  font-size: 12px;
  line-height: 1.45;
}

.message.error {
  color: var(--danger);
}

.message.busy {
  color: var(--warn);
}
/* ------------------------------------------------------------ dashboard --- */

.text-link {
  color: var(--muted);
  text-decoration: none;
  font-size: 12px;
  padding: 6px 10px;
  border-radius: 8px;
  border: 1px solid var(--border);
  white-space: nowrap;
}

.text-link:hover {
  color: var(--text);
  border-color: var(--accent);
}

/* The chart needs less height than the network view; the table below it gets
   the remainder. */
.chart-wrap {
  flex: 1 1 auto;
  min-height: min(340px, 42vh);
}

.chart-legend {
  flex: 0 0 auto;
  display: flex;
  flex-wrap: wrap;
  gap: 8px 18px;
  font-size: 11px;
  color: var(--muted);
}

.chart-legend span {
  display: inline-flex;
  align-items: center;
  gap: 7px;
}

.swatch {
  display: inline-block;
  width: 10px;
  height: 10px;
  border-radius: 3px;
  flex: 0 0 auto;
}

/* The table is the relief for the light-mode contrast warning on three series
   slots, and the form numbers are actually read from. It scrolls in its own
   box so a wide sweep never widens the page. */
.results-scroll {
  flex: 0 1 auto;
  min-height: 0;
  overflow: auto;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--panel);
}

.results-table table {
  border-collapse: collapse;
  width: 100%;
  font-size: 11.5px;
}

.results-table th,
.results-table td {
  padding: 7px 12px;
  text-align: right;
  white-space: nowrap;
  border-bottom: 1px solid var(--border);
}

.results-table thead th {
  position: sticky;
  top: 0;
  background: var(--panel-2);
  color: var(--muted);
  font-weight: 600;
  text-align: right;
}

/* The first column holds names, not numbers, in both the head and the body. */
.results-table thead th:first-child {
  text-align: left;
}

.results-table tbody th {
  text-align: left;
  font-weight: 600;
  color: var(--text);
  display: flex;
  align-items: center;
  gap: 8px;
}

.results-table td {
  color: var(--text);
  font-variant-numeric: tabular-nums;
}

/* A run that hit its round limit did not disperse; its number is a floor, not
   a cost, and the chart draws the same point hollow. */
.results-table td.capped {
  color: var(--warn);
}

.results-table td.capped::after {
  content: "*";
}

.results-table tbody tr:last-child th,
.results-table tbody tr:last-child td {
  border-bottom: 0;
}

/* The simulator's comparison table: short, under the legend, so the canvas
   keeps most of the height. The loaded row is marked. */
.compare-panel {
  max-height: 28vh;
}

.results-table tr.selected th,
.results-table tr.selected td {
  background: var(--panel-2);
}

.results-table .row-play {
  border: 1px solid var(--border);
  background: var(--panel-2);
  color: var(--text);
  border-radius: 6px;
  padding: 3px 10px;
  font-size: 11px;
  cursor: pointer;
}

@media (max-width: 900px) {
  .chart-wrap {
    min-height: min(300px, 46vh);
  }
}
/* ---------------------------------------------------------- docs page --- */

/* Kind colours for the flowcharts: the shape icon, the bar and the tint of a
   card all take --kind from its k-* class. */
:root {
  --k-entry: var(--accent);
  --k-step: #8b98b3;
  --k-decision: var(--warn);
  --k-end: var(--accent-2);
  --k-aside: #7f8aa3;
  --lane: #ffffff06;
  --lane-alt: #ffffff0c;
  --edge: #50607e;
  --yes: var(--accent-2);
  --card: var(--panel-2);
  --card-shadow: #0006;
  --code-bg: #0c1424;
  --tk-kw: #c4a5ff;
  --tk-ty: #5eead4;
  --tk-fn: #93b4ff;
  --tk-str: #fbbf77;
  --tk-num: #fdba74;
  --tk-com: #6f7c96;
  --tk-attr: #d8b4fe;
}

html[data-theme="light"] {
  --k-step: #6b778f;
  --k-decision: #b87a0d;
  --k-end: #0f9e82;
  --k-aside: #7a8499;
  --lane: #18223708;
  --lane-alt: #1822370f;
  --edge: #a3adbf;
  --yes: #0f9e82;
  --card: #fff;
  --card-shadow: #31415b26;
  --code-bg: #f6f8fc;
  --tk-kw: #7c3aed;
  --tk-ty: #0f766e;
  --tk-fn: #1d4ed8;
  --tk-str: #b45309;
  --tk-num: #c2410c;
  --tk-com: #8792a8;
  --tk-attr: #7c3aed;
}

.docs-main {
  flex: 1 1 auto;
  min-height: 0;
  display: grid;
  grid-template-columns: 264px minmax(0, 1fr) 0;
  transition: grid-template-columns .18s ease;
}

.docs-body.has-detail .docs-main {
  grid-template-columns: 264px minmax(0, 1fr) min(440px, 34vw);
}

.docs-nav,
.docs-content,
.docs-detail {
  min-height: 0;
  overflow-y: auto;
}

/* --- left column: the simulator, the charts, the legend --- */
.docs-nav {
  border-right: 1px solid var(--border);
  padding: 18px 14px;
  background: color-mix(in srgb, var(--panel) 70%, transparent);
}

.sim-card {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px;
  margin-bottom: 20px;
  border-radius: 12px;
  background: var(--accent);
  color: #fff;
  text-decoration: none;
  box-shadow: var(--shadow);
}

.sim-card:hover {
  filter: brightness(1.08);
}

.sim-card-icon {
  flex: none;
  width: 32px;
  height: 32px;
  border-radius: 9px;
  display: grid;
  place-items: center;
  background: #fff3;
  font-size: 12px;
}

.sim-card-title {
  display: block;
  font-weight: 700;
}

.sim-card-sub {
  display: block;
  font-size: 12px;
  opacity: .85;
  margin-top: 1px;
}

.nav-title {
  margin: 6px 8px 8px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--muted);
}

.nav-title:not(:first-of-type) {
  margin-top: 24px;
}

.nav-item {
  display: flex;
  gap: 10px;
  padding: 9px 8px;
  border-radius: 10px;
  color: var(--text);
  text-decoration: none;
}

.nav-item:hover {
  background: var(--panel-2);
}

.nav-item[aria-current="page"] {
  background: color-mix(in srgb, var(--accent) 16%, transparent);
}

.nav-num {
  flex: none;
  width: 22px;
  height: 22px;
  border-radius: 7px;
  display: grid;
  place-items: center;
  font-size: 12px;
  font-weight: 700;
  background: var(--panel-2);
  color: var(--muted);
}

.nav-item[aria-current="page"] .nav-num {
  background: var(--accent);
  color: #fff;
}

.nav-name {
  display: block;
  font-weight: 650;
}

.nav-short {
  display: block;
  font-size: 12px;
  color: var(--muted);
  margin-top: 1px;
}

.legend-list {
  list-style: none;
  margin: 0;
  padding: 0 8px;
  display: grid;
  gap: 8px;
  font-size: 12.5px;
  color: var(--muted);
}

.legend-list li {
  display: flex;
  align-items: center;
  gap: 10px;
}

.docs-body .tag {
  width: 18px;
  text-align: center;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 10px;
  font-weight: 700;
  color: var(--accent);
}

.nav-foot {
  margin: 24px 8px 0;
  font-size: 12px;
  line-height: 1.5;
  color: var(--muted);
}

/* --- middle column: one chart --- */
.docs-content {
  padding: 22px clamp(16px, 2.4vw, 32px) 40px;
}

.chart-head .eyebrow {
  margin: 0;
}

.chart-head h1 {
  margin: 4px 0 8px;
  font-size: 22px;
  letter-spacing: -.01em;
}

.blurb {
  max-width: 82ch;
  margin-bottom: 14px;
  font-size: 13.5px;
  line-height: 1.6;
  color: var(--muted);
}

.blurb p,
.blurb ul {
  margin: 0 0 8px;
}

.blurb code,
.notes code,
.detail-desc code,
.eyebrow code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: .92em;
  color: var(--text);
}

.stage-wrap {
  position: relative;
  height: calc(100vh - 250px);
  height: calc(100dvh - 250px);
  min-height: 440px;
  border: 1px solid var(--border);
  border-radius: 16px;
  background: var(--canvas);
  box-shadow: var(--shadow);
  overflow: hidden;
}

.stage {
  width: 100%;
  height: 100%;
  cursor: grab;
  touch-action: none;
}

.stage.panning {
  cursor: grabbing;
}

.stage .chart {
  display: block;
  width: 100%;
  height: 100%;
}

.stage-tools {
  position: absolute;
  left: 10px;
  right: 10px;
  bottom: 10px;
  display: flex;
  align-items: center;
  gap: 6px;
  pointer-events: none;
}

.stage-tools > * {
  pointer-events: auto;
}

.stage-tools .primary {
  border: 0;
  border-radius: 8px;
  padding: 8px 12px;
  font-size: 12px;
  font-weight: 700;
}

.stage-hint {
  margin: 0 auto;
  max-width: 55%;
  padding: 5px 12px;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: color-mix(in srgb, var(--panel) 85%, transparent);
  color: var(--muted);
  font-size: 11.5px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  pointer-events: none !important;
}

.stage-tools .secondary {
  padding: 8px 12px;
}

.zoom-level {
  min-width: 48px;
  padding: 7px 4px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--panel-2);
  color: var(--muted);
  font-size: 12px;
  text-align: center;
  font-variant-numeric: tabular-nums;
}

.notes {
  margin-top: 16px;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--panel);
}

.notes summary {
  cursor: pointer;
  padding: 10px 14px;
  font-weight: 650;
}

.notes ul {
  margin: 0;
  padding: 0 18px 12px 32px;
  color: var(--muted);
  line-height: 1.6;
  font-size: 13px;
}

.notes li + li {
  margin-top: 4px;
}

/* --- diagram marks, written against the theme tokens --- */
.chart text {
  font-family: Inter, ui-sans-serif, system-ui, sans-serif;
  fill: var(--text);
}

.chart .lane {
  fill: var(--lane);
}

.chart .lane.alt {
  fill: var(--lane-alt);
}

.chart .lane-label {
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: .1em;
  fill: var(--muted);
}

.chart .edge {
  fill: none;
  stroke: var(--edge);
  stroke-width: 1.6;
  transition: stroke .12s, opacity .12s;
}

.chart .edge.e-yes {
  stroke: var(--yes);
}

.chart .edge.e-no {
  stroke-dasharray: 5 4;
}

.chart .edge.e-aside {
  stroke-dasharray: 2 4;
  stroke-width: 1.3;
}

.chart .ah {
  fill: var(--edge);
}

.chart .ah-yes {
  fill: var(--yes);
}

.chart .ah-hot {
  fill: var(--accent);
}

.chart .chip rect {
  fill: var(--panel);
  stroke: var(--border);
}

.chart .chip text {
  font-size: 11px;
  font-weight: 650;
  fill: var(--muted);
  text-anchor: middle;
}

.chart .chip.c-yes rect {
  stroke: var(--yes);
}

.chart .chip.c-yes text {
  fill: var(--yes);
}

.chart .node {
  cursor: pointer;
  outline: none;
  transition: opacity .12s;
}

.chart .card {
  fill: var(--card);
  stroke: var(--border);
  stroke-width: 1;
  filter: drop-shadow(0 1px 1.5px var(--card-shadow)) drop-shadow(0 4px 10px var(--card-shadow));
}

.chart .bar {
  fill: var(--kind);
}

.chart .title {
  font-size: 13px;
  font-weight: 650;
}

.chart .sub {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 11.2px;
  fill: var(--muted);
}

.ic {
  fill: color-mix(in srgb, var(--kind) 18%, transparent);
  stroke: var(--kind);
  stroke-width: 1.3;
}

.chart .code-tag rect {
  fill: color-mix(in srgb, var(--accent) 16%, transparent);
}

.chart .code-tag text {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 9.5px;
  font-weight: 700;
  fill: var(--accent);
  text-anchor: middle;
}

.k-entry { --kind: var(--k-entry); }
.k-step { --kind: var(--k-step); }
.k-decision { --kind: var(--k-decision); }
.k-end { --kind: var(--k-end); }
.k-aside { --kind: var(--k-aside); }

.chart .k-entry .card { fill: color-mix(in srgb, var(--k-entry) 9%, var(--card)); }
.chart .k-decision .card { fill: color-mix(in srgb, var(--k-decision) 8%, var(--card)); }
.chart .k-end .card { fill: color-mix(in srgb, var(--k-end) 9%, var(--card)); }
.chart .k-aside .card { fill: transparent; stroke-dasharray: 5 4; filter: none; }

.chart .node:hover .card,
.chart .node:focus-visible .card {
  stroke: var(--kind);
  stroke-width: 1.8;
}

.chart .node.selected .card {
  stroke: var(--accent);
  stroke-width: 2.6;
}

/* Hovering or selecting a box brings it and its connections forward. */
.stage.focusing .node:not(.hot),
.stage.focusing .edge:not(.hot),
.stage.focusing .chip:not(.hot) {
  opacity: .28;
}

.chart .edge.hot {
  stroke: var(--accent);
  stroke-width: 2.2;
}

/* --- right column: the box being read --- */
.docs-detail {
  border-left: 1px solid var(--border);
  background: var(--panel);
  padding: 18px 18px 30px;
}

.docs-body:not(.has-detail) .docs-detail {
  visibility: hidden;
  padding: 0;
  border: 0;
}

.detail-empty {
  margin-top: 40px;
  padding: 0 20px;
  text-align: center;
  color: var(--muted);
  line-height: 1.55;
}

.detail-empty-title {
  color: var(--text);
  font-size: 15px;
  font-weight: 700;
}

.detail-head {
  display: flex;
  align-items: center;
  gap: 8px;
}

.docs-body .spacer {
  flex: 1;
}

.kind-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 10px 3px 8px;
  border-radius: 999px;
  color: var(--kind);
  background: color-mix(in srgb, var(--kind) 15%, transparent);
  font-size: 11.5px;
  font-weight: 700;
}

.kind-chip::before {
  content: "";
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--kind);
}

.tour-ctl {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  padding: 2px;
  border: 1px solid var(--border);
  border-radius: 9px;
}

.tour-ctl .num {
  min-width: 46px;
  text-align: center;
  color: var(--muted);
  font-size: 12px;
  font-variant-numeric: tabular-nums;
}

.tour-btn {
  width: 28px;
  height: 28px;
  border: 0;
  border-radius: 7px;
  background: transparent;
  color: var(--text);
  font-size: 18px;
  line-height: 1;
}

.tour-btn:hover:not(:disabled) {
  background: var(--panel-2);
}

.docs-detail h2 {
  margin: 16px 0 2px;
  font-size: 18px;
  letter-spacing: -.01em;
}

.detail-sub {
  margin: 0;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 12px;
  color: var(--muted);
}

.detail-desc {
  font-size: 13.5px;
  line-height: 1.6;
}

.detail-links {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  margin: 4px 0 16px;
}

.detail-links .dir {
  margin-right: 2px;
  color: var(--muted);
  font-size: 11.5px;
}

.detail-links button {
  padding: 5px 10px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--panel-2);
  color: var(--text);
  font-size: 12px;
}

.detail-links button:hover {
  border-color: var(--accent);
}

.code-head {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 8px 10px;
  border: 1px solid var(--border);
  border-bottom: 0;
  border-radius: 10px 10px 0 0;
  background: var(--panel-2);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 11.5px;
  color: var(--muted);
}

.code-head .secondary {
  padding: 5px 10px;
  font-family: Inter, ui-sans-serif, system-ui, sans-serif;
  text-decoration: none;
}

#d_file {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  direction: rtl;
  text-align: left;
}

.code {
  margin: 0;
  padding: 10px 0;
  max-height: 58vh;
  overflow: auto;
  border: 1px solid var(--border);
  border-radius: 0 0 10px 10px;
  background: var(--code-bg);
  font: 12px/1.6 ui-monospace, SFMono-Regular, Menlo, monospace;
}

.code code {
  display: block;
  min-width: max-content;
  counter-reset: ln var(--start, 0);
  /* The line breaks between lines are there for copying; each line is its
     own block, so they must not render. */
  white-space: normal;
}

.code .line {
  display: block;
  padding-right: 14px;
  white-space: pre;
}

.code .line::before {
  counter-increment: ln;
  content: counter(ln);
  display: inline-block;
  width: 42px;
  margin-right: 14px;
  padding-right: 10px;
  border-right: 1px solid var(--border);
  color: var(--muted);
  text-align: right;
  user-select: none;
}

.code .kw { color: var(--tk-kw); }
.code .ty { color: var(--tk-ty); }
.code .fn { color: var(--tk-fn); }
.code .str { color: var(--tk-str); }
.code .num { color: var(--tk-num); }
.code .com { color: var(--tk-com); font-style: italic; }
.code .attr { color: var(--tk-attr); }

@media (max-width: 1180px) {
  .docs-main {
    grid-template-columns: 228px minmax(0, 1fr) 0;
  }

  .docs-body.has-detail .docs-main {
    grid-template-columns: 228px minmax(0, 1fr) 360px;
  }
}

@media (max-width: 900px) {
  /* One column: the page scrolls instead of each column scrolling itself. */
  body.docs-body {
    height: auto;
    min-height: 100vh;
    overflow: visible;
  }

  .docs-main,
  .docs-body.has-detail .docs-main {
    display: block;
  }

  .docs-nav {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
    border-right: 0;
    border-bottom: 1px solid var(--border);
    padding: 10px;
  }

  .docs-nav .nav-title,
  .legend-list,
  .nav-foot,
  .nav-short,
  .sim-card-sub {
    display: none;
  }

  .sim-card {
    width: 100%;
    margin-bottom: 6px;
    padding: 8px 12px;
  }

  .docs-detail {
    border-left: 0;
    border-top: 1px solid var(--border);
  }

  .docs-body:not(.has-detail) .docs-detail {
    display: none;
  }

  .stage-wrap {
    height: 70vh;
  }
}

/* ----------------------------------------------------------- glossary --- */

.glossary summary {
  cursor: pointer;
  padding: 7px 0;
  font-size: 12px;
  font-weight: 650;
  color: var(--text);
  list-style: none;
  display: flex;
  align-items: center;
  gap: 7px;
}

/* Replace the default marker with one that rotates, so the control reads the
   same in every browser. */
.glossary summary::-webkit-details-marker {
  display: none;
}

.glossary summary::before {
  content: "\25b8";
  color: var(--accent-2);
  transition: transform .15s ease;
  flex: 0 0 auto;
}

.glossary details[open] > summary::before {
  transform: rotate(90deg);
}

.glossary details {
  border-bottom: 1px solid var(--border);
}

.glossary details:last-of-type {
  border-bottom: 0;
}

.glossary details > div {
  padding: 0 0 12px 16px;
}

.glossary p {
  margin: 0 0 8px;
  font-size: 11.5px;
  line-height: 1.55;
  color: var(--muted);
}

.glossary p:last-child {
  margin-bottom: 0;
}

.glossary b {
  color: var(--text);
  font-weight: 650;
}

.glossary code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 10.5px;
  padding: 1px 4px;
  border-radius: 4px;
  background: var(--panel-2);
  border: 1px solid var(--border);
  color: var(--text);
  white-space: nowrap;
}

.glossary-intro {
  margin-bottom: 10px;
}

.glossary-note {
  font-size: 10.5px;
  opacity: .82;
}

/* Links out to the documentation. They sit inside muted note text, so they
   carry the accent to stay findable without shouting. */
.glossary a,
.help-note a {
  color: var(--accent);
  text-decoration: none;
  border-bottom: 1px solid transparent;
}

.glossary a:hover,
.help-note a:hover {
  border-bottom-color: currentColor;
}

@media (prefers-reduced-motion: reduce) {
  .glossary summary::before {
    transition: none;
  }
}

.help-note {
  font-size: 11px;
  line-height: 1.45;
  color: var(--muted);
  opacity: .85;
}

/* ------------------------------------------------------------- workspace - */

.workspace {
  min-width: 0;
  min-height: 0;
  overflow: auto;
  display: flex;
  flex-direction: column;
  padding: var(--workspace-pad);
  gap: var(--workspace-gap);
}

.workspace-head {
  flex: 0 0 auto;
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: 12px 20px;
}

.workspace-head h2 {
  font-size: clamp(20px, 3vw, 29px);
}

.metrics {
  display: flex;
  flex-wrap: wrap;
  gap: clamp(12px, 3vw, 28px);
}

.metrics span {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
}

.metrics b {
  font-size: 17px;
  color: var(--accent-2);
}

.metrics small {
  color: var(--muted);
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: .08em;
}

/* -------------------------------------------------- canvas viewport ----- */

/* The only element that grows.  `min-height:0` is deliberately absent here:
 * --canvas-min is the floor, and it is viewport-relative so it can never
 * demand more room than the workspace has. */
.canvas-wrap {
  position: relative;
  flex: 1 1 auto;
  min-height: var(--canvas-min);
  border: 1px solid var(--border);
  border-radius: 14px;
  background: var(--canvas);
  box-shadow: var(--shadow);
  overflow: hidden;
}

/* Absolute so the canvas bitmap never contributes intrinsic height back to
 * the flex column.  Rust sizes the backing store from the wrap's client rect. */
.canvas-wrap canvas {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
}

.empty-state {
  position: absolute;
  inset: 0;
  display: grid;
  place-content: center;
  text-align: center;
  color: var(--muted);
  pointer-events: none;
  padding: 16px;
}

.empty-state h3 {
  color: var(--text);
  margin: 10px 0 3px;
}

.empty-state p {
  font-size: 12px;
  margin: 0;
}

.empty-icon {
  font-size: 48px;
  line-height: 1;
  color: var(--accent);
  opacity: .7;
}

.tooltip {
  position: absolute;
  z-index: 2;
  max-width: 230px;
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--panel);
  box-shadow: var(--shadow);
  font-size: 11px;
  line-height: 1.55;
  pointer-events: none;
}

/* -------------------------------------------------- playback and legend - */

/* Flex rather than a fixed grid: the frame counter drops to its own line
 * before the transport buttons or the scrubber are squeezed. */
.playback {
  flex: 0 0 auto;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
}

.playback button {
  border: 1px solid var(--border);
  background: var(--panel-2);
  color: var(--text);
  border-radius: 7px;
  height: 34px;
  width: 38px;
  font-size: 20px;
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  padding: 0;
}

.playback #play {
  width: 42px;
}

.playback > input {
  accent-color: var(--accent);
  flex: 1 1 140px;
  min-width: 0;
}

.playback > span {
  font-size: 11px;
  color: var(--muted);
  white-space: nowrap;
}

/* Speed lives with the transport it controls rather than in the setup panel. */
.speed {
  flex: 0 1 230px;
  display: flex;
  align-items: center;
  gap: 8px;
  margin-left: auto;
  padding-left: 12px;
  border-left: 1px solid var(--border);
  font-size: 11px;
  color: var(--muted);
  white-space: nowrap;
}

.speed output {
  color: var(--text);
  min-width: 46px;
}

.speed input {
  flex: 1 1 80px;
  min-width: 60px;
}

/* Legend on the left, view toggles on the right: both describe the canvas. */
.view-bar {
  flex: 0 0 auto;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 10px 24px;
  padding-top: 10px;
  border-top: 1px solid var(--border);
}

.view-filters {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px 14px;
  font-size: 12px;
}

.view-filters-title {
  color: var(--muted);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
}

.view-filters label {
  display: flex;
  align-items: center;
  gap: 6px;
  color: var(--text);
  cursor: pointer;
  white-space: nowrap;
}

.view-filters input {
  accent-color: var(--accent);
  margin: 0;
}

/* One line naming the step and phase of the frame on screen. Kept to its own
 * row, and reserved even when empty, so the canvas does not jump. */
.phase-label {
  flex: 0 0 auto;
  margin: 0;
  min-height: 1.4em;
  font-size: 12px;
  color: var(--text);
  font-variant-numeric: tabular-nums;
}

.legend {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 16px;
  color: var(--muted);
  font-size: 11px;
  flex-wrap: wrap;
}

.dot {
  display: inline-block;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  margin-right: 5px;
}

.dot.settled {
  background: var(--accent-2);
}

.dot.waiting {
  background: var(--warn);
}

.dot.unsettled {
  background: var(--danger);
}

.dot.home {
  background: transparent;
  border: 1.5px dashed var(--warn);
}

.dot.probing {
  background: transparent;
  border: 2px solid #7c8cff;
}

.probe-info {
  flex: 1 1 100%;
  color: var(--muted);
  font-size: 12px;
  min-height: 1em;
}

.compare {
  display: grid;
  gap: 6px;
}

.compare .hint,
#placementNote {
  margin: 0;
  color: var(--muted);
  font-size: 11px;
}

.compare-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 11px;
}

.compare-table th,
.compare-table td {
  padding: 3px 4px;
  text-align: left;
  border-bottom: 1px solid rgba(127, 127, 127, .25);
}

.legend-tip {
  font-style: italic;
  opacity: .85;
}

/* ---------------------------------------------------------------- footer - */

footer {
  flex: 0 0 auto;
  height: var(--footer-h);
  border-top: 1px solid var(--border);
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 4px;
  color: var(--muted);
  font-size: 11px;
  padding: 0 12px;
  text-align: center;
}

footer a {
  color: var(--accent);
}

/* ------------------------------------------------------------- utilities - */

.hidden {
  display: none !important;
}

.mobile-only {
  display: none;
}

/* ========================================================= floating lab = */

/* Main page on a desktop-sized screen: the dotted backdrop runs edge to edge
 * and every piece of chrome floats on it as a card.  The canvas wrap is the
 * box between those cards, not the whole screen, so the graph layout - which
 * Rust fits to the wrap - never puts a node underneath one.  These queries
 * are the exact complement of drawer mode below, which takes over unchanged. */
@media (min-width: 1025px), (min-width: 901px) and (min-height: 561px) {
  body.lab {
    --float-gap: 12px;
    --bar-h: 46px;
    --float-bg: color-mix(in srgb, var(--panel) 90%, transparent);
    display: block;
  }

  .lab .float-card,
  .lab .topbar,
  .lab .controls,
  .lab .workspace-head,
  .lab .playback,
  .lab .legend,
  .lab .view-filters,
  .lab .phase-label,
  .lab .compare-panel {
    background: var(--float-bg);
    border: 1px solid var(--border);
    border-radius: 12px;
    box-shadow: var(--shadow);
    backdrop-filter: blur(10px);
  }

  /* RootedDisp's step notes and the comparison table float like the bars
   * around them; the note shows only once there is a frame to describe. */
  .lab .phase-label {
    align-self: flex-start;
    max-width: 100%;
    padding: 6px 12px;
    min-height: 0;
  }

  .lab .phase-label:empty {
    display: none;
  }

  /* Toolbar: a pill in the top-left corner rather than a full-width bar. */
  .lab .topbar {
    position: fixed;
    top: var(--float-gap);
    left: var(--float-gap);
    height: var(--bar-h);
    padding: 0 8px 0 14px;
    gap: 14px;
    justify-content: flex-start;
    border-bottom: 1px solid var(--border);
  }

  .lab .brand {
    align-items: center;
    font-size: 14px;
    gap: 8px;
  }

  .lab .brand-mark {
    font-size: 18px;
  }

  .lab .brand small {
    display: none;
  }

  .lab .top-actions {
    gap: 8px;
  }

  .lab .top-nav {
    border-right: 0;
    padding-right: 0;
    border-left: 1px solid var(--border);
    padding-left: 10px;
  }

  .lab .top-nav .text-link {
    font-size: 12px;
  }

  .lab .icon-button {
    width: 30px;
    height: 30px;
    border-radius: 8px;
  }

  .lab footer {
    display: none;
  }

  .lab .app-shell {
    display: block;
  }

  /* Settings: a card under the toolbar, as tall as its content and never
   * taller than the screen; the body inside it scrolls. */
  .lab .controls {
    position: fixed;
    z-index: 4;
    top: calc(var(--float-gap) * 2 + var(--bar-h) - 2px);
    left: var(--float-gap);
    width: var(--sidebar-w);
    max-height: calc(100vh - var(--bar-h) - var(--float-gap) * 3);
    max-height: calc(100dvh - var(--bar-h) - var(--float-gap) * 3);
    overflow: hidden;
  }

  .lab .panel-heading {
    padding: 14px 16px 10px;
  }

  .lab .panel-heading .eyebrow {
    display: none;
  }

  .lab .panel-heading h1 {
    font-size: 14px;
  }

  .lab .panel-tabs {
    margin: 0 16px 8px;
  }

  .lab .controls-body {
    padding: 0 16px 8px;
  }

  .lab .run-bar {
    padding: 12px 16px;
    background: transparent;
    box-shadow: none;
  }

  .lab .message {
    min-height: 0;
    margin-top: 8px;
  }

  /* Everything right of the settings card: stats on top, the canvas, then the
   * transport and the legend along the bottom. */
  .lab .workspace {
    position: fixed;
    top: var(--float-gap);
    right: var(--float-gap);
    bottom: var(--float-gap);
    left: calc(var(--sidebar-w) + var(--float-gap) * 2);
    padding: 0;
    gap: 10px;
    display: flex;
    flex-direction: column;
  }

  /* Stats: a pill in the top-right corner, level with the toolbar.  It keeps
   * to the right so the toolbar can extend over the canvas column. */
  .lab .workspace-head {
    flex: 0 0 var(--bar-h);
    align-self: flex-end;
    max-width: calc(100% - 250px);
    min-width: 0;
    display: flex;
    align-items: center;
    gap: 18px;
    padding: 0 16px;
  }

  .lab .workspace-head > div:first-child {
    min-width: 0;
  }

  .lab .workspace-head .eyebrow {
    display: none;
  }

  .lab .workspace-head h2 {
    font-size: 13px;
    font-weight: 650;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  .lab .metrics {
    flex: 0 0 auto;
    flex-wrap: nowrap;
    gap: 16px;
    padding-left: 16px;
    border-left: 1px solid var(--border);
  }

  .lab .metrics span {
    flex-direction: row;
    align-items: baseline;
    gap: 5px;
  }

  .lab .metrics b {
    font-size: 14px;
  }

  .lab .metrics small {
    order: -1;
    font-size: 10px;
  }

  /* The canvas sits straight on the backdrop: no frame, no fill. */
  .lab .canvas-wrap {
    min-height: 0;
    border: 0;
    border-radius: 0;
    background: transparent;
    box-shadow: none;
    overflow: visible;
  }

  .lab .playback {
    flex-wrap: nowrap;
    padding: 6px 12px 6px 6px;
    gap: 8px;
  }

  .lab .playback button {
    height: 32px;
    width: 34px;
    font-size: 18px;
    border-color: transparent;
    background: transparent;
  }

  .lab .playback #play {
    width: 64px;
    background: var(--accent);
    color: #fff;
    font-size: 14px;
  }

  .lab .playback #play:disabled {
    background: var(--panel-2);
    color: var(--muted);
  }

  .lab .speed {
    flex: 0 0 210px;
  }

  .lab .view-bar {
    border-top: 0;
    padding: 0;
    flex-wrap: nowrap;
    gap: 10px;
  }

  .lab .legend,
  .lab .view-filters {
    padding: 8px 14px;
    flex-wrap: nowrap;
    min-width: 0;
  }

  /* The hint text is the part that gives way, so the filters never get
   * pushed off screen by a long message. */
  .lab .legend {
    flex: 0 1 auto;
  }

  .lab .legend > span:not(.legend-tip) {
    flex: 0 0 auto;
    white-space: nowrap;
  }

  .lab .legend-tip {
    min-width: 0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  .lab .view-filters {
    flex: 0 0 auto;
  }

  .lab .view-filters {
    gap: 12px;
    overflow-x: auto;
  }
}

/* Laptop widths: the run title gives way before the counters do. */
@media (min-width: 1025px) and (max-width: 1280px),
  (min-width: 901px) and (max-width: 1024px) and (min-height: 561px) {
  .lab .workspace-head > div:first-child,
  .lab .legend-tip {
    display: none;
  }

  .lab .metrics {
    border-left: 0;
    padding-left: 0;
  }

  .lab .view-bar {
    flex-wrap: wrap;
  }
}

/* ============================================================ breakpoints = */

/* Compact desktop: reclaim workspace width before the sidebar has to go. */
@media (max-width: 1180px) {
  :root {
    --sidebar-w: 272px;
    --workspace-gap: 12px;
  }

  .metrics {
    gap: 16px;
  }

  .metrics b {
    font-size: 15px;
  }
}

/* Drawer mode.  Two triggers: narrow viewports, and short-and-not-wide ones
 * (landscape phones), where a permanent 272px sidebar would leave nothing.
 * 900px keeps 768px tablet portrait out of the old cramped two-column zone. */
@media (max-width: 900px), (max-width: 1024px) and (max-height: 560px) {
  :root {
    --topbar-h: 58px;
    --canvas-min: min(300px, 40vh);
  }

  .mobile-only {
    display: block;
  }

  .brand small {
    display: none;
  }

  .engine-state {
    display: none;
  }

  .app-shell {
    display: block;
  }

  .controls {
    position: fixed;
    z-index: 10;
    left: 0;
    top: var(--topbar-h);
    bottom: 0;
    width: min(330px, 92vw);
    border-right: 1px solid var(--border);
    background: var(--panel);
    transform: translateX(-102%);
    transition: transform .2s ease;
    box-shadow: var(--shadow);
  }

  .controls.open {
    transform: translateX(0);
  }

  /* Dismiss target for the drawer; only exists while the drawer is open. */
  .panel-scrim.open {
    display: block;
    position: fixed;
    inset: var(--topbar-h) 0 0 0;
    z-index: 9;
    background: #05080f80;
    backdrop-filter: blur(2px);
  }

  /* The workspace is no longer a grid child, so it needs the viewport height
   * relationship restated to keep the canvas inside the fold. */
  /* The shell is no longer a grid here, so the workspace has to restate its
     own height. Definite, not a minimum: the canvas is the flex child that
     absorbs whatever the surrounding controls leave, and against a minimum it
     could only grow, which pushed the footer off screen. */
  .workspace {
    height: calc(100vh - var(--topbar-h) - var(--footer-h));
    height: calc(100dvh - var(--topbar-h) - var(--footer-h));
    min-height: 0;
    overflow: auto;
    padding: 18px 14px;
  }

  .workspace-head {
    align-items: flex-start;
    flex-direction: column;
  }

  .metrics {
    width: 100%;
    justify-content: space-between;
  }

  .metrics span {
    align-items: flex-start;
  }

  .top-nav {
    padding-right: 4px;
  }

  .view-bar {
    flex-direction: column;
    align-items: flex-start;
  }
}

/* Phone: single-column controls and a full-width scrubber row.  The page
 * links need the topbar width more than the wordmark does, so only the mark
 * stays. */
@media (max-width: 560px) {
  .brand > span:not(.brand-mark) {
    display: none;
  }

  .top-nav {
    padding-right: 0;
    border-right: 0;
  }

  .top-nav .text-link {
    padding: 6px 7px;
  }

  :root {
    --canvas-min: min(240px, 34vh);
  }

  .workspace {
    padding: 14px 12px;
  }

  .two-col,
  .checks,
  .file-actions {
    grid-template-columns: 1fr;
  }

  .metrics {
    gap: 12px;
  }

  .metrics b {
    font-size: 14px;
  }

  .playback > input {
    flex: 1 1 100%;
    order: 1;
  }

  .playback > span {
    order: 2;
  }

  .speed {
    order: 3;
    flex: 1 1 100%;
    margin-left: 0;
    padding-left: 0;
    border-left: 0;
  }
}

/* Short viewports (landscape phones, split-screen): shed chrome so the
 * canvas keeps a usable share of the height. */
@media (max-height: 620px) {
  :root {
    --workspace-gap: 10px;
    --canvas-min: 180px;
  }

  .workspace {
    padding: 12px;
  }

  .workspace-head h2 {
    font-size: 18px;
  }

  .help-note {
    display: none;
  }

  .legend {
    gap: 12px;
  }
}

/* Landscape phones (~390px tall).  At this height the legend and the section
 * eyebrow cost more than they inform, and the canvas needs every pixel. */
@media (max-height: 480px) {
  :root {
    --workspace-gap: 8px;
    --canvas-min: 132px;
  }

  .workspace .eyebrow {
    display: none;
  }

  .workspace-head {
    gap: 8px 16px;
  }

  .legend {
    display: none;
  }
}

/* --------------------------------------------------- input and motion --- */

/* Touch pointers get 44px targets without inflating the mouse layout. */
@media (pointer: coarse) {
  .icon-button {
    width: 44px;
    height: 44px;
  }

  .playback button {
    height: 44px;
    width: 46px;
  }

  .playback #play {
    width: 52px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .controls {
    transition: none;
  }

  .panel-scrim.open {
    backdrop-filter: none;
  }
}
