/* =========================================================
   Swing Lab — swing.css
   Cream-first report-card surface with forest chrome.
   Brand tokens come from ../tokens.css (--rd-*). One easing
   for everything: cubic-bezier(0.2, 0.8, 0.2, 1).
   ========================================================= */

:root {
  --sw-ease: cubic-bezier(0.2, 0.8, 0.2, 1);
  --sw-work-bg: rgba(176, 67, 42, 0.10);
  --sw-work-line: rgba(176, 67, 42, 0.32);
  --sw-read-bg: rgba(107, 117, 113, 0.12);
}

* { box-sizing: border-box; }

/* Author display rules beat the browser's own [hidden] rule, so anything given
   a display value stayed on screen after show() hid it. That is why every error
   panel sat under a frozen "Reading the swing" progress block and a live Cancel
   button, and why a "Share swing card" button appeared on a read that failed.
   Caught 2026-07-26 in the no-WebGL proof shots. One rule ends the class; the
   two hand-patched exceptions further down are now redundant, not wrong. */
[hidden] { display: none !important; }

body {
  margin: 0;
  background: var(--rd-cream);
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}

main {
  flex: 1;
  width: 100%;
  max-width: 780px;
  margin: 0 auto;
  padding: var(--rd-space-4) var(--rd-space-4) var(--rd-space-6);
}

.visually-hidden {
  position: absolute !important;
  width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  clip: rect(0 0 0 0); clip-path: inset(50%);
  overflow: hidden; white-space: nowrap;
}

#work-video {
  position: absolute;
  left: -9999px;
  top: 0;
  width: 2px;
  height: 2px;
}

/* ---------- header: forest chrome ---------- */

.site-head {
  background: var(--rd-forest);
  color: var(--rd-cream);
  display: flex;
  align-items: center;
  gap: var(--rd-space-4);
  flex-wrap: wrap;
  padding: var(--rd-space-3) var(--rd-space-4);
}
.head-lockup {
  display: inline-flex;
  align-items: center;
  gap: var(--rd-space-2);
  text-decoration: none;
}
.head-back {
  color: var(--rd-cream);
  font-size: var(--rd-small);
  text-decoration-color: rgba(245, 241, 232, 0.4);
}
.head-back:hover { text-decoration-color: var(--rd-gold); }
.preview-pill {
  margin-left: auto;
  font-family: var(--rd-mono);
  font-size: 0.7rem;
  font-weight: 500;
  letter-spacing: 0.03em;
  color: var(--rd-cream);
  border: 1px solid var(--rd-gold);
  border-radius: var(--rd-radius-pill);
  padding: 4px 12px;
  white-space: nowrap;
}
/* Narrow phones: the full line clips, so wrap the pill text instead. */
@media (max-width: 480px) {
  .preview-pill {
    white-space: normal;
    text-align: center;
    line-height: 1.35;
    border-radius: var(--rd-radius);
    max-width: 100%;
  }
}

/* ---------- hero ---------- */

.hero { padding-top: var(--rd-space-7); }
.lab-title {
  font-size: clamp(3rem, 9vw, var(--rd-display-xxl));
  line-height: 0.95;
}
.lab-eyebrow { margin-top: var(--rd-space-2); }
.lab-lede {
  margin: var(--rd-space-4) 0 var(--rd-space-5);
  max-width: 38rem;
}

.privacy-callout {
  display: flex;
  gap: var(--rd-space-3);
  align-items: flex-start;
  background: var(--rd-cream-2);
  border-left: 3px solid var(--rd-gold);
  border-radius: var(--rd-radius-sm);
  padding: var(--rd-space-3) var(--rd-space-4);
  max-width: 38rem;
}
.privacy-callout p { margin: 0; font-size: var(--rd-small); font-weight: 500; }
.privacy-glyph {
  width: 20px; height: 20px;
  flex: 0 0 auto;
  margin-top: 2px;
  stroke: var(--rd-forest);
  stroke-width: 1.8;
  fill: none;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* ---------- setup ---------- */

.setup-grid {
  display: grid;
  gap: var(--rd-space-4);
  grid-template-columns: 1fr;
  margin-top: var(--rd-space-7);
}
@media (min-width: 720px) {
  .setup-grid { grid-template-columns: 1fr 1fr; }
}

.setup-card {
  background: var(--rd-cream-2);
  border: 1px solid var(--rd-border);
  border-radius: var(--rd-radius);
  padding: var(--rd-space-5);
}
.setup-card h3 { margin-bottom: var(--rd-space-4); }

.field-row {
  display: flex;
  align-items: center;
  gap: var(--rd-space-3);
  flex-wrap: wrap;
  margin-bottom: var(--rd-space-4);
}
.field-label {
  font-family: var(--rd-body);
  font-size: var(--rd-caption);
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--rd-fg-muted);
  min-width: 52px;
}
.chip-group { display: flex; gap: var(--rd-space-2); flex-wrap: wrap; }
.chip {
  font-family: var(--rd-body);
  font-size: var(--rd-small);
  font-weight: 600;
  color: var(--rd-forest);
  background: var(--rd-cream);
  border: 1px solid var(--rd-border);
  border-radius: 0.5rem;
  padding: 6px 14px;
  cursor: pointer;
  transition: background 180ms var(--sw-ease), color 180ms var(--sw-ease),
              transform 180ms var(--sw-ease), box-shadow 180ms var(--sw-ease);
}
.chip:hover { transform: translateY(-1px); }
.chip[aria-pressed="true"] {
  background: var(--rd-forest);
  color: var(--rd-cream);
  border-color: var(--rd-forest);
  box-shadow: var(--rd-cta-lift);
}
.field-hint {
  font-size: var(--rd-small);
  color: var(--rd-fg-muted);
  margin: var(--rd-space-2) 0 0;
}

/* filming guide */
.film-guide { width: 100%; height: auto; display: block; margin-bottom: var(--rd-space-3); }
.film-guide .fg-frame {
  fill: none;
  stroke: var(--rd-gold);
  stroke-width: 1.5;
  stroke-dasharray: 6 5;
}
.film-guide .fg-ground { stroke: var(--rd-forest); opacity: 0.2; stroke-width: 2; }
/* The batter's GEOMETRY comes from figures.js (see the comment in index.html);
   these two rules only restate it in the diagram's ink, so a posed human renders
   in the same flat two-colour register as the frame, the phone and the sight line.
   Every node the module emits declares fill or stroke explicitly, so matching on
   the attribute repaints all of it and adds nothing: no default stroke is grown
   onto a shape that never had one, and the fill="none" limbs stay strokes.
   The module's own paint is built for a forest field — its cream pants measure
   #EDE7D4 against this card's #EDE7D6 and the front leg disappears. That is why
   this is flattened rather than shipped in colour. */
