/* R2T2 streaming replay.
 *
 * Visual language follows r2t2.ai: warm near-black ground, a single hot orange
 * accent, mono for anything numeric or labelled, sans for prose. The waveform is
 * a row of bars rather than a canvas trace, and it toggles between the amplitude
 * envelope comes from the capture log, so the display stays a pure function of
 * the data.
 */

:root {
  --ink: #080807;
  --ink-soft: #12110f;
  --panel: #181512;
  --paper: #f3f0e9;
  --paper-soft: #e8e3da;
  /* The greys are measured, not chosen by eye. Panels are --panel at 62% over
     --ink, so text in a panel really sits on #12100e; every value below clears
     4.5:1 there, which is what the 10px mono labels need. The previous --muted
     (#777168) was 3.93:1 and the untokenised #5f5a54 was 2.78:1 — both were
     large-text-only ratios being used at 10px. See capture/verify_site.py,
     which now asserts this. */
  --muted: #8b8478;      /* 5.13:1 on panel — small-label grey */
  --faint: #877f74;      /* 4.81:1 — the quietest grey still legible at 9.5px */
  --dim: #918981;        /* 5.51:1 — body-copy grey */
  --line: rgba(255, 255, 255, 0.10);
  --line-strong: rgba(255, 255, 255, 0.14);
  --accent: #ff5b23;
  --accent-hot: #ff7547;
  /* Held-back tokens were --accent-hot at 0.55 alpha, which composites to
     2.91:1. They are the point of the in-flight stage, so they get a real
     colour at full opacity instead of a faded one. */
  --held: #ffa982;
  --gold: #e8c07a;
  --bad: #ff6b5e;
  --ok: #7ddba1;
  --sans: "Manrope", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
          "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif;
  --mono: "DM Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  --side: clamp(20px, 5vw, 72px);
  --content-max: 1500px;
  --radius: 24px;
}

* { box-sizing: border-box; }

html { scroll-behavior: smooth; }

body {
  margin: 0;
  background: var(--ink);
  color: var(--paper);
  font-family: var(--sans);
  font-size: 15px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

/* Film grain, as on the reference site: it keeps the large flat dark areas
   from banding. Fixed and non-interactive. */
body::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 40;
  pointer-events: none;
  opacity: 0.038;
  background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 180 180' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

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

/* The captures are 50+ panels behind a header and a six-item index, so a
   keyboard user reaching them has to walk the whole nav first. Off-screen until
   focused rather than `display: none`, which would take it out of the tab
   order and defeat the point. */
.skip {
  position: fixed;
  top: 8px;
  left: 8px;
  z-index: 60;
  transform: translateY(-200%);
  padding: 10px 16px;
  border-radius: 10px;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}
.skip:focus { transform: translateY(0); text-decoration: none; }

code, .mono {
  font-family: var(--mono);
  font-size: 0.88em;
}

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

header {
  position: relative;
  max-width: var(--content-max);
  margin: 0 auto;
  padding: clamp(46px, 7vw, 96px) var(--side) 34px;
  overflow: hidden;
}

header::before {
  content: "";
  position: absolute;
  width: 720px;
  height: 720px;
  right: -180px;
  top: -320px;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(255, 91, 35, 0.19),
                              rgba(255, 91, 35, 0.04) 38%, transparent 68%);
  filter: blur(8px);
  pointer-events: none;
}

.brand {
  display: flex;
  align-items: baseline;
  gap: 14px;
  flex-wrap: wrap;
  margin-bottom: 26px;
}

.brand-glyph {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--accent);
  border: 1px solid rgba(255, 117, 71, 0.42);
  border-radius: 999px;
  padding: 5px 11px;
}

.brand-name { font-size: 15px; font-weight: 600; letter-spacing: -0.01em; }
.brand-subtitle { font-family: var(--mono); font-size: 11px; color: var(--dim); }

h1 {
  margin: 0 0 18px;
  font-size: clamp(30px, 4.6vw, 58px);
  font-weight: 600;
  line-height: 1.06;
  letter-spacing: -0.035em;
  max-width: 18ch;
}

h1 em {
  font-style: normal;
  color: var(--accent-hot);
}

.lede {
  margin: 0 0 26px;
  max-width: 66ch;
  color: var(--dim);
  font-size: 16px;
}

.meta {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 20px;
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
  border-top: 1px solid var(--line);
  padding-top: 18px;
}
.meta code { color: var(--paper-soft); text-transform: none; letter-spacing: 0; }

