/* The home page, built from Husky's design of 2026-10-14 (site/design/home-hero-source.png) with
   the changes he asked for: a smaller headline, the Lab example drawn as the Lab really is, its
   motion on a loop, the third fact (Access) taken out, and no Sample label, state or band box.
   Under it, the stages, the market data, the assistant and the connector, each from its own file
   in site/design/, all on the same loop.

   The example copies the Lab's own screens as they were on 2026-10-14: a project's header with its
   three tabs and the green line under the current one, the Workspace's editor and Result panel
   (metrics under dotted labels), and the Validation tab's Checklist (round marks, the band). Those
   marks belong to the product being shown. The site's own rule
   against a coloured dot beside a word is about this site's interface, not about a picture of the Lab.

   Only tokens from tokens.css. No gradient, blur or extra shadow: the Lab window is a floating
   window, so it takes --shadow-float, the one shadow a page may use for one. */

.home-page main.wrap {
  max-width: none;
  width: min(100%, 1344px);
  padding-inline: 32px;
  padding-block: 72px 96px;
}
/* The strip is not set here: site.css gives it one width on every page. No page has a footer,
   since 2026-10-14. */

/* --- the hero: the promise on the left, the Lab on the right ------------ */
.hero {
  display: grid;
  grid-template-columns: minmax(0, 30rem) minmax(0, 1fr);
  gap: 64px;
  align-items: center;
}
.hero-copy { min-width: 0; }
.hero-kicker, .home-kicker {
  margin: 0 0 18px;
  color: var(--muted);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
}
/* Smaller than the design's, which set five lines at about 88px. This sets three at 1440 wide. */
.hero h1 {
  margin: 0;
  color: var(--text);
  font-size: clamp(38px, 3.6vw, 52px);
  font-weight: var(--weight-semibold);
  letter-spacing: -0.045em;
  line-height: 1.02;
  text-wrap: balance;
}
.hero-lead {
  margin: 24px 0 0;
  max-width: 34em;
  color: var(--sec);
  font-size: 17px;
  line-height: 1.6;
  text-wrap: pretty;
}
.hero-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin: 32px 0 0;
}
.hero-facts {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  margin: 48px 0 0;
  padding-top: 18px;
  border-top: 1px solid var(--quiet);
}
.hero-facts > div { padding-right: 16px; }
.hero-facts > div + div { padding-left: 16px; border-left: 1px solid var(--quiet); }
.hero-facts dt { color: var(--muted); font-size: var(--text-sm); }
.hero-facts dd { margin: 4px 0 0; color: var(--text); font-size: var(--text-md); }

/* --- the Lab window ------------------------------------------------------ */
.lab-window {
  margin: 0;
  min-width: 0;
  background: var(--panel);
  border: 1px solid var(--chrome);
  border-radius: var(--radius-panel);
  box-shadow: var(--shadow-float);
  overflow: hidden;
  color: var(--text);
  font-size: var(--text-sm);
  line-height: var(--leading-normal);
}
.lab-dim { color: var(--muted); font-weight: var(--weight-regular); }

/* A project's header: its name and the three tabs. The Lab's data line under the name is left out,
   at Husky's word on 2026-10-14. */
.lab-head { padding: 16px 20px 0; background: var(--ground); border-bottom: 1px solid var(--line); }
.lab-title { display: flex; flex-wrap: wrap; align-items: baseline; column-gap: 14px; row-gap: 2px; }
.lab-name { font-size: var(--text-lg); font-weight: var(--weight-semibold); letter-spacing: -0.01em; }
.lab-tabs { display: flex; gap: 28px; margin-top: 12px; color: var(--muted); }
.lab-tab { display: flex; align-items: center; gap: 8px; padding: 8px 0 10px; border-bottom: 2px solid transparent; }
/* The finished state is Validation. The animation shows Workspace first. */
.tab-validation { color: var(--text); border-bottom-color: var(--accent); }
.lab-count {
  padding: 0 6px;
  border-radius: 4px;
  background: var(--active);
  color: var(--sec);
  font-size: var(--text-xs);
  line-height: 18px;
}

.lab-body {
  display: grid;
  grid-template-columns: minmax(0, 23rem) minmax(0, 1fr);
  gap: 12px;
  padding: 12px;
  background: var(--ground);
}
.lab-editor, .lab-result {
  min-width: 0;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius-surface);
  overflow: hidden;
}
.lab-pane-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  padding: 10px 14px;
  border-bottom: 1px solid var(--line);
}
.lab-pane-head b { font-weight: var(--weight-semibold); }

/* The editor: its file tab with the run arrow, the entrypoint line, the code. */
.lab-files { display: flex; padding: 8px 8px 0; border-bottom: 1px solid var(--line); }
.lab-file {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 6px 12px 7px;
  border: 1px solid var(--chrome);
  border-bottom: 0;
  border-top: 2px solid var(--accent);
  border-radius: var(--radius-control) var(--radius-control) 0 0;
  background: var(--panel);
}
.lab-file-name { display: grid; font-family: var(--mono); font-size: var(--text-xs); line-height: 1.35; }
.lab-file-role { color: var(--muted); }
.lab-run { width: 10px; height: 12px; fill: var(--accent); }
.lab-tag {
  padding: 1px 8px;
  border: 1px solid var(--line);
  border-radius: var(--radius-control);
  color: var(--muted);
  font-size: var(--text-xs);
}

/* Sized so the longest line fits its pane at 12px: no clipped line and no scrollbar. */
.code {
  margin: 0;
  padding: 12px 14px 16px;
  list-style: none;
  counter-reset: line;
  color: var(--sec);
  font-family: var(--mono);
  font-size: var(--text-xs);
  line-height: 1.9;
  overflow-x: auto;
}
.code li { white-space: pre; counter-increment: line; }
.code li::before {
  content: counter(line);
  display: inline-block;
  width: 2ch;
  margin-right: 14px;
  color: var(--faint);
  text-align: right;
}
.code .k, .code .f { color: var(--accent); }
.code .n { color: var(--stale); }
.code .c { color: var(--muted); font-style: italic; }

/* The Result panel: four of its metrics and its equity line. */

.lab-metrics {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  margin: 12px 12px 0;
  border: 1px solid var(--line);
  border-radius: var(--radius-surface);
}
.lab-metric { min-width: 0; padding: 10px 12px 12px; }
.lab-metric:nth-child(odd) { border-right: 1px solid var(--line); }
.lab-metric:nth-child(n + 3) { border-top: 1px solid var(--line); }
.lab-metric dt {
  color: var(--sec);
  font-size: var(--text-xs);
  text-decoration: underline dotted var(--faint-mark);
  text-underline-offset: 3px;
}
.lab-metric dd {
  margin: 4px 0 0;
  font-size: var(--text-xl);
  letter-spacing: -0.01em;
  font-variant-numeric: tabular-nums;
}
.lab-metric .is-up { color: var(--accent); }
.lab-metric .is-caution { color: var(--stale); }

.lab-chart-wrap { position: relative; height: 128px; margin: 12px 12px 12px; }
.lab-chart { display: block; width: calc(100% - 40px); height: 100%; overflow: visible; }
.lab-chart .grid { stroke: var(--quiet); stroke-width: 1; vector-effect: non-scaling-stroke; }
.lab-chart .equity-area { fill: color-mix(in srgb, var(--accent) 10%, transparent); }
.lab-chart .equity-line {
  fill: none;
  stroke: var(--accent);
  stroke-width: 1.75;
  stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
}
/* The axis on the right, as the Lab draws it. Its three values sit on the three grid lines. */
.lab-axis { position: absolute; inset: 0 0 0 auto; width: 34px; color: var(--muted); font-size: var(--text-xs); }
.lab-axis span { position: absolute; right: 0; transform: translateY(-50%); }
.lab-axis span:nth-child(1) { top: 6.7%; }
.lab-axis span:nth-child(2) { top: 42.8%; }
.lab-axis span:nth-child(3) { top: 78.9%; }