.film-guide .fg-batter [fill]:not([fill="none"])     { fill: var(--rd-forest); }
.film-guide .fg-batter [stroke]:not([stroke="none"]) { stroke: var(--rd-forest); }
.film-guide .fg-tag-height { fill: var(--rd-gold); }
.film-guide .fg-phone line,
.film-guide .fg-phone rect {
  stroke: var(--rd-forest);
  stroke-width: 2.5;
  fill: none;
  stroke-linecap: round;
}
.film-guide .fg-sight { stroke: var(--rd-gold); stroke-width: 1.5; stroke-dasharray: 2 4; }
.film-guide .fg-tag {
  font-family: var(--rd-mono);
  font-size: 9px;
  fill: var(--rd-cool-gray);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.film-list {
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: var(--rd-small);
}
.film-list li {
  padding: 5px 0 5px 18px;
  position: relative;
}
.film-list li::before {
  content: "";
  position: absolute;
  left: 0; top: 12px;
  width: 8px; height: 3px;
  background: var(--rd-gold);
  border-radius: 2px;
  transform: skewX(-18deg);
}

/* ---------- buttons (locked spec) ---------- */

.btn {
  display: inline-block;
  font-family: var(--rd-display);
  font-weight: 400;
  font-size: 1.15rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  line-height: 1.1;
  padding: 0.75rem 1.5rem;
  border-radius: 0.5rem;
  border: 0;
  cursor: pointer;
  text-align: center;
  text-decoration: none;
  transition: transform 180ms var(--sw-ease), background 180ms var(--sw-ease);
}
.btn-primary {
  background: var(--rd-forest);
  color: var(--rd-cream);
  box-shadow: var(--rd-cta-lift); /* 2px gold bottom border */
}
.btn-primary:hover { background: var(--rd-forest-2); transform: translateY(-1px); }
.btn-primary:active { background: var(--rd-forest-3); transform: translateY(0); }
.btn-secondary {
  background: var(--rd-cream);
  color: var(--rd-forest);
  border: 1.5px solid var(--rd-forest);
  padding: calc(0.75rem - 1.5px) calc(1.5rem - 1.5px);
}
.btn-secondary:hover { transform: translateY(-1px); }
.btn:focus-visible { outline: 2px solid var(--rd-gold); outline-offset: 2px; }

.analyze-cta {
  margin-top: var(--rd-space-6);
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--rd-space-3);
}
.mock-banner {
  font-family: var(--rd-mono);
  font-size: var(--rd-caption);
  color: var(--rd-forest);
  background: var(--rd-cream-3);
  border: 1px dashed var(--rd-gold);
  border-radius: var(--rd-radius-sm);
  padding: 6px 10px;
  margin: 0;
}
.fine-print {
  font-size: var(--rd-caption);
  color: var(--rd-fg-muted);
  max-width: 36rem;
  margin: var(--rd-space-2) 0 0;
}

/* ---------- analyzing ---------- */

#screen-analyzing {
  padding-top: var(--rd-space-9);
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: var(--rd-space-4);
}
.analyzing-title { font-size: var(--rd-display-l); }
.progress-track {
  width: min(420px, 90%);
  height: 14px;
  background: var(--rd-forest);
  border-radius: 7px;
  overflow: hidden;
}
.progress-fill {
  height: 100%;
  width: 0%;
  background: var(--rd-gold);
  border-radius: 7px;
  transition: width 200ms var(--sw-ease);
}
.progress-count {
  font-family: var(--rd-mono);
  font-variant-numeric: tabular-nums;
  font-size: var(--rd-small);
  font-weight: 500;
  color: var(--rd-fg-strong);
}
/* The one calm line shown while the no-acceleration reader runs. Same muted
   register as the privacy line: it is a fact about this browser, not a warning. */
.progress-note {
  font-size: var(--rd-small);
  color: var(--rd-fg-muted);
  max-width: 30rem;
  margin: 0;
}
.privacy-line {
  font-size: var(--rd-small);
  color: var(--rd-fg-muted);
  max-width: 30rem;
  margin: 0;
}

/* ---------- report: ACT 1, THE CALL ----------------------------------------
   directive 2026-07-27 §4a. This replaces the old grade band entirely. The
   72 px ON TRACK chip in a forest box was the largest type on the page and the
   fault was the smallest; that inversion was the whole hierarchy bug. The clip
   is the fold now, the fault name is the largest thing on the page, and the
   grade is a 20 px corner stamp with no box, no border and no shadow.

   RETIRED HERE: .grade-chip, .grade-line, .grade-sub, .grade-score,
   .category-row / .category, .consistency-line, .fps-badge, .cmp-rail /
   .rail-*, .compare-legend / .cmp-swatch, .cmp-joints, .phase-time,
   .fixes-intro, and the ?hero= present-mode block. */

/* ---------- ACT 1, THE SWING (design ruling REV2 2026-08-05 §2) ----------
   The stage is the first thing on the report. Full bleed out of main's 780px
   column on a phone; held to the body measure on desktop so a landscape frame
   has no dead side margins. Nothing is drawn over it and no heading sits above
   it — the player's own swing is the first pixel. */
.act-stage {
  margin-left: calc(50% - 50vw);
  margin-right: calc(50% - 50vw);
  width: 100vw;
  margin-top: calc(var(--rd-space-6) * -1);
  display: flex;
  flex-direction: column;
  align-items: center;
}
.act-stage #compare-section { width: 100%; margin-top: 0; }
.act-stage .compare-wrap { width: 100%; }
.act-stage .compare-col {
  width: 100%;
  max-width: 720px;
  margin: 0 auto;
  gap: var(--rd-space-3);
}
/* On a phone the frame runs edge to edge: no card, no border, no radius.
   The forest card returns at the body measure, where it reads as a stage. */
.act-stage .compare-stage {
  background: #06130E;
  border: none;
  border-radius: 0;
  padding: 0;
}
.act-stage .compare-frame { border-radius: 0; }
.act-stage .compare-controls,
.act-stage .stage-line,
.act-stage .sweep-refusal { padding-left: var(--rd-space-4); padding-right: var(--rd-space-4); }

/* The phase rail: R3, the primary control. Names, not ticks. 44px minimum
   target, scrollable rather than shrunk, and never abbreviated. */
.stage-rail {
  display: flex;
  gap: 2px;
  width: 100%;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}
.stage-rail::-webkit-scrollbar { display: none; }
.stage-phase {
  flex: 0 0 auto;
  min-height: 44px;
  padding: 0 12px;
  border: none;
  background: none;
  cursor: pointer;
  font-family: var(--rd-mono);
  font-size: 0.72rem;
  font-weight: 500;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  white-space: nowrap;
  color: var(--rd-fg-muted);
  border-bottom: 2px solid transparent;   /* the nav underline, docs/21 §7.6 */
  transition: color 140ms var(--sw-ease);
}
.stage-phase[aria-current="true"] {
  color: var(--rd-forest);
  font-weight: 700;
  border-bottom-color: var(--rd-gold);
}
.stage-phase:focus-visible { outline: 2px solid var(--rd-gold); outline-offset: -2px; }
.stage-fine { display: flex; align-items: center; gap: var(--rd-space-3); width: 100%; }
/* The one line under the stage, composed per state. */
.stage-line {
  font-size: var(--rd-small);
  line-height: 1.5;
  color: var(--rd-fg-muted);
  margin: 0;
  max-width: 38rem;
}