main:focus { outline: none; }

/* ------------------------------------------------------------------- main */

main {
  max-width: var(--content-max);
  margin: 0 auto;
  padding: 0 var(--side) 110px;
}

.stage {
  position: relative;
  padding: 76px 0 60px;
  border-top: 1px solid var(--line);
  /* Clears the sticky nav when a stage is jumped to from the index. */
  scroll-margin-top: 62px;
}

.kicker {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 20px;
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--muted);
}
.kicker::before {
  content: "";
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 11px var(--accent);
}

/* The playback contract, stated where you meet the stage rather than only in the
   notes at the bottom. `margin-left: auto` so it sits at the far end of the
   kicker rather than competing with the section number. */
.plays {
  margin-left: auto;
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  padding: 5px 10px;
  border-radius: 999px;
  border: 1px solid var(--line-strong);
  color: var(--dim);
  white-space: nowrap;
}
.plays-sync { color: var(--accent-hot); border-color: rgba(255, 117, 71, 0.42); }
.plays-both { color: var(--gold); border-color: rgba(232, 192, 122, 0.36); }

/* --------------------------------------------------------------- stage nav */

.stage-nav {
  display: none;
  position: sticky;
  top: 0;
  z-index: 30;
  max-width: var(--content-max);
  margin: 0 auto;
  padding: 9px var(--side);
  gap: 4px;
  overflow-x: auto;
  scrollbar-width: none;
  background: rgba(8, 8, 7, 0.86);
  backdrop-filter: blur(15px);
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
}
.stage-nav.ready { display: flex; }
.stage-nav::-webkit-scrollbar { display: none; }

/* How far down a very long page you are. The nav tells you *where* you are but
   not how much is left, and the answer at 50+ panels is "a lot". Decorative, so
   aria-hidden in the markup. */
.nav-progress {
  position: absolute;
  left: 0;
  right: 0;
  bottom: -1px;
  height: 2px;
  background: rgba(255, 255, 255, 0.06);
}
.nav-progress i {
  display: block;
  height: 100%;
  width: 0;
  background: linear-gradient(to right, var(--accent), var(--accent-hot));
  transition: width 90ms linear;
}

.stage-nav a {
  display: flex;
  align-items: center;
  gap: 7px;
  padding: 7px 11px;
  border-radius: 9px;
  color: var(--muted);
  font-size: 12.5px;
  white-space: nowrap;
  transition: color 160ms, background 160ms;
}
.stage-nav a:hover { color: var(--paper); background: rgba(255, 255, 255, 0.04); text-decoration: none; }
.stage-nav a.current { color: var(--paper); background: rgba(255, 91, 35, 0.11); }
.nav-num {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.08em;
  color: var(--muted);
}
.stage-nav a.current .nav-num { color: var(--accent); }
/* How much is in a stage, so the index says what the scroll costs: the
   languages stage is 50 panels and the noise stage is 3, and they look
   identical in a list of titles. */
.nav-count {
  font-family: var(--mono);
  font-size: 9.5px;
  letter-spacing: 0.06em;
  color: var(--faint);
  font-variant-numeric: tabular-nums;
}
.stage-nav a.current .nav-count { color: var(--muted); }
/* Section-position indicator: inactive dots stay neutral, while the dot on the
   section currently under the sticky navigation is the sole orange marker. */
.nav-dot {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--muted);
  box-shadow: none;
  transition: background 160ms, box-shadow 160ms;
}
.stage-nav a.current .nav-dot {
  background: var(--accent);
  box-shadow: 0 0 8px var(--accent);
}

.stage h2 {
  margin: 0 0 10px;
  font-size: clamp(23px, 2.7vw, 33px);
  font-weight: 600;
  letter-spacing: -0.025em;
}

.question {
  margin: 0 0 14px;
  color: var(--accent-hot);
  font-size: 16px;
  font-weight: 500;
  max-width: 60ch;
}

.blurb {
  margin: 0 0 26px;
  max-width: 84ch;
  color: var(--dim);
  font-size: 14.5px;
}
.blurb code { color: var(--paper-soft); }

/* -------------------------------------------------------------- transport */

.transport {
  display: flex;
  align-items: center;
  gap: 14px;
  margin-bottom: 20px;
  padding: 13px 16px;
  border: 1px solid var(--line-strong);
  border-radius: 14px;
  background: rgba(6, 5, 4, 0.5);
  backdrop-filter: blur(13px);
  flex-wrap: wrap;
}