/* The Validation tab's Checklist. */
.lab-checklist { border-top: 1px solid var(--line); background: var(--panel); }
.lab-checklist-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  padding: 12px 20px;
  border-bottom: 1px solid var(--line);
}
.lab-checklist-head > b { font-weight: var(--weight-semibold); }
/* Plain words, no box around them: Husky's call on 2026-10-14. */
.lab-band {
  color: var(--sec);
  font-size: var(--text-xs);
  white-space: nowrap;
}
.lab-band b { margin: 0 4px; color: var(--stale); font-weight: var(--weight-semibold); }
.lab-band-count { color: var(--text); }

.lab-checks {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  margin: 0;
  padding: 0;
  list-style: none;
}
.lab-check {
  display: grid;
  grid-template-columns: 22px minmax(0, 1fr);
  column-gap: 10px;
  align-content: start;
  padding: 14px 14px 16px;
}
.lab-check + .lab-check { border-left: 1px solid var(--line); }
.lab-check .mark { grid-row: 1 / span 2; width: 22px; height: 22px; }
.check-name {
  font-weight: var(--weight-medium);
  text-decoration: underline dotted var(--faint-mark);
  text-underline-offset: 3px;
}
.check-status { margin-top: 2px; color: var(--sec); font-size: var(--text-xs); }
.check-status.is-fail { color: var(--invalid); }

.mark circle { stroke-width: 1.5; }
.mark path { fill: none; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.mark.is-pass circle { fill: var(--accent); stroke: var(--accent); }
.mark.is-pass path { stroke: var(--ground); }
.mark.is-fail circle { fill: color-mix(in srgb, var(--invalid) 16%, var(--panel)); stroke: color-mix(in srgb, var(--invalid) 55%, var(--line)); }
.mark.is-fail path { stroke: var(--invalid); }
.mark.is-none circle { fill: none; stroke: var(--field); }

/* --- the stages: the Lab's four, in its order ----------------------------
   From Husky's design (site/design/home-stages-source.png). The heading is a step under the hero's
   (his file set the two about the same size). The four sit in one panel, split by 1px lines: the
   list's own background shows through a 1px gap, so the lines follow any number of columns. */
/* Every section under the hero. site.css rules a line between two sections. His files have none
   here, so the space alone parts them. */
.home-section { margin-top: 128px; padding-top: 0; border-top: 0; }
.home-section h2 {
  margin: 0;
  color: var(--text);
  font-size: clamp(30px, 3vw, 42px);
  font-weight: var(--weight-semibold);
  letter-spacing: -0.04em;
  line-height: 1.08;
  text-wrap: balance;
}
.section-lead {
  margin: 18px 0 0;
  max-width: 36em;
  color: var(--sec);
  font-size: 17px;
  line-height: 1.65;
  text-wrap: pretty;
}
.stage-list {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 1px;
  margin: 48px 0 0;
  padding: 0;
  list-style: none;
  background: var(--line);
  border: 1px solid var(--line);
  border-radius: var(--radius-panel);
  overflow: hidden;
}
.stage { position: relative; min-width: 0; padding: 28px 24px 32px; background: var(--panel); }
/* The line along the top of each stage, green like the current tab in the Lab. It reaches 1px
   past its stage to cover the gap, so in one row the four read as one line. */
.stage::before {
  content: "";
  position: absolute;
  inset: 0 -1px auto 0;
  height: 2px;
  background: var(--accent);
  transform-origin: left center;
}
.stage-num { display: block; color: var(--accent); font-family: var(--mono); font-size: var(--text-xs); }
.stage h3 {
  margin: 14px 0 0;
  color: var(--text);
  font-size: 18px;
  font-weight: var(--weight-medium);
  letter-spacing: -0.01em;
  line-height: var(--leading-tight);
}
.stage p { margin: 10px 0 0; color: var(--muted); font-size: 14px; line-height: 1.65; text-wrap: pretty; }

/* --- market data: what the Lab holds --------------------------------------
   From Husky's design (site/design/home-market-source.png), redrawn at his word on 2026-10-14 with
   less text: four figures, each under a line that is its history. Every line runs on one scale,
   1 January 2015 to 14 October 2026, dark before the data starts and green after, so the four can
   be compared at a glance. Open, not boxed: the sections above are panels. The figures are the
   Lab's own: the comment over this section in index.html says where each comes from. */
.market-intro {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 34em);
  gap: 24px 64px;
  align-items: end;
}
.market-intro .section-lead { margin: 0; max-width: none; }

.market-stats {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 48px 32px;
  margin: 56px 0 0;
  padding: 0;
  list-style: none;
}
.market-stat { min-width: 0; }
.track { position: relative; display: block; height: 3px; border-radius: 2px; background: var(--active); }
.cover { position: absolute; inset: 0 0 0 auto; border-radius: 2px; background: var(--accent); }
/* Where each start falls on the scale. */
.from-2016-06 { left: 12.01%; }
.from-2017-08 { left: 21.91%; }
.from-2018-05 { left: 28.25%; }
.from-2025-08 { left: 90.40%; }
.market-num {
  display: block;
  margin-top: 28px;
  color: var(--text);
  font-size: clamp(36px, 3.4vw, 48px);
  font-weight: var(--weight-semibold);
  letter-spacing: -0.04em;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}
.market-what { display: block; margin-top: 12px; color: var(--sec); font-size: var(--text-md); }
.market-since { display: block; margin-top: 6px; color: var(--muted); font-family: var(--mono); font-size: var(--text-xs); }

/* site.css holds a paragraph to 68ch, which would break this one line in two. */
.market-symbols { margin: 48px 0 0; max-width: none; color: var(--muted); font-family: var(--mono); font-size: var(--text-xs); }
.market-symbols .sym { white-space: nowrap; }
/* The slash follows its symbol, so a line that wraps on a phone ends on one rather than starting with one. */
.market-symbols .sym:not(:last-child)::after { content: "/"; content: "/" / ""; margin: 0 4px 0 10px; color: var(--faint-mark); }
.market-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* --- the assistant: the chat on the left, the words on the right --------
   From Husky's design (site/design/home-assistant-source.png). The chat is a picture of the Lab's
   Assistant, as the window above is a picture of the Lab: its parts, words, sizes, colours and
   icons are the Lab's own, read from public/lab/lab.css and lab.js on 2026-10-14, with the Lab's
   tokens under this site's names (its block is --panel here, its control fill --raised). One
   change: the file card runs the width of the thread, where the Lab holds it to 420px, so the
   file's name is not cut short. */
.assistant {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 30rem);
  gap: 72px;
  align-items: center;
}
.assistant-words { grid-column: 2; grid-row: 1; }
.chat {
  grid-column: 1;
  grid-row: 1;
  display: flex;
  flex-direction: column;
  min-width: 0;
  margin: 0;
  background: var(--ground);
  border: 1px solid var(--chrome);
  border-radius: var(--radius-panel);
  overflow: hidden;
}
.chat p { max-width: none; }
.chat-head { display: flex; align-items: center; gap: 10px; height: 52px; padding: 0 20px; border-bottom: 1px solid var(--line); }
.chat-menu { color: var(--muted); font-size: 14px; }
.chat-title { color: var(--text); font-size: 14px; font-weight: var(--weight-semibold); }

/* The thread keeps one height, the taller of the empty chat and the conversation. Each part sits in
   a row that opens from nothing as it arrives (the motion below), so the chat grows down the page
   as the Lab's does, with the Lab's spacing: 28px above, 20px between. The finished screen is the
   conversation: the empty chat and "Writing" stay shut. */
.chat-thread { height: 276px; padding: 28px 20px 12px; overflow: hidden; }
.row { display: grid; grid-template-rows: 1fr; }
.row > div { min-height: 0; overflow: hidden; }
.chat-messages .row + .row > div > * { margin-top: 20px; }
.row-empty, .row-writing { grid-template-rows: 0fr; }

.chat-empty-title { margin: 0 0 6px; color: var(--text); font-size: 20px; font-weight: var(--weight-semibold); letter-spacing: -0.02em; }
.chat-empty p:not(.chat-empty-title) { margin: 0 0 20px; color: var(--sec); font-size: 13px; line-height: 1.55; }
.chat-suggest { display: grid; gap: 6px; }
.chat-suggest span {
  padding: 10px 12px;
  color: var(--sec);
  background: var(--panel);
  border: 1px solid var(--quiet);
  border-radius: 10px;
  font-size: 13px;
  line-height: 1.45;
}