.act-call {
  margin-top: var(--rd-space-4);
}
.call-copy {
  max-width: 34rem;
}
.call-eyebrow {
  font-family: var(--rd-mono);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--rd-gold-2);            /* on cream the eyebrow is gold-2, tokens.css .rd-eyebrow */
  margin: 0 0 var(--rd-space-2);
}
/* Same face, same size it measured at 390 wide before the move (13vw = 50.7px).
   The type did not shrink; it changed ground, forest on cream. */
.call-fault {
  font-family: var(--rd-display);
  font-size: clamp(44px, 13.4vw, 96px);
  line-height: 0.9;
  letter-spacing: 0.01em;
  text-transform: uppercase;
  color: var(--rd-forest);
  margin: 0;
  text-wrap: balance;
}
.call-line {
  font-family: var(--rd-body);
  font-size: 17px;
  font-weight: 400;
  line-height: 1.35;
  color: var(--rd-fg);
  margin: var(--rd-space-3) 0 0;
  max-width: 34rem;
}
/* THE TALLY AND THE SCOPE LINE, authored (2026-08-05). swing-app.js creates
   both elements and injects a stylesheet ONLY when the sheet does not already
   define .call-tally — the deferral it documents. They are authored here now
   because the block moved onto cream and the injected rule paints them cream,
   which on cream is invisible. Forest measures 8.7:1 on this ground. */
.call-tally, .call-scope {
  font-family: var(--rd-mono);
  font-size: 13px;
  letter-spacing: 0.04em;
  line-height: 1.45;
  text-transform: uppercase;
  color: var(--rd-forest);
  max-width: 34rem;
}
.call-tally { font-weight: 700; margin: var(--rd-space-4) 0 0; }
.call-scope { font-weight: 500; margin: 6px 0 0; }
.call-cue {
  width: 26px; height: 26px;
  margin: var(--rd-space-3) 0 0;
  color: var(--rd-forest);
  opacity: 0.5;
}

/* ---------- ACT 2, THE PROOF (§4b) ---------- */
.act-proof { margin-top: var(--rd-space-2); }
.proof-pair {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--rd-space-3);
  align-items: start;
}
.proof-still { margin: 0; }
.proof-shot {
  display: block;
  position: relative;          /* the one construct registers on top of the still */
  background: #06130E;
  border-radius: var(--rd-radius-sm);
  overflow: hidden;
  line-height: 0;
}
.proof-canvas { display: block; width: 100%; height: auto; }
/* THE ONE CONSTRUCT (ruling 2026-08-05 R1). Same viewBox the slow-mo stage
   maps into and the same crop the still was cut from, stretched to the exact
   canvas box, so the lines land on the body and not near it. Decorative: the
   caption carries the number, and the geometry is aria-hidden. */
.proof-geo {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}
.proof-cap {
  display: block;
  font-family: var(--rd-display);
  font-size: 18px;
  line-height: 1;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--rd-forest);
  margin-top: var(--rd-space-2);
}
.proof-line {
  font-family: var(--rd-body);
  font-size: 16px;
  line-height: 1.45;
  color: var(--rd-fg);
  margin: var(--rd-space-4) 0 0;
  max-width: 34rem;
}
@media (prefers-reduced-motion: no-preference) {
  .act-proof .proof-still { animation: proofIn 220ms var(--sw-ease) both; }
  .act-proof .proof-still:nth-child(2) { animation-delay: 80ms; }
}
@keyframes proofIn { from { opacity: 0; } to { opacity: 1; } }

/* ---------- ACT 3, THE WORK (§4c) ---------- */
.act-work { margin-top: var(--rd-space-2); }
.work-name {
  font-family: var(--rd-display);
  font-size: 28px;
  line-height: 1;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--rd-forest);
  margin: 0;
}
.work-desc {
  font-size: 16px;
  line-height: 1.5;
  color: var(--rd-fg);
  margin: var(--rd-space-3) 0 0;
  max-width: 34rem;
}
.work-chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--rd-space-2);
  margin: var(--rd-space-4) 0 0;
  padding-top: var(--rd-space-3);
  border-top: 2px solid var(--rd-gold);   /* gold 2 of 3 (§4h): the drill-chip rule */
}
.work-chip {
  font-family: var(--rd-mono);
  font-variant-numeric: tabular-nums;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--rd-forest);
  border: 1px solid var(--rd-border);
  border-radius: var(--rd-radius-pill);
  padding: 5px 12px;
  background: var(--rd-cream-2);
}
.work-more {
  margin-top: var(--rd-space-4);
  background: transparent;
  border: 1px solid var(--rd-forest);
  border-radius: var(--rd-radius-pill);
  color: var(--rd-forest);
  font-family: var(--rd-body);
  font-size: var(--rd-small);
  font-weight: 600;
  padding: 8px 18px;
  cursor: pointer;
}
.work-more:focus-visible { outline: 2px solid var(--rd-gold); outline-offset: 2px; }
.work-extra { margin-top: var(--rd-space-4); }
.work-extra-row + .work-extra-row { margin-top: var(--rd-space-5); }
.work-extra-name {
  font-family: var(--rd-display);
  font-size: 20px;
  line-height: 1;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--rd-forest);
  margin: 0;
}

/* ---------- ACT 4, THE DOORS (§4d) ---------- */
.doors { margin-top: var(--rd-space-2); }
.door { border-top: 1px solid var(--rd-forest); }
.door:last-of-type { border-bottom: 1px solid var(--rd-forest); }
.door-head {
  display: flex;
  align-items: center;
  gap: var(--rd-space-3);
  padding: var(--rd-space-4) 0;
  cursor: pointer;
  list-style: none;
}
.door-head::-webkit-details-marker { display: none; }
.door-head:focus-visible { outline: 2px solid var(--rd-gold); outline-offset: -2px; }
.door-label {
  font-family: var(--rd-display);
  font-size: 20px;
  line-height: 1;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--rd-forest);
}
.door-count {
  margin-left: auto;
  font-family: var(--rd-mono);
  font-variant-numeric: tabular-nums;
  font-size: var(--rd-small);
  font-weight: 700;
  color: var(--rd-fg-muted);
}
.door-chev {
  width: 16px; height: 16px;
  color: var(--rd-forest);
  flex: 0 0 auto;
  transition: transform 240ms var(--sw-ease);
}
.door[open] .door-chev { transform: rotate(90deg); }
.door-body { padding: 0 0 var(--rd-space-6); }
/* A closed door renders NOTHING behind it. Chrome keeps closed <details>
   content in the box tree under content-visibility, which left the checkpoint
   cards, the sweep stage and fault #2's drills measurable (and, on some
   assistive paths, reachable) while the door read as closed. display:none is
   the honest state: closed means gone. */
.door:not([open]) .door-body { display: none; }
/* Same rule for the benchmarks block at the close: a closed disclosure is not
   part of the default state, and it should not be measurable as if it were. */