.transport button {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  border: 0;
  border-radius: 8px;
  padding: 10px 16px;
  cursor: pointer;
  background: var(--paper);
  color: var(--ink);
  transition: transform 180ms, background 180ms;
}
.transport button:hover { background: #fff; transform: translateY(-1px); }

.transport button.ghost {
  background: transparent;
  color: var(--paper-soft);
  border: 1px solid var(--line-strong);
}
.transport button.ghost:hover { background: rgba(255, 255, 255, 0.05); }

.seek {
  flex: 1 1 220px;
  accent-color: var(--accent);
  height: 2px;
}

/* Which recording the conductor is playing. Only present when a stage's panels
   are different files driven by one clock -- the noise and long-form stages --
   because otherwise the question has one answer. */
.src {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--paper-soft);
  background: rgba(255, 255, 255, 0.05);
  border: 1px solid var(--line-strong);
  border-radius: 8px;
  padding: 8px 10px;
  max-width: 260px;
  cursor: pointer;
}

.clock {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.08em;
  color: var(--dim);
  font-variant-numeric: tabular-nums;
  min-width: 108px;
}
.rate { font-family: var(--mono); font-size: 10px; color: var(--faint); letter-spacing: 0.06em; }

/* The keyboard contract for whichever transport you last touched, stated on the
   control rather than left to be discovered. */
.keys {
  font-family: var(--mono);
  font-size: 9.5px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--faint);
  white-space: nowrap;
}
.keys kbd {
  font-family: inherit;
  border: 1px solid var(--line-strong);
  border-radius: 4px;
  padding: 1px 4px;
  color: var(--muted);
}

/* A group's transport belongs to the sub-section below it, not to the stage, so
   it is inset and accent-marked to read as attached to that group's panels
   rather than to the whole section. */
.transport.group {
  margin-left: 0;
  border-left: 2px solid rgba(255, 91, 35, 0.5);
  border-radius: 4px 14px 14px 4px;
}

/* Sub-sections, used by the languages stage to keep languages apart. */
.subgroup {
  display: flex;
  align-items: baseline;
  gap: 12px;
  margin: 34px 0 14px;
  padding-bottom: 9px;
  border-bottom: 1px solid var(--line);
}
.subgroup:first-of-type { margin-top: 22px; }
.subgroup-name {
  font-size: 17px;
  font-weight: 600;
  letter-spacing: -0.015em;
}
.subgroup-count {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--muted);
}

/* ----------------------------------------------------------------- panels */

.grid { display: grid; gap: 16px; align-items: start; }

.panel {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: rgba(24, 21, 18, 0.62);
  padding: 18px 18px 15px;
  min-width: 0;
  transition: border-color 240ms, box-shadow 240ms;
}
.panel.playing {
  border-color: rgba(255, 117, 71, 0.4);
  box-shadow: 0 0 70px rgba(255, 91, 35, 0.07);
}

.panel-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 10px;
  padding-bottom: 13px;
  border-bottom: 1px solid var(--line);
  margin-bottom: 14px;
}
.panel-head strong { font-size: 14px; font-weight: 600; letter-spacing: -0.01em; }