.chat-ask { display: flex; justify-content: flex-end; margin: 0; font-size: 13px; line-height: 1.6; }
.chat-ask span { max-width: 82%; padding: 9px 13px; color: var(--text); background: var(--raised); border: 1px solid var(--line); border-radius: 10px; }

.chat-file {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto auto;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  color: var(--sec);
  background: var(--panel);
  border: 1px solid var(--quiet);
  border-radius: 10px;
}
.chat-file-icon { width: 12px; height: 12px; fill: none; stroke: var(--muted); stroke-width: 2; stroke-linejoin: round; }
.chat-file strong { overflow: hidden; color: var(--text); font: var(--weight-medium) 12px var(--mono); text-overflow: ellipsis; white-space: nowrap; }
.chat-file small { color: var(--muted); font: 11px var(--mono); }
.chat-file > span { color: var(--muted); font-size: 12px; font-weight: var(--weight-medium); }

.chat-step { display: flex; align-items: flex-start; gap: 8px; margin: 0; color: var(--muted); font-size: 12px; line-height: 1.5; }
.chat-step::before { content: ""; flex: none; width: 6px; height: 6px; margin-top: 6px; background: var(--accent); border-radius: 50%; }
/* "Running a backtest…" and "Ran a backtest" take one place: the first gives way to the second.
   The Lab underlines a finished run, which opens its result. */
.step-run { display: inline-grid; }
.step-run > span { grid-area: 1 / 1; }
.step-running { opacity: 0; }
.step-ran { text-decoration: underline dotted color-mix(in srgb, currentColor 45%, transparent); text-underline-offset: 3px; }

.chat-writing { display: flex; align-items: center; gap: 5px; margin: 0; color: var(--muted); }
.chat-writing span { width: 5px; height: 5px; background: var(--muted); border-radius: 50%; }
.chat-writing em { margin-left: 6px; font-size: 12px; font-style: normal; }

.chat-reply { margin: 0; color: var(--sec); font-size: 13px; line-height: 1.6; }
.chat-reply strong { color: var(--text); font-weight: var(--weight-semibold); }

.chat-composer { margin: 0 16px 16px; background: var(--panel); border: 1px solid var(--quiet); border-radius: 10px; }
.chat-field { display: grid; min-height: 50px; padding: 13px 14px 4px; font-size: 13px; line-height: 1.5; }
.chat-field > span { grid-area: 1 / 1; }
.chat-placeholder { color: var(--muted); }
.chat-typed { color: var(--text); }
.chat-typed .t { opacity: 0; }
.chat-bar { display: flex; align-items: center; gap: 8px; padding: 4px 8px 8px; }
.chat-model { display: inline-flex; align-items: center; gap: 8px; height: 30px; padding: 0 8px 0 9px; color: var(--sec); font-size: 12px; font-weight: var(--weight-medium); }
.chat-model svg { width: 12px; height: 12px; fill: none; stroke: var(--muted); stroke-width: 1.5; }
/* Dim, as the Lab draws it while there is nothing to send. */
.chat-send {
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  margin-left: auto;
  background: var(--raised);
  border: 1px solid var(--line);
  border-radius: 6px;
  opacity: 0.4;
}
.chat-send svg { width: 16px; height: 16px; fill: none; stroke: var(--text); stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }

/* --- connect your AI: the words on the left, the panel on the right ------
   From Husky's design (site/design/home-connect-source.png). Unlike the pictures above, the
   panel's tabs and Copy buttons work: home.js. Without it, .is-tabbed is never added and the panel
   shows each way to connect under its own name, with no tabs and no Copy. */
.connect {
  display: grid;
  grid-template-columns: minmax(0, 34rem) minmax(0, 1fr);
  gap: 72px;
  align-items: start;
}
.connect-facts { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 28px 32px; margin: 40px 0 0; }
.connect-facts > div { padding-top: 16px; border-top: 1px solid var(--quiet); }
.connect-facts dt { color: var(--text); font-size: var(--text-md); font-weight: var(--weight-medium); }
.connect-facts dd { margin: 6px 0 0; color: var(--muted); font-size: 14px; line-height: 1.55; }

.connect-panel {
  min-width: 0;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius-panel);
  overflow: hidden;
}
.connect-head { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 18px; padding: 12px 18px; border-bottom: 1px solid var(--line); }
.connect-title { color: var(--text); font-size: var(--text-sm); font-weight: var(--weight-medium); }
.pane-tablist { display: flex; flex-wrap: wrap; gap: 4px; }
.pane-tablist button {
  padding: 5px 10px;
  border: 1px solid transparent;
  border-radius: var(--radius-control);
  background: none;
  color: var(--muted);
  font: inherit;
  font-size: var(--text-sm);
  cursor: pointer;
  transition: color 160ms, background-color 160ms, border-color 160ms;
}
.pane-tablist button:hover { color: var(--sec); }
.pane-tablist [aria-selected="true"] { background: var(--raised); border-color: var(--line); color: var(--text); }
:is(.pane-tablist button, .connect-copy):focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.tab-sets { padding: 18px; }
.tab-set-name { margin: 0 0 12px; color: var(--text); font-size: var(--text-md); font-weight: var(--weight-medium); }
[data-tabs]:not(.is-tabbed) :is(.pane-tablist, .connect-copy) { display: none; }
[data-tabs]:not(.is-tabbed) .tab-set + .tab-set { margin-top: 24px; padding-top: 20px; border-top: 1px solid var(--line); }
/* With tabs, the three share one place, so the panel keeps the height of the tallest. */
[data-tabs].is-tabbed .tab-sets { display: grid; }
[data-tabs].is-tabbed .tab-set { grid-area: 1 / 1; }
[data-tabs].is-tabbed .tab-set:not(.is-current) { visibility: hidden; }
[data-tabs].is-tabbed .tab-set-name { display: none; }

.connect-field {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 10px 10px 10px 16px;
  background: var(--ground);
  border: 1px solid var(--line);
  border-radius: var(--radius-surface);
}
.connect-field-label { flex: none; color: var(--muted); font-size: var(--text-sm); }
.connect-field code { flex: 1; min-width: 0; border-radius: 3px; color: var(--text); font-family: var(--mono); font-size: 13px; overflow-wrap: anywhere; }
.connect-copy {
  flex: none;
  padding: 6px 12px;
  border: 1px solid var(--line);
  border-radius: var(--radius-control);
  background: var(--raised);
  color: var(--text);
  font: inherit;
  font-size: var(--text-xs);
  cursor: pointer;
}
.connect-copy:hover { background: var(--active); }

.connect-steps { display: grid; gap: 12px; margin: 18px 0 0; padding: 0; list-style: none; counter-reset: step; }
.connect-steps li { display: flex; gap: 12px; max-width: none; counter-increment: step; color: var(--sec); font-size: 14px; line-height: 22px; }
.connect-steps li::before {
  content: counter(step);
  flex: none;
  display: grid;
  place-items: center;
  width: 22px;
  height: 22px;
  border: 1px solid var(--line);
  border-radius: 50%;
  color: var(--sec);
  font-size: var(--text-xs);
}
.connect-steps b { color: var(--text); font-weight: var(--weight-medium); }
.connect-steps code { color: var(--text); font-family: var(--mono); font-size: 13px; overflow-wrap: anywhere; }

.connect-log { padding: 16px 18px 18px; border-top: 1px solid var(--line); }
.connect-log-head { display: flex; justify-content: space-between; gap: 12px; max-width: none; margin: 0 0 12px; color: var(--sec); font-size: var(--text-sm); }
.connect-sample { color: var(--stale); font-family: var(--mono); font-size: var(--text-xs); }
.connect-log dl { display: grid; gap: 8px; margin: 0; }
.log-line { display: grid; grid-template-columns: 6.5rem minmax(0, 1fr); gap: 12px; font-size: 13px; }
.log-line dt { color: var(--muted); }
.log-line dd { margin: 0; color: var(--muted); font-family: var(--mono); font-size: var(--text-xs); }
.log-line code { margin-right: 6px; color: var(--text); font-family: var(--mono); }