.sources:not([open]) .sources-body { display: none; }
.second-name {
  font-family: var(--rd-display);
  font-size: 24px;
  line-height: 1;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--rd-forest);
  margin: 0;
}
.second-line { font-size: 16px; line-height: 1.5; margin: var(--rd-space-3) 0 0; max-width: 34rem; }
.second-drill {
  font-family: var(--rd-display);
  font-size: 20px;
  line-height: 1;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--rd-forest);
  margin: var(--rd-space-5) 0 0;
}
@media (prefers-reduced-motion: reduce) {
  .door-chev { transition: none; }
}

/* ---------- report meta, at the close (§4e) ---------- */
.report-meta {
  font-size: var(--rd-small);
  color: var(--rd-fg-muted);
  margin: var(--rd-space-3) 0 0;
}

/* ---------- ACT 4i, desktop: same page, wider, one column ---------- */
@media (min-width: 760px) {
  .proof-pair { gap: var(--rd-space-5); max-width: 720px; }
  /* The stage holds the report's own 720px measure rather than running to the
     window edge. A landscape frame at the body measure is what removes the
     dead side margins, with no special desktop layout (REV2 §2 Q5). */
  .act-stage .compare-stage {
    border: 1px solid rgba(245, 241, 232, 0.12);
    border-radius: var(--rd-radius);
    padding: var(--rd-space-3);
  }
  .act-stage .compare-frame { border-radius: calc(var(--rd-radius) - 5px); }
  .act-stage .compare-controls,
  .act-stage .stage-line,
  .act-stage .sweep-refusal { padding-left: 0; padding-right: 0; }
}

/* ---------- phase strip ---------- */

.phase-strip {
  display: flex;
  gap: var(--rd-space-3);
  overflow-x: auto;
  padding-bottom: var(--rd-space-2);
  -webkit-overflow-scrolling: touch;
}
.phase-item { margin: 0; flex: 0 0 auto; }
.phase-item canvas {
  display: block;
  border-radius: var(--rd-radius-sm);
  border: 1px solid var(--rd-border);
  background: var(--rd-cream-2);
}
.phase-cap {
  display: block;
  margin-top: 4px;
}
.phase-name {
  font-family: var(--rd-mono);
  font-size: 0.65rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--rd-fg-strong);
}

/* ---------- checkpoint cards ---------- */

.cp-group { margin-bottom: var(--rd-space-5); }
.cp-group-title {
  font-size: 1.25rem;
  color: var(--rd-fg-muted);
  margin-bottom: var(--rd-space-3);
}
.cp-card {
  background: var(--rd-cream-2);
  border: 1px solid var(--rd-border);
  border-left-width: 3px;
  border-radius: var(--rd-radius);
  padding: var(--rd-space-4) var(--rd-space-5);
  margin-bottom: var(--rd-space-3);
}
.cp-card.is-on { border-left-color: var(--rd-forest); }
.cp-card.is-work { border-left-color: var(--rd-bad); }
.cp-card.is-read { border-left-color: var(--rd-cool-gray); }
.cp-card.is-unsure { border-left-color: var(--rd-gold-2); }
.cp-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--rd-space-3);
  flex-wrap: wrap;
  margin-bottom: var(--rd-space-2);
}
.cp-name { font-size: 1.3rem; }
.cp-note { margin: 0; font-size: var(--rd-small); }
.cp-value {
  font-family: var(--rd-mono);
  font-variant-numeric: tabular-nums;
  font-size: var(--rd-caption);
  font-weight: 500;
  color: var(--rd-fg-strong);
  margin-top: var(--rd-space-2);
}
.cp-conf {
  font-family: var(--rd-mono);
  font-size: 0.65rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--rd-fg-muted);
  margin-top: 4px;
}

.band-chip {
  font-family: var(--rd-body);
  font-size: var(--rd-caption);
  font-weight: 700;
  letter-spacing: 0.02em;
  border-radius: var(--rd-radius-sm);
  padding: 4px 10px;
  white-space: nowrap;
}
.band-on {
  background: var(--rd-forest);
  color: var(--rd-cream);
  box-shadow: var(--rd-cta-lift);
  animation: swCorrect 300ms var(--sw-ease) both;
}
.band-work {
  background: var(--sw-work-bg);
  color: var(--rd-bad);
  border: 1px solid var(--sw-work-line);
}
.band-read {
  background: var(--sw-read-bg);
  color: var(--rd-cool-gray);
}
/* UNSURE — measured but not clean enough to grade on this clip. Neutral, honest,
   never a graded stamp. Quiet cream fill with a gold hairline (not forest, not red). */
.band-unsure {
  background: var(--rd-cream-3);
  color: var(--rd-fg-muted);
  border: 1px solid var(--rd-gold-2);
}

/* Dev build stamp — set by swing-app.js so it ONLY shows when fresh JS runs (stale-cache tell). */
.build-stamp {
  position: fixed; right: 6px; bottom: 6px; z-index: 9999; pointer-events: none;
  font: 600 10px/1 ui-monospace, SFMono-Regular, Menlo, monospace;
  color: var(--rd-gold); background: rgba(4, 28, 21, 0.7);
  padding: 3px 7px; border-radius: 6px; letter-spacing: 0.03em;
}
.build-stamp:empty { display: none; }

/* ---------- priority fixes / drills ---------- */

.fault-block { margin-bottom: var(--rd-space-7); }
.fault-name { font-size: 1.5rem; margin-bottom: var(--rd-space-1); }
.fault-line { font-size: var(--rd-small); color: var(--rd-fg); max-width: 38rem; margin-bottom: var(--rd-space-4); }
.drill-list { display: grid; gap: var(--rd-space-3); }

.drill-card {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--rd-space-3);
  background: var(--rd-cream-2);
  border: 1px solid var(--rd-border);
  border-radius: var(--rd-radius);
  padding: var(--rd-space-4);
}
@media (min-width: 620px) {
  .drill-card { grid-template-columns: 220px 1fr; align-items: center; }
}
.drill-anim {
  /* The pose-read SVG carries its own forest panel + radius;
     this wrapper stays plain so the caption sits on card cream. */
  background: none;
  border: 0;
}
.drill-row {
  background: var(--rd-cream-2);
  border: 1px solid var(--rd-border);
  border-radius: var(--rd-radius);
  padding: var(--rd-space-3) var(--rd-space-4);
}
.drill-name { font-size: 1.2rem; margin-bottom: 4px; }
.drill-desc { font-size: var(--rd-small); margin: 0 0 var(--rd-space-2); }
.drill-meta {
  display: flex;
  gap: var(--rd-space-4);
  flex-wrap: wrap;
}
.drill-equip, .drill-reps {
  font-family: var(--rd-mono);
  font-size: 0.65rem;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--rd-fg-muted);
}
.drill-reps { color: var(--rd-fg-strong); font-weight: 700; }

/* ---------- history ---------- */