.badge {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.07em;
  color: var(--muted);
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.badge.ok { color: var(--ok); }

/* --------------------------------------------------------------- waveform */

.waveform-heading {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 10px;
}

.waveform {
  height: 72px;
  display: flex;
  align-items: center;
  gap: 2px;
  overflow: hidden;
  padding: 6px 0 14px;
  opacity: 0.92;
}
/* The bar count is set in app.js from the measured width, so the bars only have
   to share out what they are given: `flex: 1 1 0` lets them shrink, where
   `flex: 1 0 2px` made the row overflow its panel and get clipped. */
.waveform i {
  flex: 1 1 0;
  min-width: 1px;
  height: var(--level, 6%);
  border-radius: 2px;
  background: linear-gradient(to top, #6c2c15, var(--accent-hot) 62%, #d2ac96);
  transition: height 70ms linear, opacity 120ms;
}
.waveform i { transition: height 260ms cubic-bezier(0.2, 0.8, 0.2, 1), opacity 180ms; }

/* Played / not-yet-played, so the reveal front is legible without hunting for
   it. Unplayed bars dim rather than vanish: the shape of the whole clip is
   information. */
.waveform i { opacity: 0.28; }
.waveform i.played { opacity: 1; }
.waveform i.head {
  background: linear-gradient(to top, #ff5b23, #ffd0b8);
  box-shadow: 0 0 12px rgba(255, 91, 35, 0.7);
}

/* ------------------------------------------------------------- transcript */

/* The transcript is what the page is for, and it was one of seven blocks in a
   panel competing on roughly equal terms. It now sits on its own slightly
   raised surface so the eye lands there first, and everything below it is
   demoted a step. */
.transcript-wrap {
  border: 1px solid var(--line);
  border-radius: 14px;
  background: rgba(0, 0, 0, 0.24);
  padding: 13px 14px 14px;
  min-height: 176px;
  display: flex;
  flex-direction: column;
}
.panel.playing .transcript-wrap { border-color: rgba(255, 117, 71, 0.26); }

.transcript-label {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 20px;
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--muted);
}
.transcript-label .age { color: var(--faint); letter-spacing: 0.05em; }

.transcript {
  flex: 1;
  margin-top: 11px;
  font-size: 17.5px;
  line-height: 1.7;
  word-break: break-word;
  white-space: pre-wrap;
  color: var(--paper);
}
.transcript .cursor { color: var(--accent); }
/* The tokens the model has decoded but is still holding back from the committed
   prefix. Full opacity and its own hue: this is the mechanism the in-flight
   stage exists to show, and a 55%-alpha accent rendered it at 2.9:1. The dotted
   underline is what distinguishes it from committed text without relying on
   colour alone. */
.transcript .held {
  color: var(--held);
  font-style: italic;
  border-bottom: 1px dotted rgba(255, 169, 130, 0.5);
}
.transcript .held-empty {
  color: var(--faint);
  font-size: 13px;
  font-style: italic;
}
.transcript mark.hl {
  background: rgba(255, 91, 35, 0.22);
  color: #ffd9c6;
  border-bottom: 2px solid var(--accent);
  border-radius: 3px;
  padding: 0 2px;
}
.transcript .pending {
  color: var(--faint);
  font-style: italic;
  font-size: 14px;
}
/* Every committed span is rendered as an immutable piece, so it is visible
   that nothing before the cursor is ever rewritten -- only appended. A solid
   underline against the held tokens' dotted one. */
.transcript .span {
  border-bottom: 1px solid rgba(255, 117, 71, 0.22);
  padding-bottom: 1px;
}

.ref { margin-top: 11px; font-size: 12.5px; color: var(--dim); }
.ref summary {
  cursor: pointer;
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--muted);
}
.ref div { margin-top: 7px; padding-left: 10px; border-left: 1px solid var(--line); }

/* Seven numbers used to sit in one flat row of equal-weight chips, so reading
   any single one meant scanning all seven. They are now two tiers: the verdict
   that can fail, on its own line, and the measurements below it. */
.stats {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 13px;
  margin-top: 11px;
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.05em;
  color: var(--faint);
  font-variant-numeric: tabular-nums;
}
.stats .ok { color: var(--ok); }
.stats .bad { color: var(--bad); font-weight: 500; }
.stats .accent { color: var(--muted); }

/* The append-only guarantee is the one number on the panel that is a claim
   rather than a measurement, so it gets a line of its own. */
.verdict {
  display: flex;
  align-items: center;
  gap: 7px;
  margin-top: 12px;
  padding-top: 11px;
  border-top: 1px solid var(--line);
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--ok);
}
.verdict.bad { color: var(--bad); font-weight: 500; }
.verdict::before {
  content: "";
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: currentColor;
  flex: none;
}

/* What the output actually is, where that is not simply the right text. It is
   an annotation on the result rather than a warning about it, so it is set at
   prose size in --paper-soft and marked with a quiet rule, not in the red the
   append-only failure uses -- that one is a broken guarantee, this one is a
   result that is honestly poor. */
.caveat {
  margin: 10px 0 0;
  padding: 8px 11px;
  border-left: 2px solid rgba(232, 192, 122, 0.5);
  border-radius: 3px;
  background: rgba(232, 192, 122, 0.06);
  font-size: 12px;
  line-height: 1.5;
  color: var(--paper-soft);
}

/* The per-panel control. On an "independent" stage it is the only way to play
   the panel; on a "both" stage it sits under a conductor that also drives the
   panel, so it is tagged to say which of the two it is. */
.play-row {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px 10px;
  margin-top: 12px;
}
.play-tag {
  font-family: var(--mono);
  font-size: 9.5px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--faint);
  white-space: nowrap;
  flex-basis: 100%;
}