/* --- research, backtest and validation ------------------------------------
   From Husky's designs (site/design/home-research-source.png, home-validation-source.png and
   home-validation-lower-source.png), with less text. Each pane is drawn as the Lab draws its own:
   its block (--panel), its edge, and a head with a title and a muted line. */
.pane {
  min-width: 0;
  margin: 0;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius-panel);
  overflow: hidden;
}
.pane-head {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: center;
  gap: 8px 16px;
  min-height: 50px;
  padding: 9px 18px;
  border-bottom: 1px solid var(--line);
}
.pane-title { color: var(--text); font-size: var(--text-sm); font-weight: var(--weight-semibold); }
.pane-meta { color: var(--muted); font-family: var(--mono); font-size: var(--text-xs); }
.pane-tabs { display: flex; gap: 4px; }
.pane-tabs span { padding: 4px 9px; border: 1px solid transparent; border-radius: var(--radius-control); color: var(--muted); font-size: var(--text-xs); }
.pane-tabs .is-on { background: var(--raised); border-color: var(--line); color: var(--text); }

/* Research: the words, then the notebook. Backtest: the report, then the words. */
.research, .backtest { display: grid; gap: 72px; align-items: center; }
.research { grid-template-columns: minmax(0, 30rem) minmax(0, 1fr); }
.backtest { grid-template-columns: minmax(0, 1fr) minmax(0, 30rem); }
.backtest-words { grid-column: 2; grid-row: 1; }
.backtest-pane { grid-column: 1; grid-row: 1; }

/* The heatmap: the research run's own figures, a cell's green as strong as its correlation. Text
   is dark on the two strongest greens and light on the rest, for contrast. */
.heat { margin: 0 auto; padding: 4px 14px 18px; border-collapse: separate; border-spacing: 6px; }
.heat caption { padding: 16px 20px 4px; color: var(--sec); font-size: var(--text-sm); text-align: left; }
.heat th { color: var(--muted); font-family: var(--mono); font-size: var(--text-xs); font-weight: var(--weight-regular); }
.heat thead th { padding-top: 6px; }
.heat tbody th { padding-right: 6px; text-align: right; }
.heat td {
  width: 62px;
  height: 46px;
  border-radius: var(--radius-control);
  font-family: var(--mono);
  font-size: var(--text-xs);
  font-variant-numeric: tabular-nums;
  text-align: center;
}
.heat .v10 { background: var(--accent); color: var(--ground); }
.heat .v9 { background: color-mix(in srgb, var(--accent) 78%, var(--panel)); color: var(--ground); }
.heat .v8 { background: color-mix(in srgb, var(--accent) 62%, var(--panel)); color: var(--ground); }
.heat .v7 { background: color-mix(in srgb, var(--accent) 40%, var(--panel)); color: var(--text); }
.heat .v2 { background: color-mix(in srgb, var(--accent) 15%, var(--panel)); color: var(--sec); }
.heat .v1 { background: color-mix(in srgb, var(--accent) 9%, var(--panel)); color: var(--muted); }
.heat .v0 { background: color-mix(in srgb, var(--accent) 5%, var(--panel)); color: var(--muted); }

/* The backtest's Trades view: three of its tiles, then its breakdown by entry hour as bars. */
.bt-tiles { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); margin: 16px 16px 0; border: 1px solid var(--line); border-radius: var(--radius-surface); }
.bt-tiles > div { min-width: 0; padding: 12px 14px 14px; }
.bt-tiles > div + div { border-left: 1px solid var(--line); }
.bt-tiles dt { color: var(--muted); font-size: var(--text-xs); }
.bt-tiles dd { margin: 6px 0 0; }
.bt-tiles b { display: block; color: var(--text); font-family: var(--mono); font-size: 20px; font-weight: var(--weight-medium); font-variant-numeric: tabular-nums; }
.bt-tiles dd span { display: block; margin-top: 2px; color: var(--muted); font-size: var(--text-xs); }
.bt-break { padding: 18px 16px 20px; }
.bt-break-head { display: flex; justify-content: space-between; gap: 12px; max-width: none; margin: 0 0 12px; color: var(--sec); font-size: var(--text-sm); }
.bt-break-head span + span { color: var(--muted); font-family: var(--mono); font-size: var(--text-xs); }
.bt-hours { display: grid; gap: 9px; margin: 0; padding: 0; list-style: none; }
.bt-hours li { display: grid; grid-template-columns: 3rem minmax(0, 1fr) 4.5rem; align-items: center; gap: 12px; color: var(--muted); font-family: var(--mono); font-size: var(--text-xs); }
.bt-hours li > span:last-child { color: var(--text); font-variant-numeric: tabular-nums; text-align: right; }
.bt-bar { height: 10px; border-radius: 3px; background: var(--raised); }
.bt-bar > span { display: block; height: 100%; border-radius: 3px; transform-origin: left center; }
.bt-bar.is-up > span { background: var(--accent); }
.bt-bar.is-down > span { background: var(--invalid); }
/* Each bar's length against the largest hour, 13,400 USD. */
.h-1 .bt-bar > span { width: 100%; }
.h-2 .bt-bar > span { width: 44%; }
.h-3 .bt-bar > span { width: 18%; }
.h-4 .bt-bar > span { width: 9%; }
.h-5 .bt-bar > span { width: 10%; }
.h-6 .bt-bar > span { width: 6%; }

/* Validation: the words above; the Checklist and the views behind it side by side. "How validation
   works" in the hero stops here with room above the heading. */
.validation { scroll-margin-top: 40px; }
.validation-intro { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 34em); gap: 24px 64px; align-items: end; }
.validation-intro .section-lead { margin: 0; max-width: none; }
.validation-grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.2fr); gap: 16px; margin-top: 48px; align-items: stretch; }
.checks-pane .pane-meta b { margin: 0 4px; color: var(--stale); font-weight: var(--weight-semibold); }
.v-count { color: var(--text); }
.v-checks { margin: 0; padding: 0; list-style: none; }
.v-check { display: grid; grid-template-columns: 22px minmax(0, 1fr) auto; column-gap: 14px; align-items: center; padding: 17px 18px; }
.v-check + .v-check { border-top: 1px solid var(--line); }
.v-check .mark { grid-row: 1 / span 2; width: 22px; height: 22px; }
.v-name { grid-column: 2; color: var(--text); font-size: 14px; font-weight: var(--weight-medium); }
.v-status { grid-column: 2; margin-top: 2px; color: var(--sec); font-size: var(--text-xs); }
.v-status.is-fail { color: var(--invalid); }
.v-tag { grid-column: 3; grid-row: 1 / span 2; color: var(--muted); font-family: var(--mono); font-size: var(--text-xs); }

.v-figure { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 10px; max-width: none; margin: 0 0 14px; }
.v-figure b { color: var(--text); font-size: 28px; font-weight: var(--weight-semibold); letter-spacing: -0.02em; font-variant-numeric: tabular-nums; }
.v-figure span { color: var(--muted); font-size: var(--text-xs); }
.v-figure.is-fail b { color: var(--invalid); }

/* Daily P&L resampling's fan, as the Lab draws it: the middle 90% and 50% of the paths, their
   median, and this run. The dashed line is zero. */