.history-count {
  font-family: var(--rd-mono);
  font-variant-numeric: tabular-nums;
  font-size: var(--rd-small);
  color: var(--rd-fg-strong);
  margin-bottom: var(--rd-space-3);
}
.history-strip { display: flex; gap: var(--rd-space-2); flex-wrap: wrap; }
.hist-chip {
  font-family: var(--rd-mono);
  font-size: 0.65rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--rd-forest);
  background: var(--rd-cream-3);
  border: 1px solid var(--rd-border);
  border-radius: var(--rd-radius-sm);
  padding: 4px 8px;
}
.history-note { font-size: var(--rd-caption); color: var(--rd-fg-muted); margin-top: var(--rd-space-3); }

/* ---------- the refusal, R5 (docs/87 2c) ----------
   Body register, not a warning box: no red, no icon, no border. A refusal is a
   first-class result here, so it reads like the rest of the report rather than
   like an error the player caused. The fix line is the only emphasis. */
.act-refusal {
  margin: var(--rd-space-6) 0 0;
  max-width: 38rem;
}
.refusal-line {
  font-size: var(--rd-body-size);
  margin: 0 0 var(--rd-space-3);
}
.refusal-fix { font-weight: 600; margin-bottom: 0; }

/* The barrel refusal, in the Act-5 register, where the bat would have been:
   under the stage, which is now the first thing on the report (REV2 §4). */
.sweep-refusal {
  font-size: var(--rd-small);
  color: var(--rd-fg-muted);
  margin: 0;
  max-width: 38rem;
}

/* ---------- runtime invalid (docs/87 2d) ----------
   Shares the reshoot panel's shell so it reads as the same kind of surface,
   but it is a different condition and carries no filming advice. */
#runtime-panel {
  background: var(--rd-cream-2);
  border: 1px solid var(--rd-border);
  border-left: 3px solid var(--rd-gold);
  border-radius: var(--rd-radius);
  padding: var(--rd-space-6);
  margin-top: var(--rd-space-6);
}
#runtime-panel .btn { margin-top: var(--rd-space-5); margin-right: var(--rd-space-3); }

/* ---------- reshoot ---------- */

#reshoot-panel {
  background: var(--rd-cream-2);
  border: 1px solid var(--rd-border);
  border-left: 3px solid var(--rd-gold);
  border-radius: var(--rd-radius);
  padding: var(--rd-space-6);
  margin-top: var(--rd-space-6);
}
.reshoot-title { font-size: var(--rd-display-m); margin-bottom: var(--rd-space-3); }
.reshoot-detail { font-size: var(--rd-body-size); max-width: 38rem; }
#reshoot-panel .film-list { margin: var(--rd-space-4) 0 var(--rd-space-5); }
/* The actionable step (which setting, where) sits under the calm line and
   reads like part of the sentence, not like a warning. */
.reshoot-help { margin-top: var(--rd-space-3); font-weight: 600; }
.reshoot-trace {
  margin: var(--rd-space-4) 0;
  max-width: 45rem;
}
.reshoot-trace canvas {
  display: block;
  width: 100%;
  height: auto;
  background: #041c15;
  border-radius: var(--rd-radius-sm);
}
.reshoot-trace figcaption {
  margin-top: var(--rd-space-2);
  color: var(--rd-fg-muted);
  font-size: var(--rd-caption);
}
/* Evidence, discreet on purpose: the real error and its code, plus the way to
   self-diagnose. Small and muted so it never competes with the coach line, but
   always present, because this is what a generic message used to destroy. */
.reshoot-tech {
  margin-top: var(--rd-space-5);
  font-family: ui-monospace, Menlo, monospace;
  font-size: var(--rd-caption);
  color: var(--rd-fg-muted);
  white-space: pre-wrap;
  word-break: break-word;
  max-width: 38rem;
}
.reshoot-diag { margin-top: var(--rd-space-2); font-size: var(--rd-caption); color: var(--rd-fg-muted); }
.reshoot-diag a { color: inherit; }

.report-actions {
  margin-top: var(--rd-space-2);
  display: flex;
  align-items: center;
  gap: var(--rd-space-5);
  flex-wrap: wrap;
}
.action-link { font-size: var(--rd-small); }

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

.site-foot {
  background: var(--rd-forest);
  color: var(--rd-cream);
  padding: var(--rd-space-6) var(--rd-space-4);
  text-align: center;
}
.site-foot p { margin: 0 auto var(--rd-space-3); max-width: 44rem; color: var(--rd-cream); }
.foot-privacy { font-size: var(--rd-small); font-weight: 600; }
.foot-disclaimer { font-size: var(--rd-caption); opacity: 0.85; }
.foot-tag {
  font-family: var(--rd-display);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  font-size: 1.1rem;
  color: var(--rd-gold);
  margin-bottom: 0 !important;
}

/* =========================================================
   SAFE AREA (iOS), added 2026-08-05
   index.html sets viewport-fit=cover, so the page draws UNDER the notch and
   the home indicator. This stylesheet had no inset rule of any kind, so the
   preview pill in .site-head rendered under the clock, the location arrow,
   the carrier line and the battery. Photographed by the founder.
   Same shape as the two surfaces that already handle it: app/styles.css:2015
   (body insets inside @supports) and :735 (header top inset in a calc).
   ========================================================= */
@supports (padding: max(0px)) {
  body {
    padding-left: env(safe-area-inset-left, 0px);
    padding-right: env(safe-area-inset-right, 0px);
    padding-bottom: env(safe-area-inset-bottom, 0px);
  }
  /* The chrome bar clears the status bar rather than sitting under it. */
  .site-head {
    padding-top: calc(env(safe-area-inset-top, 0px) + var(--rd-space-3));
  }
  /* position: fixed opts OUT of the body padding, so it needs its own inset or
     it lands on the home indicator. */
  .build-stamp {
    right: calc(6px + env(safe-area-inset-right, 0px));
    bottom: calc(6px + env(safe-area-inset-bottom, 0px));
  }
  /* The one full-bleed element on the page. 100vw INCLUDES the notch gutters,
     so in landscape the stage would run back under the notch the body padding
     just cleared. Width and offset are both taken off the body content box.
     With zero insets this reduces exactly to the base rule above. */
  .act-stage {
    width: calc(100vw - env(safe-area-inset-left, 0px) - env(safe-area-inset-right, 0px));
    margin-left: calc(50% - 50vw
      + (env(safe-area-inset-left, 0px) + env(safe-area-inset-right, 0px)) / 2);
    margin-right: 0;
  }
}

/* =========================================================
   POSE-READ DRILL FIGURES
   The drill demos are the analyzer's own landmark skeleton:
   cream bones and joints on a forest panel, gold bat with a
   fading tip trace, at most one extra gold accent per drill.
   Geometry is driven from drills.js (rAF, in-viewport only,
   max three at once); these rules carry color and weight.
   ========================================================= */