/* The per-panel control, built rather than inherited. It used to be a native
   <audio controls> with `filter: invert(0.92) hue-rotate(180deg)` over it,
   because there is no way to ask the platform for a dark one. The filter also
   inverted the focus ring — an orange ring came out blue — and it made the one
   control on the page that did not match the conductor transport. So the pieces
   the panel actually needs are drawn here, and the <audio> stays for playback
   with no controls attribute. */
.audio-ui {
  display: flex;
  align-items: center;
  gap: 9px;
  flex: 1 1 190px;
  min-width: 0;
}

.play-btn {
  flex: none;
  width: 30px;
  height: 30px;
  padding: 0;
  border: 1px solid var(--line-strong);
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.05);
  color: var(--paper);
  font-size: 11px;
  line-height: 1;
  cursor: pointer;
  transition: background 160ms, border-color 160ms, transform 160ms;
}
.play-btn:hover {
  background: rgba(255, 255, 255, 0.11);
  border-color: rgba(255, 117, 71, 0.5);
  transform: translateY(-1px);
}
.play-btn[aria-pressed="true"] {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--ink);
}

.panel-seek {
  flex: 1 1 60px;
  min-width: 0;
  accent-color: var(--accent);
  height: 2px;
  margin: 0;
}

.panel-clock {
  flex: none;
  font-family: var(--mono);
  font-size: 9.5px;
  letter-spacing: 0.05em;
  color: var(--faint);
  font-variant-numeric: tabular-nums;
  min-width: 66px;
  text-align: right;
}

/* ------------------------------------------------------------------ notes */

.notes {
  border-top: 1px solid var(--line);
  padding: 66px 0 0;
  max-width: var(--content-max);
  margin: 0 auto;
}
.notes h2 { font-size: 22px; margin-bottom: 18px; }
.notes ul { color: var(--dim); max-width: 88ch; font-size: 14.5px; padding-left: 18px; }
.notes li { margin-bottom: 9px; }
.notes b { color: var(--paper-soft); font-weight: 600; }

/* ----------------------------------------------------------- licensing */

.licence-lede {
  color: var(--paper-soft);
  font-size: 15px;
  margin-bottom: 20px;
  max-width: 78ch;
}
.licence-foot {
  color: var(--dim);
  font-size: 13px;
  line-height: 1.65;
  margin-top: 18px;
  max-width: 88ch;
}
.licence-foot b { color: var(--paper-soft); font-weight: 600; }

table.lic {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
  color: var(--dim);
}
table.lic th {
  text-align: left;
  padding: 0 14px 10px 0;
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--dimmer, var(--dim));
  border-bottom: 1px solid var(--line);
  font-weight: 500;
}
table.lic td {
  padding: 11px 14px 11px 0;
  border-bottom: 1px solid var(--line);
  vertical-align: top;
  line-height: 1.5;
}
table.lic td b { color: var(--paper-soft); font-weight: 600; }
table.lic td.nowrap { white-space: nowrap; font-family: var(--mono); font-size: 12px; }
table.lic .lic-artist { color: var(--dimmer, var(--dim)); font-size: 12px; }
table.lic .bad { color: var(--bad); }

#loading {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted);
  padding: 60px 0;
}

/* ------------------------------------------------------------ direction */

/* Eight of the panels are Egyptian Arabic. The transcript and the reference are
   the only right-to-left content on an otherwise left-to-right page, so `dir` is
   set on those two elements from clip.lang rather than on the document — the
   panel's labels, numbers and controls all stay LTR. Without this the committed
   text rendered left-aligned with its punctuation reordered, which for an
   append-only demo is exactly the wrong impression.
   `text-align: start` rather than `right`, so the same rule serves both. */
[dir="rtl"] { text-align: start; }
.transcript[dir="rtl"] { line-height: 1.85; }
/* The reveal cursor belongs at the end of the text, which in RTL is the left.
   `unicode-bidi: isolate` keeps the LTR block glyph from being reordered into
   the middle of the Arabic run. */
.transcript[dir="rtl"] .cursor { unicode-bidi: isolate; }
.ref div[dir="rtl"] {
  padding-left: 0;
  padding-right: 10px;
  border-left: 0;
  border-right: 1px solid var(--line);
}

/* The signal is a control, so it has to be reachable and legible without a
   mouse. */
.waveform:focus-visible {
  outline: 2px solid var(--accent-hot);
  outline-offset: 3px;
  border-radius: 6px;
}

/* Keyboard focus everywhere else. Default rings on a near-black ground are
   invisible in some browsers, and on the native audio controls close to it. */
