@charset "utf-8";
/* ==========================================================================
   KeyboardLatencyTest.com — mother-tool.css
   Page-specific rules for "/" ONLY. Everything that design-system.css already
   provides is reused as-is; this file adds the handful of components the
   design system genuinely does not have:

     01  small layout helpers the homepage needs
     02  segmented control (.seg)          — sample target + result detail
     03  stage panes, progress bar         — the live test surface
     04  chart grid                        — two charts side by side ≥1024px
     05  keyboard map host + legend swatch — scrollable mount, key panel
     06  latency-chain diagram             — theme-aware inline SVG
   ========================================================================== */

/* ==========================================================================
   01 — LAYOUT HELPERS
   ========================================================================== */

/* The site header is sticky and 57-65px tall. Without scroll padding, both an
   in-page anchor (#how-it-works) and a backwards Tab scroll their target to
   y=0, which parks it entirely underneath the header — WCAG 2.4.11 Focus Not
   Obscured. One value clears the tallest header state with room to spare. */
:root { scroll-padding-block-start: 5rem; }

/* .prose gives every h2/h3 a top margin; as the first child of a section that
   already has .section spacing it double-counts. */
.prose > :first-child { margin-block-start: 0; }

/* Hero on this page carries a CTA row, so the block padding is tightened to
   keep the test surface above the fold on a 1366x768 laptop. */
.hero--tight { padding-block: clamp(1.25rem, 3vw, 2rem) clamp(0.75rem, 2vw, 1.1rem); }
.hero__cta { margin-block-start: 1rem; }

/* Heading + control on one line, stacking under 480px. */
.sechead {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.6rem 1rem;
  margin-block-end: 0.75rem;
}

.sechead > * { min-inline-size: 0; }
.sechead h2, .sechead h3 { margin: 0; }

/* Value + unit on one baseline. .metric is a column flex container, so without
   this the block-level .metric__value pushes .metric__unit onto its own line.
   Keeping the unit a SIBLING (not a child) of .metric__value is deliberate:
   KLT.ui.setMetric rewrites the value element's textContent wholesale, and
   kb-export.js reads the unit separately when it builds the PNG report. */
.metric__line {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0 0.15rem;
  min-inline-size: 0;
}

.metric__line > .metric__value { min-inline-size: 0; }

/* Layout-picker row. */
.pickers {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(190px, 100%), 1fr));
  gap: 0.75rem;
  margin-block-end: 0.85rem;
}

.pickers > .field { margin: 0; }

/* ==========================================================================
   02 — SEGMENTED CONTROL — moved to design-system.css §10.1.
   /keyboard-typing-test/ had built the same control a second, incompatible way,
   so it is now one shared component (.seg / .seg__label / .seg__btn, including
   the coarse-pointer 44px branch). Nothing page-specific remains here.
   ========================================================================== */

/* ==========================================================================
   03 — STAGE PANES + PROGRESS
   ========================================================================== */

/* .stage is a centred grid; each pane is one grid item and only one is ever
   visible, so the box never jumps between states. */
.stage__pane {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.6rem;
  inline-size: 100%;
  max-inline-size: 46ch;
}

.stage__eyebrow {
  font-size: 0.6875rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.11em;
  color: var(--text-2);
}

.stage__eyebrow--warn { color: var(--warn); }

.stage__big { display: flex; align-items: baseline; gap: 0.15em; }

.stage__unit {
  font-family: var(--font);
  font-size: clamp(0.9rem, 0.7rem + 0.9vw, 1.25rem);
  font-weight: 600;
  color: var(--text-2);
  letter-spacing: 0;
}

.stage__count {
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
  font-size: 0.9375rem;
  color: var(--text-2);
}

.stage__count b { color: var(--text); }
.stage__foot { margin-block-start: 0.1rem; }

/* .btn--lg moved to design-system.css §10 so the size ladder sm/base/lg reads
   in one place — it sizes the site's most important control and was the one
   rule a person editing the button ladder would never open. */

/* The stage is clickable to focus, but its interactive children must win. */
.stage__pane .btn { position: relative; z-index: 1; }