.pr-svg {
  display: block;
  width: 100%;
  max-width: 220px;
  height: auto;
  margin: 0 auto;
  border-radius: var(--rd-radius);
}
.pr-svg .pr-bg { fill: var(--rd-forest); }
.pr-svg .pr-grid line { stroke: var(--rd-cream); }
.pr-svg .pr-floor { opacity: 0.26; stroke-width: 1.5; stroke-linecap: round; }
.pr-svg .pr-tick { opacity: 0.13; stroke-width: 1; }
.pr-svg .pr-bone { stroke: var(--rd-cream); stroke-width: 2.5; stroke-linecap: round; fill: none; }
.pr-svg .pr-far { opacity: 0.55; } /* rear-side limbs sit back in depth */
.pr-svg .pr-joint { fill: var(--rd-cream); }
.pr-svg .pr-halo { fill: var(--rd-cream); opacity: 0.18; } /* soft landmark glow */
.pr-svg .pr-head { fill: none; stroke: var(--rd-cream); stroke-width: 2.5; }
.pr-svg .pr-bat { stroke: var(--rd-gold); stroke-width: 3; stroke-linecap: round; }
.pr-svg .pr-goldhip { stroke: var(--rd-gold); stroke-width: 3; } /* separation drill hip line */
.pr-svg .pr-trace path {
  fill: none;
  stroke: var(--rd-gold);
  stroke-width: 2.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.pr-svg .pr-tr-old { opacity: 0.16; }
.pr-svg .pr-tr-mid { opacity: 0.44; }
.pr-svg .pr-tr-new { opacity: 0.85; }
.pr-svg .pr-prop-gold { stroke: var(--rd-gold); stroke-width: 3; stroke-linecap: round; }
.pr-svg .pr-prop { stroke: var(--rd-cream); opacity: 0.45; stroke-width: 2.5; stroke-linecap: round; }
.pr-svg .pr-ball { fill: var(--rd-cream); opacity: 0.9; }
.pr-svg .pr-bandline {
  stroke: var(--rd-gold);
  stroke-width: 2.5;
  stroke-dasharray: 5 4;
  stroke-linecap: round;
}
.pr-svg .pr-legflash {
  stroke: var(--rd-gold);
  stroke-width: 4;
  fill: none;
  stroke-linecap: round;
  stroke-linejoin: round;
  opacity: 0;
}
.pr-svg .pr-chip rect {
  fill: rgba(245, 241, 232, 0.07);
  stroke: rgba(245, 241, 232, 0.35);
  stroke-width: 0.75;
}
.pr-svg .pr-chip text {
  font-family: var(--rd-mono);
  font-size: 8.5px;
  font-weight: 500;
  letter-spacing: 0.08em;
  fill: var(--rd-cream);
}
.pr-caption {
  font-family: var(--rd-mono);
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.02em;
  line-height: 1.45;
  color: var(--rd-cool-gray);
  text-align: center;
  max-width: 230px;
  margin: 8px auto 0;
}

/* ---------- reduced motion: zero durations, end-states direct ---------- */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
  /* Pose-read drill figures: drills.js renders a static teaching
     pose with the full bat trace instead of attaching animators. */
  .btn:hover, .chip:hover, .btn-secondary:hover { transform: none; }
  .band-on { animation: none !important; } /* settle state, no flash */
}

/* ---------- sources / methodology panel ---------- */
.sources {
  margin-top: var(--rd-space-6);
  border-top: 1px solid var(--rd-border);
  padding-top: var(--rd-space-4);
}
.sources > summary {
  font-family: var(--rd-body);
  font-size: var(--rd-small);
  font-weight: 700;
  color: var(--rd-forest);
  cursor: pointer;
  list-style: none;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 0;
}
.sources > summary::-webkit-details-marker { display: none; }
.sources > summary::before {
  content: "";
  width: 8px; height: 8px;
  border-right: 2px solid var(--rd-gold);
  border-bottom: 2px solid var(--rd-gold);
  transform: rotate(-45deg);
  transition: transform 180ms var(--sw-ease);
}
.sources[open] > summary::before { transform: rotate(45deg); }
.sources-body { padding: var(--rd-space-2) 0 var(--rd-space-2); }
.sources-body p { font-size: var(--rd-small); line-height: 1.55; margin: 0 0 var(--rd-space-3); }
.sources-list {
  margin: 0 0 var(--rd-space-4);
  padding: 0;
  list-style: none;
  display: grid;
  gap: 7px;
}
.sources-list li {
  font-size: var(--rd-small);
  line-height: 1.45;
  padding-left: 18px;
  position: relative;
  color: var(--rd-fg-muted);
}
.sources-list li::before {
  content: "";
  position: absolute;
  left: 0; top: 7px;
  width: 7px; height: 7px;
  background: var(--rd-gold);
  border-radius: 1px;
  transform: rotate(45deg);
}
.sources-list a { color: var(--rd-forest); font-weight: 600; text-decoration-color: var(--rd-gold); }
.sources-note {
  font-size: var(--rd-caption) !important;
  color: var(--rd-fg-muted);
  line-height: 1.5 !important;
}
.sources-note strong { color: var(--rd-forest); }

/* ---------- you vs the model (ideal-line overlay) ---------- */
#compare-section { margin-top: var(--rd-space-6); }
.compare-intro {
  font-size: var(--rd-small);
  color: var(--rd-fg-muted);
  margin: 0 0 var(--rd-space-4);
  max-width: 34rem;
}
/* §4i: the stage is one column at every width. swing.css:840 used to read
   grid-template-columns: 240px 1fr, which is the desktop failure in one line:
   it shrank the athlete to a 240 px thumbnail so a nine-row rail could have a
   column. The rail is gone and the grid does not come back. */
.compare-wrap { display: block; }
.compare-stage {
  background: var(--rd-forest);
  border: 1px solid rgba(245, 241, 232, 0.12);
  border-radius: var(--rd-radius);
  padding: var(--rd-space-3);
}
/* Wraps the captured footage + the SVG lines so they overlay pixel-for-pixel.
   touch-action pan-y: the browser keeps VERTICAL drag as a page scroll and
   hands us the horizontal axis, which is the scrub gesture a coach expects
   from video (REV2 §2 Q4). */
.compare-frame {
  position: relative;
  width: 100%;
  border-radius: calc(var(--rd-radius) - 5px);
  overflow: hidden;
  line-height: 0;
  touch-action: pan-y;
  cursor: ew-resize;
}
.compare-bg {
  position: absolute;
  inset: 0;
  width: 100%; height: 100%;
  display: block;
  z-index: 0;
}
.compare-svg { position: relative; z-index: 1; width: 100%; height: auto; display: block; }
/* slow-mo replay controls */
.compare-col { display: flex; flex-direction: column; gap: var(--rd-space-3); }
/* R3: rail on top (primary), fine adjustment underneath. Stacked, not inline:
   at 390px with ~40 play frames the slider gives about 3px per frame, which no
   thumb can land, so it cannot be the control a coach reaches for first. */
.compare-controls {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: var(--rd-space-2);
  padding: 0 2px;
}
.compare-controls .cmp-phase { text-align: right; }
/* 44px, not 38: these two controls moved onto the opener with the stage, and
   REV2 Q4 sets 44px as the floor for anything on it. Measured by the phone
   layout gate at 390x844 before this: cmp-play 38x38, cmp-scrub 220x4. */