:where(a, button, select, input, summary, [tabindex]):focus-visible {
  outline: 2px solid var(--accent-hot);
  outline-offset: 2px;
  border-radius: 6px;
}

@media (max-width: 1000px) {
  /* Reflow rather than collapse. A hard `1fr` turned the languages stage into
     ten stacks of five very tall panels; `auto-fit` keeps as many panels on a
     line as the width allows and wraps the rest, which is what a grid wants to
     do anyway. `!important` because the column count is set inline per stage. */
  .grid {
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 290px), 1fr)) !important;
  }
  .transport { gap: 10px; }
  .rate { display: none; }
}
@media (max-width: 640px) {
  .waveform { height: 56px; gap: 1px; }
  .transcript { font-size: 15.5px; }
  .kicker { flex-wrap: wrap; }
  .plays { margin-left: 0; }
  .stage-nav { padding-left: 12px; padding-right: 12px; }
  .stage-nav a { padding: 6px 8px; font-size: 12px; }
  .keys { display: none; }
}

/* Six titled items do not fit in 390px, so the nav scrolled horizontally with a
   hidden scrollbar: the items past the third were reachable but nothing said so.
   Below 560px the titles collapse to their numbers, which fits, and the current
   stage keeps its name so the bar still answers "where am I". */
@media (max-width: 560px) {
  .stage-nav { gap: 2px; }
  .stage-nav a { padding: 6px 9px; gap: 5px; }
  .stage-nav a .nav-name,
  .stage-nav a .nav-count { display: none; }
  /* `min-width: 0` on both, so flexbox shrinks the current entry until the row
     fits rather than relying on a viewport-width guess. The guess was 42vw and
     it overflowed by 2px the moment a seventh stage was added; shrinking to fit
     is what the layout actually means, and it holds for any number of stages. */
  .stage-nav a.current { min-width: 0; }
  .stage-nav a.current .nav-name {
    display: inline;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
}

/* The reveal itself is the content and stays; only the easing is decoration. */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .waveform i,
  .transport button,
  .play-btn,
  .nav-progress i,
  .panel,
  .stage-nav a {
    transition-duration: 1ms !important;
  }
}

/* Focused comparison layout */
body > .notes { display: none; }
.blurb { display: none; }
.shared-signal {
  margin: 18px 0 22px;
  padding: 16px 18px 18px;
  border: 1px solid rgba(255, 91, 35, .24);
  border-radius: 18px;
  background: linear-gradient(120deg, rgba(255,91,35,.10), rgba(255,255,255,.025));
}
.shared-signal .waveform-heading { margin-bottom: 10px; }
.panel[hidden] { display: none !important; }
.noise-panels { grid-template-columns: 1fr; }
.transcript-unavailable { color: var(--muted); font-size: 14px; }
.horizontal-comparison { align-items: stretch; }
.horizontal-comparison .panel { min-width: 0; }
.noise-control {
  display: grid;
  grid-template-columns: minmax(150px, .45fr) minmax(120px, .2fr) minmax(260px, 1fr);
  align-items: center;
  gap: 18px;
  margin: 18px 0;
  padding: 16px 18px 14px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: rgba(255,255,255,.025);
}
.noise-copy { display: grid; gap: 4px; }
.noise-eyebrow { color: var(--accent-hot); font: 10px/1 var(--mono); text-transform: uppercase; letter-spacing: .14em; }
.noise-copy strong { color: var(--paper-soft); font-size: 15px; }
.noise-copy small { color: var(--muted); font-size: 11px; }
.noise-current { color: var(--accent-hot); font: 13px/1 var(--mono); text-align: right; white-space: nowrap; }
.noise-slider { display: grid; gap: 8px; min-width: 0; }
.noise-slider input { width: 100%; accent-color: var(--accent); }
.noise-scale { display: flex; justify-content: space-between; gap: 8px; }
.noise-scale span { color: var(--muted); cursor: pointer; font: 10px/1 var(--mono); text-transform: uppercase; white-space: nowrap; }
.noise-scale span.active { color: var(--accent-hot); }
.empty-stage {
  margin: 22px 0 0;
  padding: 24px;
  border: 1px dashed var(--line-strong);
  border-radius: 14px;
  color: var(--muted);
  text-align: center;
  font: 13px/1.5 var(--mono);
}
@media (max-width: 700px) {
  .noise-control { grid-template-columns: 1fr auto; }
  .noise-slider { grid-column: 1 / -1; }
}