/* Focus lost mid-run: dashed amber edge + no sweep animation. */
.stage--paused {
  border-style: dashed;
  border-color: var(--warn);
  background-color: color-mix(in srgb, var(--warn) 6%, var(--surface));
}

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

.prog {
  inline-size: min(100%, 26rem);
  block-size: 10px;
  padding: 2px;
  background: var(--surface-2);
  border: 1px solid var(--border-ui);
  border-radius: 999px;
  overflow: hidden;
}

/* Driven by --p (0-100) rather than an inline width: a custom property is the
   one thing every target browser sets identically from script. */
.prog__bar {
  display: block;
  block-size: 100%;
  inline-size: calc(var(--p, 0) * 1%);
  border-radius: 999px;
  background: var(--accent);
  transition: inline-size 0.14s linear;
}

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

/* Controls under the stage. */
.stagebar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.6rem 1rem;
  margin-block-start: 0.85rem;
}

.stagebar > * { min-inline-size: 0; }
.stagebar .tiny { max-inline-size: 52ch; }

/* ==========================================================================
   04 — CHART GRID
   ========================================================================== */

.chartgrid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0.85rem;
}

/* Grid children must be allowed to shrink below their content width or a
   canvas' intrinsic 300px would set the column floor. */
.chartgrid > * { min-inline-size: 0; }

/* .chart__head moved to design-system.css §13 (same class name, no markup
   change) — it belongs with the chart component, not with this page. */

@media (min-width: 1024px) {
  .chartgrid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* ==========================================================================
   05 — KEYBOARD MAP HOST
   The mount is the scroll region (it carries tabindex/role/aria-label), so the
   map inside it grows to its natural width instead of scrolling separately.
   ========================================================================== */

.kbdhost {
  overflow-x: auto;
  overscroll-behavior-x: contain;
  border-radius: var(--r);
  max-inline-size: 100%;
}

.kbdhost .kbd-map {
  overflow-x: visible;
  inline-size: max-content;
  min-inline-size: 100%;
  /* NOTE: --u is NOT set here any more. The 40px floor and the coarse-pointer
     48px branch this page pioneered are now the SHARED policy in
     design-system.css §14, so every page that mounts a map gets them. Do not
     reintroduce a page-local --u — that divergence is what left five
     diagnostic pages rendering 18x18px keycaps. */
  /* The widest rows carry a nav-cluster spacer whose negative inline-end
     margin makes this box's max-content resolve one --kbd-gap narrower than
     the row it has to hold; the last keycap then paints over the right border.
     One spare gutter of end padding absorbs it. */
  padding-inline-end: calc(var(--kbd-gap) * 2);
}

.kbdhost:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  box-shadow: var(--ring);
}

/* Legend swatches mirror the three keycap states without repeating their CSS. */
.lgnd {
  display: inline-block;
  inline-size: 14px;
  block-size: 14px;
  border-radius: 3px;
  border: 1px solid var(--border-ui);
  vertical-align: -2px;
  flex: none;
}

.lgnd--hit { background: color-mix(in srgb, var(--good) 20%, var(--surface-2)); border-color: var(--good); }
.lgnd--active { background: var(--accent); border-color: var(--accent); }
/* A 14px swatch cannot carry the keycap's subtle treatment: at --border and a
   40% hatch it measured 1.4:1 against the page, so the swatch beside the words
   read as an empty box. --border-ui plus a denser hatch clears 3:1. */
.lgnd--dead {
  border-style: dashed;
  border-color: var(--border-ui);
  background-image: repeating-linear-gradient(
    -45deg,
    color-mix(in srgb, var(--bad) 70%, transparent) 0 2px,
    transparent 2px 5px
  );
}

.keypanel {
  background: var(--surface);
  border: 1px solid var(--border);
  border-inline-start: 3px solid var(--accent);
  border-radius: 0 var(--r) var(--r) 0;
  padding: 0.9rem 1rem 1rem;
}

.keypanel > * + * { margin-block-start: 0.7rem; }

.keypanel__title {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.2rem 0.5rem;
  font-size: 0.9375rem;
  color: var(--text-2);
}

.keypanel__title b { color: var(--text); }

/* A <details> sitting inside a .note should not draw a second nested card. */
.disclose--flush { background: transparent; border-color: var(--border); }
.disclose--flush > summary { padding-inline: 0.65rem; }
.disclose--flush > :not(summary) { padding-inline: 0.65rem; }