.cmp-play {
  flex: 0 0 auto;
  width: 44px; height: 44px;
  display: inline-flex; align-items: center; justify-content: center;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: var(--rd-forest);
  color: var(--rd-cream);
  cursor: pointer;
  transition: background 140ms var(--sw-ease), transform 140ms var(--sw-ease);
}
.cmp-play:hover { background: var(--rd-forest-2); transform: scale(1.05); }
.cmp-play:focus-visible { outline: 2px solid var(--rd-gold); outline-offset: 2px; }
.cmp-play:active { transform: scale(0.96); }
.cmp-play-ico { width: 18px; height: 18px; display: block; }
/* The hit area is 44px tall; the drawn track stays 4px. A 4px-tall input is a
   4px-tall target, and this one is the fine adjustment under a stage a thumb is
   already on. Track moved onto the ::track pseudo-elements so raising the
   element height does not thicken the line. */
.cmp-scrub {
  flex: 1 1 auto;
  -webkit-appearance: none; appearance: none;
  height: 44px;
  background: none;
  cursor: pointer;
}
.cmp-scrub::-webkit-slider-runnable-track {
  height: 4px;
  border-radius: 999px;
  background: var(--rd-border);
}
.cmp-scrub::-moz-range-track {
  height: 4px;
  border-radius: 999px;
  background: var(--rd-border);
}
.cmp-scrub::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none;
  width: 15px; height: 15px;
  margin-top: -5.5px;                 /* centre the 15px thumb on the 4px track */
  border-radius: 50%;
  background: var(--rd-gold);
  border: 2px solid var(--rd-cream);
  box-shadow: 0 1px 3px rgba(10, 35, 66, 0.25);
}
.cmp-scrub::-moz-range-thumb {
  width: 15px; height: 15px;
  border-radius: 50%;
  background: var(--rd-gold);
  border: 2px solid var(--rd-cream);
  box-shadow: 0 1px 3px rgba(10, 35, 66, 0.25);
}
.cmp-phase {
  flex: 0 0 auto;
  min-width: 4.5rem;
  text-align: right;
  font-family: var(--rd-mono);
  font-size: 0.7rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--rd-fg-muted);
}
/* The 260px cap that used to live here is DELETED (2026-08-05). It shrank the
   stage to a thumbnail on exactly the device the founder reviews on, and the
   stage is now the first thing on the report. It does not come back. */

/* ---------- broadcast comet trace canvas (Swing Lab v2, docs/67 W1) ----------
   Sits above the captured footage (z-index 0, painted after .compare-bg) and
   below the SVG constructs/labels (z-index 1). The glow is drawn on the canvas
   itself with additive compositing — no CSS filter needed. */
.compare-trace {
  position: absolute;
  inset: 0;
  width: 100%; height: 100%;
  display: block;
  z-index: 0;
  pointer-events: none;
}

/* Fan / Ribbon / Both — sweep-style segmented toggle (docs/67 W1 rework) */
.cmp-mode {
  display: inline-flex;
  gap: 0;
  border: 1px solid var(--rd-border);
  border-radius: 999px;
  overflow: hidden;
  width: fit-content;
}
.mode-btn {
  border: none;
  background: transparent;
  color: var(--rd-fg-muted);
  font-family: var(--rd-mono);
  font-size: 0.64rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  padding: 6px 12px;
  cursor: pointer;
  transition: background 140ms var(--sw-ease), color 140ms var(--sw-ease);
}
.mode-btn + .mode-btn { border-left: 1px solid var(--rd-border); }
.mode-btn[aria-pressed="true"] {
  background: var(--rd-forest);
  color: var(--rd-cream);
}
.mode-btn:focus-visible { outline: 2px solid var(--rd-gold); outline-offset: -2px; }

/* load-tempo bar (docs/52 LOAD slice) */
.cmp-tempo {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 0 2px;
}
.cmp-tempo-label {
  font-family: var(--rd-mono);
  font-size: 0.62rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--rd-fg-muted);
}
.cmp-tempo-bar {
  display: flex;
  height: 8px;
  border-radius: 999px;
  overflow: hidden;
  background: var(--rd-border);
}
.cmp-tempo-load { background: var(--rd-gold); }
.cmp-tempo-swing { background: var(--rd-forest); opacity: 0.55; }
.cmp-tempo-val {
  font-family: var(--rd-mono);
  font-size: 0.64rem;
  color: var(--rd-fg-muted);
}

/* fps sniff badge (docs/67 W1 item 5) */
.fps-badge {
  font-size: var(--rd-small);
  line-height: 1.5;
  color: var(--rd-fg);
  background: var(--rd-cream-2);
  border-radius: var(--rd-radius);
  padding: var(--rd-space-3) var(--rd-space-4);
  margin-bottom: var(--rd-space-4);
  border-left: 4px solid var(--rd-gold);
}
.fps-badge.is-slomo { border-left-color: var(--rd-forest); }
.fps-badge strong { color: var(--rd-forest); }
.fps-badge em { font-style: italic; }

/* ---------- kinematic sequence panel (docs/67 W1 item 3) ---------- */
.kinematic-section { margin-top: var(--rd-space-6); }
.kinematic-panel {
  max-width: 420px;
  margin: var(--rd-space-3) 0 var(--rd-space-4);
}
.kseq-svg {
  width: 100%;
  height: auto;
  display: block;
  background: var(--rd-cream-2);
  border: 1px solid var(--rd-border);
  border-radius: var(--rd-radius);
  padding: 6px;
}
.kseq-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 10px 16px;
  margin-top: var(--rd-space-3);
}
.kseq-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: var(--rd-small);
  color: var(--rd-fg);
}
.kseq-key {
  width: 18px; height: 6px;
  display: inline-block;
  flex: 0 0 auto;
}
.kinematic-verdict {
  font-size: var(--rd-small);
  line-height: 1.55;
  color: var(--rd-fg);
  max-width: 42rem;
}
.kinematic-note {
  font-size: calc(var(--rd-small) * 0.92);
  color: var(--rd-fg-muted);
  max-width: 42rem;
  margin-top: var(--rd-space-2);
}

/* ---------- FIRING ORDER panel (redesign 2026-07-17) ----------
   Built for a five-second read: a status pill, then either a lane timeline with
   rank badges (confident) or a neutral "too close to call" row (low confidence). */
.fo-wrap {
  max-width: 480px;
  background: var(--rd-cream-2);
  border: 1px solid var(--rd-border);
  border-radius: var(--rd-radius);
  padding: var(--rd-space-4) var(--rd-space-5);
  margin: var(--rd-space-3) 0 var(--rd-space-4);
}
.fo-status {
  display: inline-flex;
  align-items: center;
  font-family: var(--rd-display);
  font-size: 1.5rem;
  letter-spacing: 0.02em;
  padding: 4px 14px;
  border-radius: var(--rd-radius-pill);
  margin-bottom: var(--rd-space-4);
}
.fo-status-good { background: var(--rd-forest); color: var(--rd-cream); }
.fo-status-warn { background: var(--rd-gold); color: var(--rd-near-black); }
.fo-status-low  { background: var(--rd-cream-3); color: var(--rd-fg-muted); border: 1px solid var(--rd-gold-2); }