.fan { display: block; width: 100%; height: 210px; overflow: visible; }
.fan-90 { fill: color-mix(in srgb, var(--sec) 9%, transparent); }
.fan-50 { fill: color-mix(in srgb, var(--sec) 17%, transparent); }
.fan-zero { stroke: var(--faint-mark); stroke-width: 1; stroke-dasharray: 3 4; vector-effect: non-scaling-stroke; }
.fan-median { fill: none; stroke: var(--muted); stroke-width: 1.25; stroke-dasharray: 5 4; vector-effect: non-scaling-stroke; }
.fan-run { fill: none; stroke: var(--accent); stroke-width: 2; stroke-linejoin: round; vector-effect: non-scaling-stroke; }
.v-legend { display: flex; flex-wrap: wrap; gap: 6px 18px; max-width: none; margin: 14px 0 0; color: var(--muted); font-size: var(--text-xs); }
.v-legend span::before { content: ""; display: inline-block; width: 14px; height: 8px; margin-right: 7px; border-radius: 2px; vertical-align: 0; }
.v-legend .k-run::before { height: 2px; background: var(--accent); }
.v-legend .k-median::before { height: 0; border-top: 2px dashed var(--muted); }
.v-legend .k-50::before { background: color-mix(in srgb, var(--sec) 17%, transparent); }
.v-legend .k-90::before { background: color-mix(in srgb, var(--sec) 9%, transparent); }

/* The two shorter views sit in the middle of the space the fan sets. */
.views-pane.is-tabbed :is(.view-prop, .view-unseen) { align-self: center; }

/* The prop firm test: where 2,000 attempts ended. */
.prop-bar { display: flex; gap: 2px; height: 12px; margin: 6px 0 20px; }
.prop-bar span { border-radius: 2px; transform-origin: left center; }
.p-pass, .r-pass dt::before { background: var(--accent); }
.p-max, .r-max dt::before { background: var(--invalid); }
.p-daily, .r-daily dt::before { background: color-mix(in srgb, var(--invalid) 50%, var(--panel)); }
.p-time, .r-time dt::before { background: var(--stale); }
.p-pass { flex: 22; }
.p-max { flex: 61; }
.p-daily { flex: 9; }
.p-time { flex: 8; }
.prop-reasons { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px 24px; margin: 0; }
.prop-reasons > div { display: flex; justify-content: space-between; gap: 12px; padding-top: 9px; border-top: 1px solid var(--line); font-size: var(--text-xs); }
.prop-reasons dt { color: var(--muted); }
.prop-reasons dt::before { content: ""; display: inline-block; width: 8px; height: 8px; margin-right: 8px; border-radius: 2px; }
.prop-reasons dd { margin: 0; color: var(--text); font-family: var(--mono); }

/* Out-of-sample: the dates the strategy was built on, and the year kept from it. */
.oos-bar { display: grid; grid-template-columns: 5fr 1fr; gap: 3px; margin: 6px 0 0; }
.oos-bar > span {
  display: grid;
  align-content: center;
  gap: 2px;
  min-height: 64px;
  padding: 0 12px;
  border-radius: var(--radius-control);
  color: var(--sec);
  font-family: var(--mono);
  font-size: var(--text-xs);
  transform-origin: left center;
}
.oos-bar b { color: var(--text); font-size: var(--text-xs); font-weight: var(--weight-medium); }
.oos-build { background: color-mix(in srgb, var(--accent) 12%, var(--panel)); border: 1px solid color-mix(in srgb, var(--accent) 28%, var(--line)); }
.oos-unseen { background: color-mix(in srgb, var(--invalid) 14%, var(--panel)); border: 1px solid color-mix(in srgb, var(--invalid) 45%, var(--line)); }

/* --- the motion -------------------------------------------------------------
   A loop of sixteen seconds, over and over (Husky, 2026-10-14). In each pass: the run (0.3 s), the
   result and its line (1.5 to 3 s), the move from Workspace to Validation (3.1 s), the four checks
   one at a time (3.3 to 4.4 s), the band (4.35 s), then the finished screen held for about ten
   seconds, as he asked for a longer pause between plays. It clears (14.7 to 15.2 s) and the next
   pass starts on the Workspace tab.

   Every step has its own keyframes, written in sixteenths of the loop (6.25% is one second),
   because a delay would only offset an element's first pass and the steps would drift apart. The
   curves inside them are written out: they are --ease and --ease-spring from tokens.css, but a
   var() in a keyframe's timing function is not applied, and the step runs linear. Only when the
   reader's system allows motion: otherwise the page shows the finished screen, which is what every
   rule here leaves in place outside the media query. */
@media (prefers-reduced-motion: no-preference) {
  .lab-run { transform-box: fill-box; transform-origin: center; animation: lab-loop-run 16s linear infinite; }
  .lab-metric dd { animation: lab-loop-metric 16s linear infinite; }
  /* A stagger of 80 ms keeps its offset on every pass, which is all it needs to do. */
  .lab-metric:nth-child(2) dd { animation-delay: 80ms; }
  .lab-metric:nth-child(3) dd { animation-delay: 160ms; }
  .lab-metric:nth-child(4) dd { animation-delay: 240ms; }
  .lab-chart .equity { animation: lab-loop-draw 16s linear infinite; }
  .tab-workspace { animation: lab-loop-tab-first 16s linear infinite; }
  .tab-validation { animation: lab-loop-tab-then 16s linear infinite; }
  .lab-check:nth-child(1) :is(.mark, .check-status) { animation: lab-loop-check-1 16s linear infinite; }
  .lab-check:nth-child(2) :is(.mark, .check-status) { animation: lab-loop-check-2 16s linear infinite; }
  .lab-check:nth-child(3) :is(.mark, .check-status) { animation: lab-loop-check-3 16s linear infinite; }
  .lab-check:nth-child(4) :is(.mark, .check-status) { animation: lab-loop-check-4 16s linear infinite; }
  .lab-band { animation: lab-loop-band 16s linear infinite; }
  .stage:nth-child(1)::before { animation: stage-loop-line-1 16s linear infinite; }
  .stage:nth-child(2)::before { animation: stage-loop-line-2 16s linear infinite; }
  .stage:nth-child(3)::before { animation: stage-loop-line-3 16s linear infinite; }
  .stage:nth-child(4)::before { animation: stage-loop-line-4 16s linear infinite; }
  .stage:nth-child(1) .stage-num { animation: stage-loop-num-1 16s linear infinite; }
  .stage:nth-child(2) .stage-num { animation: stage-loop-num-2 16s linear infinite; }
  .stage:nth-child(3) .stage-num { animation: stage-loop-num-3 16s linear infinite; }
  .stage:nth-child(4) .stage-num { animation: stage-loop-num-4 16s linear infinite; }
  .cover { animation: market-loop-grow 16s linear infinite backwards; }
  .market-stat:nth-child(2) .cover { animation-delay: 100ms; }
  .market-stat:nth-child(3) .cover { animation-delay: 200ms; }
  .market-stat:nth-child(4) .cover { animation-delay: 300ms; }
  .chat-placeholder { animation: chat-loop-placeholder 16s linear infinite; }
  .t-1 { animation: chat-loop-t-1 16s linear infinite; }
  .t-2 { animation: chat-loop-t-2 16s linear infinite; }
  .t-3 { animation: chat-loop-t-3 16s linear infinite; }
  .t-4 { animation: chat-loop-t-4 16s linear infinite; }
  .chat-send { animation: chat-loop-send 16s linear infinite; }
  .row-empty { animation: chat-loop-empty 16s linear infinite; }
  .row-ask { animation: chat-loop-ask 16s linear infinite; }
  .row-writing { animation: chat-loop-writing 16s linear infinite; }
  .row-file { animation: chat-loop-file 16s linear infinite; }
  .row-step { animation: chat-loop-step 16s linear infinite; }
  .row-reply { animation: chat-loop-reply 16s linear infinite; }
  .step-running { animation: chat-loop-running 16s linear infinite; }
  .step-ran { animation: chat-loop-ran 16s linear infinite; }
  .say-1 { animation: chat-loop-say-1 16s linear infinite; }
  .say-2 { animation: chat-loop-say-2 16s linear infinite; }
  .say-3 { animation: chat-loop-say-3 16s linear infinite; }
  .say-4 { animation: chat-loop-say-4 16s linear infinite; }
  /* The Lab's own "Writing" dots, with its timing. */
  .chat-writing span { animation: chat-writing-dot 1.1s cubic-bezier(0.22, 1, 0.36, 1) infinite; }
  .chat-writing span:nth-child(2) { animation-delay: 0.15s; }
  .chat-writing span:nth-child(3) { animation-delay: 0.3s; }
  /* The panel's own moves, set off by home.js: a tab's content arriving, and the demo of picking
     out its address or command, which ends on the Copy button. */
  [data-tabs].is-tabbed .tab-set.is-current { animation: connect-in 280ms cubic-bezier(0.22, 1, 0.36, 1); }
  .connect-field.is-demo code { animation: connect-pick 1.8s 0.6s both; }
  .connect-field.is-demo .connect-copy { animation: connect-press 1.8s 0.6s both; }
  /* Research, backtest and validation on the shared loop. Each stagger is a delay, which keeps
     its offset on every pass; backwards holds the first frame through it. */
  .heat td { animation: heat-loop 16s linear infinite backwards; }
  .heat .d1 { animation-delay: 60ms; }
  .heat .d2 { animation-delay: 120ms; }
  .heat .d3 { animation-delay: 180ms; }
  .heat .d4 { animation-delay: 240ms; }
  .heat .d5 { animation-delay: 300ms; }
  .heat .d6 { animation-delay: 360ms; }
  .heat .d7 { animation-delay: 420ms; }
  .heat .d8 { animation-delay: 480ms; }
  .heat .d9 { animation-delay: 540ms; }
  .heat .d10 { animation-delay: 600ms; }
  .bt-tiles b { animation: bt-loop-figure 16s linear infinite backwards; }
  .bt-tiles > div:nth-child(2) b { animation-delay: 100ms; }
  .bt-tiles > div:nth-child(3) b { animation-delay: 200ms; }
  .bt-bar > span { animation: bt-loop-bar 16s linear infinite backwards; }
  .h-2 .bt-bar > span { animation-delay: 120ms; }
  .h-3 .bt-bar > span { animation-delay: 240ms; }
  .h-4 .bt-bar > span { animation-delay: 360ms; }
  .h-5 .bt-bar > span { animation-delay: 480ms; }
  .h-6 .bt-bar > span { animation-delay: 600ms; }
  .v-check :is(.mark, .v-status, .v-tag) { animation: v-loop-check 16s linear infinite backwards; }
  .v-check:nth-child(2) :is(.mark, .v-status, .v-tag) { animation-delay: 150ms; }
  .v-check:nth-child(3) :is(.mark, .v-status, .v-tag) { animation-delay: 300ms; }
  .v-check:nth-child(4) :is(.mark, .v-status, .v-tag) { animation-delay: 450ms; }
  .v-check:nth-child(5) :is(.mark, .v-status, .v-tag) { animation-delay: 600ms; }
  /* The views behind the checks, each as its tab opens. */
  .view-resampling.is-current :is(.fan-90, .fan-50, .fan-median) { animation: v-fade 700ms cubic-bezier(0.22, 1, 0.36, 1) both; }
  .view-resampling.is-current .fan-run { animation: v-draw 1.4s 200ms linear both; }
  .view-prop.is-current .prop-bar span { animation: v-draw 600ms cubic-bezier(0.22, 1, 0.36, 1) both; }
  .view-prop.is-current .prop-bar span:nth-child(2) { animation-delay: 120ms; }
  .view-prop.is-current .prop-bar span:nth-child(3) { animation-delay: 240ms; }
  .view-prop.is-current .prop-bar span:nth-child(4) { animation-delay: 360ms; }
  .view-unseen.is-current .oos-build { animation: v-draw 700ms cubic-bezier(0.22, 1, 0.36, 1) both; }
  .view-unseen.is-current .oos-unseen { animation: v-draw 500ms 600ms cubic-bezier(0.22, 1, 0.36, 1) both; }
}