/* ==========================================================================
   06 — LATENCY CHAIN DIAGRAM
   Two hand-authored SVGs, swapped at 1024px. Every colour comes from a design
   token, so both themes and the print palette work with no extra rules.
   ========================================================================== */

.chainfig {
  margin-block: 1.25rem;
  padding: clamp(0.75rem, 2vw, 1.25rem);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
}

.chain {
  inline-size: 100%;
  block-size: auto;
  /* Never wider than its own artwork, so it stops scaling up on huge screens. */
  max-inline-size: 100%;
  margin-inline: auto;
}

.chain--wide { display: none; }
.chain--tall { display: block; max-inline-size: 26rem; }

/* The stacked diagram is 340 viewBox units wide but only gets ~262 CSS px at a
   320px viewport, so it renders at 0.77x — which would drop its 12px and 13px
   labels to 9-10 CSS px. Size the tall variant's type up so the smallest
   rendering still lands above 12px. The wide variant never scales down. */
.chain--tall .chain__band-label { font-size: 16px; }
.chain--tall .chain__label { font-size: 17px; }

@media (min-width: 1024px) {
  .chain--wide { display: block; }
  .chain--tall { display: none; }
}

.chainfig__cap {
  margin-block-start: 0.75rem;
  font-size: 0.8125rem;
  color: var(--text-2);
  text-align: center;
}

/* ---- diagram parts ---- */

.chain__band {
  fill: none;
  stroke: var(--border-ui);
  stroke-width: 1;
  stroke-dasharray: 5 4;
}

.chain__band--on { stroke: var(--accent); stroke-width: 1.5; stroke-dasharray: none; }
.chain__band--frame { stroke: var(--amber); stroke-width: 1.5; stroke-dasharray: none; }

.chain__band-label {
  fill: var(--text-2);
  font-family: var(--font);
  /* The wide diagram is 1116 viewBox units and only gets ~908 CSS px at a
     1024px viewport, so it renders at 0.81x. These sizes are chosen so the
     smallest rendering still lands above 11 CSS px; every node box has room
     to spare at this size (widest label 70 of 104 units). */
  font-size: 15px;
  font-weight: 600;
  letter-spacing: 0.01em;
}

.chain__band-label--on { fill: var(--accent); font-weight: 700; }
.chain__band-label--frame { fill: var(--amber); font-weight: 700; }

.chain__node {
  fill: var(--surface-2);
  stroke: var(--border-ui);
  stroke-width: 1;
}

/* Stages a browser can never see: quieter fill, dashed edge. */
.chain__node--dim {
  fill: color-mix(in srgb, var(--surface-2) 55%, transparent);
  stroke: var(--border);
  stroke-dasharray: 4 3;
}

.chain__node--on {
  fill: color-mix(in srgb, var(--accent) 14%, var(--surface));
  stroke: var(--accent);
  stroke-width: 1.5;
}

.chain__node--frame {
  fill: color-mix(in srgb, var(--amber) 14%, var(--surface));
  stroke: var(--amber);
  stroke-width: 1.5;
}

.chain__label {
  fill: var(--text);
  font-family: var(--font);
  font-size: 15px;
  font-weight: 600;
}

.chain__label--dim { fill: var(--text-2); font-weight: 500; }

.chain__idx {
  fill: var(--text-2);
  font-family: var(--mono);
  font-size: 14px;
  font-weight: 600;
}

.chain__idx--on { fill: var(--accent); }
.chain__idx--frame { fill: var(--amber); }

.chain__arrow { stroke: var(--border-ui); stroke-width: 1.5; fill: none; }
.chain__arrow--on { stroke: var(--accent); stroke-width: 2.5; }
.chain__arrow--frame { stroke: var(--amber); stroke-width: 2.5; }

.chain__arrow-head { fill: var(--border-ui); stroke: none; }
.chain__arrow-head--on { fill: var(--accent); }
.chain__arrow-head--frame { fill: var(--amber); }

@media print {
  .chain--wide { display: block; }
  .chain--tall { display: none; }
  .chainfig { break-inside: avoid; }
}