.fo-axis {
  display: flex;
  justify-content: space-between;
  font-family: var(--rd-mono);
  font-size: 0.62rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--rd-fg-muted);
  margin-bottom: 6px;
}
.fo-lanes { display: flex; flex-direction: column; gap: 8px; }
.fo-lane { display: flex; align-items: center; gap: var(--rd-space-3); }
.fo-lane-name {
  flex: 0 0 84px;
  font-family: var(--rd-body);
  font-weight: 700;
  font-size: 0.82rem;
  color: var(--rd-fg-strong);
}
.fo-track {
  position: relative;
  flex: 1 1 auto;
  height: 26px;
  border-radius: var(--rd-radius-pill);
  background: linear-gradient(90deg, rgba(11,77,60,0.06), rgba(11,77,60,0.13));
  border: 1px solid var(--rd-border);
}
.fo-marker {
  position: absolute;
  top: 50%;
  transform: translate(-50%, -50%);
}
.fo-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px; height: 22px;
  border-radius: 50%;
  font-family: var(--rd-mono);
  font-weight: 700;
  font-size: 0.8rem;
  box-shadow: 0 1px 3px rgba(4,28,21,0.35);
}
.fo-lane-missing {
  position: absolute;
  left: 10px; top: 50%;
  transform: translateY(-50%);
  font-family: var(--rd-mono);
  font-size: 0.62rem;
  letter-spacing: 0.03em;
  color: var(--rd-fg-muted);
}
.fo-ideal {
  margin: var(--rd-space-4) 0 0;
  font-family: var(--rd-mono);
  font-size: 0.66rem;
  letter-spacing: 0.03em;
  color: var(--rd-fg-muted);
}
.fo-tooclose { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: var(--rd-space-3); }
.fo-neutral-chip {
  font-family: var(--rd-body);
  font-weight: 600;
  font-size: 0.8rem;
  color: var(--rd-fg-muted);
  background: var(--rd-cream-3);
  border: 1px solid var(--rd-border);
  border-radius: var(--rd-radius-sm);
  padding: 4px 12px;
}
.fo-tooclose-note {
  margin: 0;
  font-size: var(--rd-small);
  color: var(--rd-fg);
}
.kinematic-detail-btn {
  display: inline-flex;
  align-items: center;
  background: transparent;
  border: 1px solid var(--rd-border);
  border-radius: var(--rd-radius-pill);
  color: var(--rd-fg-muted);
  font-family: var(--rd-mono);
  font-size: 0.66rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  padding: 6px 12px;
  margin-top: var(--rd-space-2);
  cursor: pointer;
}
.kinematic-detail-btn:focus-visible { outline: 2px solid var(--rd-gold); outline-offset: 2px; }
.kinematic-detail { max-width: 420px; margin-top: var(--rd-space-3); }

/* metrics-rail collapse line — the one quiet line that replaces dashed rows */
.rail-collapse {
  margin: var(--rd-space-3) 0 0;
  font-size: var(--rd-small);
  line-height: 1.5;
  color: var(--rd-fg);
  padding-top: var(--rd-space-3);
  border-top: 1px solid var(--rd-border);
}

/* ---------- Pro-compare v0: you vs a model swing ---------- */
.procompare-section { margin-top: var(--rd-space-7); }
.pc-mode {
  display: inline-flex;
  gap: 2px;
  background: var(--rd-cream-2);
  border: 1px solid var(--rd-border);
  border-radius: var(--rd-radius-pill);
  padding: 3px;
  margin-bottom: var(--rd-space-4);
}
.pc-mode-btn {
  border: none;
  background: transparent;
  color: var(--rd-fg-muted);
  font-family: var(--rd-mono);
  font-size: 0.68rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  padding: 6px 14px;
  border-radius: var(--rd-radius-pill);
  cursor: pointer;
}
.pc-mode-btn[aria-pressed="true"] { background: var(--rd-forest); color: var(--rd-cream); }
.pc-mode-btn:focus-visible { outline: 2px solid var(--rd-gold); outline-offset: 2px; }
.pc-stage { width: 100%; }
.pc-side { display: flex; gap: var(--rd-space-4); flex-wrap: wrap; }
.pc-overlay { display: flex; }
/* [hidden] would otherwise lose to the display rules above (author CSS beats the
   UA hidden style) — restore it with equal-or-higher specificity. */
.pc-side[hidden], .pc-overlay[hidden] { display: none; }
.pc-pane { margin: 0; flex: 1 1 280px; min-width: 0; }
.pc-canvas {
  width: 100%;
  height: auto;
  display: block;
  background: #06140F;
  border: 1px solid var(--rd-border);
  border-radius: var(--rd-radius);
}
.pc-cap {
  font-family: var(--rd-mono);
  font-size: 0.66rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--rd-fg-muted);
  margin-top: 6px;
}
.pc-controls {
  display: flex;
  align-items: center;
  gap: var(--rd-space-3);
  margin-top: var(--rd-space-4);
}
.pc-refcap {
  margin-top: var(--rd-space-3);
  font-size: var(--rd-small);
  line-height: 1.5;
  color: var(--rd-fg-muted);
  max-width: 42rem;
}
.pc-refcap strong { color: var(--rd-gold-2); }

/* ---------- AI coach audio button ---------- */
.hear-btn {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  margin-top: var(--rd-space-4);
  padding: 9px 16px;
  background: var(--rd-forest);
  color: var(--rd-cream);
  border: none;
  border-radius: var(--rd-radius-pill);
  font-family: var(--rd-body);
  font-size: var(--rd-small);
  font-weight: 700;
  cursor: pointer;
  box-shadow: var(--rd-cta-lift);
  transition: transform 160ms var(--sw-ease), background 160ms var(--sw-ease);
}
.hear-btn:hover { transform: translateY(-1px); background: var(--rd-forest-2); }
.hear-btn:active { transform: translateY(0); }
.hear-ico { width: 18px; height: 18px; flex: 0 0 auto; }
.hear-btn .spk-w1, .hear-btn .spk-w2 { opacity: 0.9; }
/* while speaking: the sound waves pulse and the label flips to Stop */
.hear-btn.is-speaking { background: var(--rd-gold); color: var(--rd-forest-3); box-shadow: none; }
.hear-btn.is-speaking .spk-w1 { animation: spkPulse 1s var(--sw-ease) infinite; }
.hear-btn.is-speaking .spk-w2 { animation: spkPulse 1s var(--sw-ease) infinite 0.18s; }
@keyframes spkPulse { 0%, 100% { opacity: 0.3; } 50% { opacity: 1; } }
@media (prefers-reduced-motion: reduce) {
  .hear-btn.is-speaking .spk-w1, .hear-btn.is-speaking .spk-w2 { animation: none; }
}