/* --- the arrival --------------------------------------------------------------
   At Husky's word (2026-10-14): each section under the hero fades up as the reader scrolls to it,
   once, its parts 120 ms apart, and "How validation works" scrolls to its section rather than
   jumping. A section's share of the loop waits at its first frame until the section arrives, so
   it is seen from the start. home.js sets this going (.reveals on the page, .is-in on a section).
   Without the script nothing is hidden and the loop runs from the page's opening, as before. */
@media (prefers-reduced-motion: no-preference) {
  html { scroll-behavior: smooth; }
  /* Hidden at once, shown over 700 ms: only the arrival is a transition. */
  .reveals .home-section:not(.is-in) > * { opacity: 0; transform: translateY(24px); }
  .reveals .home-section.is-in > * { transition: opacity 700ms var(--ease), transform 700ms var(--ease); }
  .reveals .home-section.is-in > :nth-child(2) { transition-delay: 120ms; }
  .reveals .home-section.is-in > :nth-child(3) { transition-delay: 240ms; }
  .reveals .home-section:not(.is-in) *,
  .reveals .home-section:not(.is-in) *::before { animation-play-state: paused; }
  /* The stages' line waits 4.8 s for the Lab example above to play. A reader who scrolls down to
     the stages has seen it, so for them the line starts about a second after they arrive. */
  .stages.is-late .stage::before,
  .stages.is-late .stage-num { animation-delay: -3.8s; }
}

/* --- the opening --------------------------------------------------------------
   Husky, 2026-10-14: as the page loads, the hero rises into place a part at a time, 70 ms apart,
   then the Lab window, all done in about a second. Once per load. A page that slid in from another
   page of the site has moved already (nav.js marks it), so it does not rise as well. */
@media (prefers-reduced-motion: no-preference) {
  .hero-copy > *,
  .hero .lab-window { animation: hero-rise 700ms var(--ease) backwards; }
  .hero-copy > :nth-child(2) { animation-delay: 70ms; }
  .hero-copy > :nth-child(3) { animation-delay: 140ms; }
  .hero-copy > :nth-child(4) { animation-delay: 210ms; }
  .hero-copy > :nth-child(5) { animation-delay: 280ms; }
  .hero .lab-window { animation-duration: 900ms; animation-delay: 240ms; }
  .slid-in .hero-copy > *,
  .slid-in .hero .lab-window { animation: none; }
}
@keyframes hero-rise { from { opacity: 0; transform: translateY(16px); } }

/* The run arrow pulses twice as the run starts: 0.3 s to 1.7 s. */
@keyframes lab-loop-run {
  0%, 1.875% { opacity: 1; transform: none; }
  4.0625% { opacity: 0.35; transform: scale(0.8); }
  6.25% { opacity: 1; transform: none; }
  8.4375% { opacity: 0.35; transform: scale(0.8); }
  10.625%, 100% { opacity: 1; transform: none; }
}
/* In from 1.5 s to 1.95 s, held to 14.7 s, out by 15.2 s. */
@keyframes lab-loop-metric {
  0%, 9.375% { opacity: 0; transform: translateY(4px); animation-timing-function: cubic-bezier(0.22, 1, 0.36, 1); }
  12.1875%, 91.875% { opacity: 1; transform: none; }
  95%, 100% { opacity: 0; transform: none; }
}
/* Drawn from 1.6 s to 3 s, at an even pace. */
@keyframes lab-loop-draw {
  0%, 10% { clip-path: inset(0 100% 0 0); opacity: 1; }
  18.75%, 91.875% { clip-path: inset(0 0 0 0); opacity: 1; }
  95%, 100% { clip-path: inset(0 0 0 0); opacity: 0; }
}
/* Workspace is current until 3.1 s and again from 15.2 s; Validation in between. */
@keyframes lab-loop-tab-first {
  0%, 19.3125% { color: var(--text); border-bottom-color: var(--accent); }
  19.375%, 94.9375% { color: var(--muted); border-bottom-color: transparent; }
  95%, 100% { color: var(--text); border-bottom-color: var(--accent); }
}
@keyframes lab-loop-tab-then {
  0%, 19.3125% { color: var(--muted); border-bottom-color: transparent; }
  19.375%, 94.9375% { color: var(--text); border-bottom-color: var(--accent); }
  95%, 100% { color: var(--muted); border-bottom-color: transparent; }
}
/* The checks at 3.3, 3.55, 3.8 and 4.05 s, each in 0.36 s. */
@keyframes lab-loop-check-1 {
  0%, 20.625% { opacity: 0; transform: scale(0.85); animation-timing-function: cubic-bezier(0.34, 1.26, 0.64, 1); }
  22.875%, 91.875% { opacity: 1; transform: none; }
  95%, 100% { opacity: 0; transform: none; }
}
@keyframes lab-loop-check-2 {
  0%, 22.1875% { opacity: 0; transform: scale(0.85); animation-timing-function: cubic-bezier(0.34, 1.26, 0.64, 1); }
  24.4375%, 91.875% { opacity: 1; transform: none; }
  95%, 100% { opacity: 0; transform: none; }
}
@keyframes lab-loop-check-3 {
  0%, 23.75% { opacity: 0; transform: scale(0.85); animation-timing-function: cubic-bezier(0.34, 1.26, 0.64, 1); }
  26%, 91.875% { opacity: 1; transform: none; }
  95%, 100% { opacity: 0; transform: none; }
}
@keyframes lab-loop-check-4 {
  0%, 25.3125% { opacity: 0; transform: scale(0.85); animation-timing-function: cubic-bezier(0.34, 1.26, 0.64, 1); }
  27.5625%, 91.875% { opacity: 1; transform: none; }
  95%, 100% { opacity: 0; transform: none; }
}
/* The band from 4.35 s to 4.75 s. */
@keyframes lab-loop-band {
  0%, 27.1875% { opacity: 0; }
  29.6875%, 91.875% { opacity: 1; }
  95%, 100% { opacity: 0; }
}

/* The stages, on the same loop, once the Lab example has finished: the line runs across them at an
   even pace from 4.8 s to 7.6 s, 0.7 s each, and each number turns green as the line reaches it.
   Held with the Lab example, cleared with it. Before 4.8 s the stages are as his file drew them. */
@keyframes stage-loop-line-1 {
  0%, 30% { opacity: 1; transform: scaleX(0); }
  34.375%, 91.875% { opacity: 1; transform: none; }
  95%, 100% { opacity: 0; transform: none; }
}
@keyframes stage-loop-line-2 {
  0%, 34.375% { opacity: 1; transform: scaleX(0); }
  38.75%, 91.875% { opacity: 1; transform: none; }
  95%, 100% { opacity: 0; transform: none; }
}
@keyframes stage-loop-line-3 {
  0%, 38.75% { opacity: 1; transform: scaleX(0); }
  43.125%, 91.875% { opacity: 1; transform: none; }
  95%, 100% { opacity: 0; transform: none; }
}
@keyframes stage-loop-line-4 {
  0%, 43.125% { opacity: 1; transform: scaleX(0); }
  47.5%, 91.875% { opacity: 1; transform: none; }
  95%, 100% { opacity: 0; transform: none; }
}
@keyframes stage-loop-num-1 {
  0%, 30% { color: var(--muted); }
  31.875%, 91.875% { color: var(--accent); }
  95%, 100% { color: var(--muted); }
}
@keyframes stage-loop-num-2 {
  0%, 34.375% { color: var(--muted); }
  36.25%, 91.875% { color: var(--accent); }
  95%, 100% { color: var(--muted); }
}
@keyframes stage-loop-num-3 {
  0%, 38.75% { color: var(--muted); }
  40.625%, 91.875% { color: var(--accent); }
  95%, 100% { color: var(--muted); }
}
@keyframes stage-loop-num-4 {
  0%, 43.125% { color: var(--muted); }
  45%, 91.875% { color: var(--accent); }
  95%, 100% { color: var(--muted); }
}

/* The market data's history lines fill in from their first date to now, 0.6 s to 2.2 s, one
   figure every 100 ms, held and cleared with the rest. The section is seen on its own, so it plays at the
   start of the loop rather than after the stages, and spends most of the loop finished. */
@keyframes market-loop-grow {
  0%, 3.75% { opacity: 1; clip-path: inset(0 100% 0 0); animation-timing-function: cubic-bezier(0.22, 1, 0.36, 1); }
  13.75%, 91.875% { opacity: 1; clip-path: inset(0 0 0 0); }
  95%, 100% { opacity: 0; clip-path: inset(0 0 0 0); }
}

/* The chat, on the same loop. It opens on the Lab's empty chat. The message is typed into the
   composer from 0.6 s, the send arrow lighting as there is something to send, and sent at 2.2 s:
   the empty chat gives way and the message arrives (2.3 s). "Writing" (2.9 s), the file card
   (3.6 s), "Running a backtest…" (4.2 s) until "Ran a backtest" (5.55 s), then the reply in place
   of "Writing" from 5.8 s, a sentence at a time. Held to 14.7 s, cleared by 15.2 s, and the empty
   chat is back by the start of the next pass. The rows open by grid-template-rows, 0fr to 1fr. */
@keyframes chat-loop-placeholder { 0%, 3.75% { opacity: 1; } 4.375%, 13.75% { opacity: 0; } 14.375%, 100% { opacity: 1; } }
@keyframes chat-loop-t-1 { 0%, 3.75% { opacity: 0; } 4.375%, 13.75% { opacity: 1; } 14.0625%, 100% { opacity: 0; } }
@keyframes chat-loop-t-2 { 0%, 5.9375% { opacity: 0; } 6.5625%, 13.75% { opacity: 1; } 14.0625%, 100% { opacity: 0; } }
@keyframes chat-loop-t-3 { 0%, 8.125% { opacity: 0; } 8.75%, 13.75% { opacity: 1; } 14.0625%, 100% { opacity: 0; } }
@keyframes chat-loop-t-4 { 0%, 10.3125% { opacity: 0; } 10.9375%, 13.75% { opacity: 1; } 14.0625%, 100% { opacity: 0; } }
@keyframes chat-loop-send {
  0%, 3.75% { opacity: 0.4; background-color: var(--raised); border-color: var(--line); transform: none; }
  4.375%, 12.8125% { opacity: 1; background-color: color-mix(in srgb, var(--accent) 16%, var(--raised)); border-color: color-mix(in srgb, var(--accent) 50%, var(--line)); transform: none; }
  13.4375% { opacity: 1; background-color: color-mix(in srgb, var(--accent) 26%, var(--raised)); border-color: var(--accent); transform: scale(0.94); }
  14.0625%, 100% { opacity: 0.4; background-color: var(--raised); border-color: var(--line); transform: none; }
}
@keyframes chat-loop-empty {
  0%, 13.75% { grid-template-rows: 1fr; opacity: 1; }
  14.375% { grid-template-rows: 1fr; opacity: 0; }
  15.625%, 95% { grid-template-rows: 0fr; opacity: 0; }
  96.875% { grid-template-rows: 1fr; opacity: 0; }
  100% { grid-template-rows: 1fr; opacity: 1; }
}
@keyframes chat-loop-ask {
  0%, 14.375% { grid-template-rows: 0fr; opacity: 0; animation-timing-function: cubic-bezier(0.22, 1, 0.36, 1); }
  16.25%, 91.875% { grid-template-rows: 1fr; opacity: 1; }
  93.75% { grid-template-rows: 1fr; opacity: 0; }
  95%, 100% { grid-template-rows: 0fr; opacity: 0; }
}
@keyframes chat-loop-writing {
  0%, 18.125% { grid-template-rows: 0fr; opacity: 0; }
  19.375%, 36.25% { grid-template-rows: 1fr; opacity: 1; }
  37.1875%, 100% { grid-template-rows: 0fr; opacity: 0; }
}
@keyframes chat-loop-file {
  0%, 22.5% { grid-template-rows: 0fr; opacity: 0; animation-timing-function: cubic-bezier(0.34, 1.26, 0.64, 1); }
  24.375%, 91.875% { grid-template-rows: 1fr; opacity: 1; }
  93.75% { grid-template-rows: 1fr; opacity: 0; }
  95%, 100% { grid-template-rows: 0fr; opacity: 0; }
}
@keyframes chat-loop-step {
  0%, 26.25% { grid-template-rows: 0fr; opacity: 0; }
  27.5%, 91.875% { grid-template-rows: 1fr; opacity: 1; }
  93.75% { grid-template-rows: 1fr; opacity: 0; }
  95%, 100% { grid-template-rows: 0fr; opacity: 0; }
}
@keyframes chat-loop-reply {
  0%, 36.25% { grid-template-rows: 0fr; opacity: 0; }
  37.5%, 91.875% { grid-template-rows: 1fr; opacity: 1; }
  93.75% { grid-template-rows: 1fr; opacity: 0; }
  95%, 100% { grid-template-rows: 0fr; opacity: 0; }
}
@keyframes chat-loop-running { 0%, 34.6875% { opacity: 1; } 35%, 100% { opacity: 0; } }
@keyframes chat-loop-ran { 0%, 34.6875% { opacity: 0; } 35.3125%, 100% { opacity: 1; } }
@keyframes chat-loop-say-1 { 0%, 36.875% { opacity: 0; } 38.75%, 100% { opacity: 1; } }
@keyframes chat-loop-say-2 { 0%, 40% { opacity: 0; } 41.875%, 100% { opacity: 1; } }
@keyframes chat-loop-say-3 { 0%, 43.125% { opacity: 0; } 45%, 100% { opacity: 1; } }
@keyframes chat-loop-say-4 { 0%, 46.25% { opacity: 0; } 48.125%, 100% { opacity: 1; } }
@keyframes chat-writing-dot { 0%, 80%, 100% { opacity: 0.25; transform: none; } 40% { opacity: 1; transform: translateY(-2px); } }

/* The connected log's three lines, at 1 s, 1.6 s and 2.2 s of the loop. */
@keyframes log-loop-1 { 0%, 6.25% { opacity: 0; } 8.75%, 91.875% { opacity: 1; } 95%, 100% { opacity: 0; } }
@keyframes log-loop-2 { 0%, 10% { opacity: 0; } 12.5%, 91.875% { opacity: 1; } 95%, 100% { opacity: 0; } }
@keyframes log-loop-3 { 0%, 13.75% { opacity: 0; } 16.25%, 91.875% { opacity: 1; } 95%, 100% { opacity: 0; } }

@keyframes connect-in { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }
@keyframes connect-pick {
  0% { background-color: transparent; }
  15%, 65% { background-color: color-mix(in srgb, var(--accent) 22%, transparent); }
  100% { background-color: transparent; }
}
@keyframes connect-press {
  0%, 30% { transform: none; border-color: var(--line); }
  38% { transform: scale(0.94); border-color: var(--accent); }
  50%, 70% { transform: none; border-color: var(--accent); }
  100% { transform: none; border-color: var(--line); }
}

/* Research, backtest and validation: the heatmap fills in along its diagonal from 0.6 s, the
   backtest's figures arrive from 0.5 s and its bars grow from 1 s, the checks arrive from 0.6 s.
   Held and cleared with the rest. */
@keyframes heat-loop {
  0%, 3.75% { opacity: 0; transform: scale(0.9); animation-timing-function: cubic-bezier(0.22, 1, 0.36, 1); }
  6.25%, 91.875% { opacity: 1; transform: none; }
  95%, 100% { opacity: 0; transform: none; }
}
@keyframes bt-loop-figure {
  0%, 3.125% { opacity: 0; transform: translateY(4px); animation-timing-function: cubic-bezier(0.22, 1, 0.36, 1); }
  5.625%, 91.875% { opacity: 1; transform: none; }
  95%, 100% { opacity: 0; transform: none; }
}
@keyframes bt-loop-bar {
  0%, 6.25% { opacity: 1; transform: scaleX(0); animation-timing-function: cubic-bezier(0.22, 1, 0.36, 1); }
  10.625%, 91.875% { opacity: 1; transform: none; }
  95%, 100% { opacity: 0; transform: none; }
}
@keyframes v-loop-check {
  0%, 3.75% { opacity: 0; transform: scale(0.85); animation-timing-function: cubic-bezier(0.34, 1.26, 0.64, 1); }
  6%, 91.875% { opacity: 1; transform: none; }
  95%, 100% { opacity: 0; transform: none; }
}
@keyframes v-fade { from { opacity: 0; } }
@keyframes v-draw { from { clip-path: inset(0 100% 0 0); } to { clip-path: inset(0 0 0 0); } }

/* --- narrower windows ----------------------------------------------------- */
/* Below this the two columns stop fitting: the promise goes first, the Lab under it at full width. */
@media (max-width: 1180px) {
  .hero { grid-template-columns: minmax(0, 1fr); gap: 56px; }
  .hero-copy { max-width: 36rem; }
}
@media (max-width: 1180px) {
  .market-intro { grid-template-columns: minmax(0, 1fr); }
  .market-intro .section-lead { max-width: 36em; }
  /* The words first, then the chat or the panel under them. */
  .assistant, .connect { grid-template-columns: minmax(0, 1fr); gap: 40px; }
  .assistant-words, .chat { grid-column: auto; grid-row: auto; }
  .assistant-words, .connect-words { max-width: 36rem; }
  .research, .backtest { grid-template-columns: minmax(0, 1fr); gap: 40px; }
  .backtest-words, .backtest-pane { grid-column: auto; grid-row: auto; }
  .backtest-words { order: -1; }
  .research-words, .backtest-words { max-width: 36rem; }
  .validation-intro, .validation-grid { grid-template-columns: minmax(0, 1fr); }
  .validation-intro .section-lead { max-width: 36em; }
}
@media (max-width: 900px) {
  .stage-list { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .market-stats { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 40px 24px; }
  .lab-checks { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .lab-check + .lab-check { border-left: 0; }
  .lab-check { border-top: 1px solid var(--line); }
  .lab-check:nth-child(-n + 2) { border-top: 0; }
  .lab-check:nth-child(even) { border-left: 1px solid var(--line); }
}
@media (max-width: 720px) {
  .home-page main.wrap { padding-inline: 20px; padding-block: 48px 72px; }
  .lab-head { padding-inline: 14px; }
  .lab-tabs { gap: 20px; }
  /* The panes run edge to edge here, so the longest line still fits at 12px on a 390px phone. */
  .lab-body { grid-template-columns: minmax(0, 1fr); padding: 0; gap: 0; }
  .lab-editor, .lab-result { border-width: 0; border-radius: 0; }
  .lab-editor { border-bottom: 1px solid var(--line); }
  .code { padding-inline: 8px; }
  .code li::before { margin-right: 8px; }
  .lab-checks { grid-template-columns: minmax(0, 1fr); }
  .lab-check, .lab-check:nth-child(even) { border-left: 0; }
  .lab-check:nth-child(2) { border-top: 1px solid var(--line); }
  .lab-checklist-head { padding-inline: 14px; }
  .home-section { margin-top: 88px; }
}
@media (max-width: 560px) {
  /* The thread is taller, as the words wrap more, and the file card puts its line under its name. */
  .chat-thread { height: 372px; padding-inline: 14px; }
  .chat-composer { margin-inline: 10px; }
  .chat-ask span { max-width: 92%; }
  .chat-file { grid-template-columns: auto minmax(0, 1fr); row-gap: 4px; }
  .chat-file small, .chat-file > span { grid-column: 2; }
  .connect-facts { grid-template-columns: minmax(0, 1fr); gap: 20px; }
  .connect-head, .tab-sets, .connect-log { padding-inline: 14px; }
  /* The address or command takes a line of its own under its label and Copy, so it breaks at its
     spaces rather than inside a word. */
  .connect-field { flex-wrap: wrap; row-gap: 8px; padding: 10px 10px 12px 14px; }
  .connect-field-label { flex: 1; }
  .connect-field code { order: 3; flex-basis: 100%; }
  .log-line { grid-template-columns: 5.5rem minmax(0, 1fr); gap: 8px; }
  .stage-list { grid-template-columns: minmax(0, 1fr); }
  .stage { padding: 22px 20px 24px; }
  .heat { padding-inline: 4px; border-spacing: 4px; }
  .heat td { width: 42px; height: 38px; }
  .heat caption { padding-inline: 14px; }
  .bt-tiles { grid-template-columns: minmax(0, 1fr); }
  .bt-tiles > div + div { border-left: 0; border-top: 1px solid var(--line); }
  .prop-reasons { grid-template-columns: minmax(0, 1fr); }
  .pane-head, .v-check { padding-inline: 14px; }
}
