/* ─────────────────────────────────────────────────────────────────────────
   testimonials.css — the proof library, in the site's ruled-sheet register.

   The old sheet was a different vintage: a dark gradient hero, floating
   glass cards, a rounded drop-shadowed film panel, green as decoration.
   Everything below re-draws the page under the current law — regions
   separated by 1px --graphite rules, two line weights only (each film's
   chrome bar closes with the 2px rule of record, exactly once per sheet),
   white as the material, and --leaf on live signal alone: the pulsing
   active node, the rail's reached segment, the event line's leaf edge, the
   meter fill and the drawn confirmation tick.

   Content lives in src/content/testimonials.js. Each record becomes one
   proof article and one four-stage film; this stylesheet contains no
   client-specific rules, so a new record never needs a layout edit.

   ── THE REVEAL ENGINE ─────────────────────────────────────────────────────

   The director writes ONE number per section — `--tm-in`, 0 → 1 — and every
   entrance on this page is derived from it here, in the same grammar as
   page-services.css: a per-element window into that one number.

       --i        the element's index inside its section
       --tm-at    when it starts, in units of --tm-in  (= --i × 0.06)
       --tm-dur   how long it takes, in the same units (0.4)
       --tm-p     the element's own 0 → 1

   THE ONE ARITHMETIC RULE: --tm-at + --tm-dur must never exceed 1. The
   largest index used anywhere is 6 → 0.36 + 0.4 = 0.76, under the ceiling.

   --tm-in DEFAULTS TO 1, so a page whose director never starts — reduced
   motion, or a script that failed — arrives fully composed, never blank.

   Load AFTER tokens.css, base.css and page.css. Every colour is a var();
   there is not a raw hex in this file.
   ───────────────────────────────────────────────────────────────────────── */

[data-tm-section] { --tm-in: 1; }

.tm-rise {
  --tm-at: calc(var(--i, 0) * 0.06);
  --tm-dur: 0.4;
  --tm-p: clamp(0, calc((var(--tm-in, 1) - var(--tm-at)) / var(--tm-dur)), 1);
  opacity: var(--tm-p);
  /* Transform and opacity only, and only ever these two. 8px = --s2. */
  transform: translate3d(0, calc((1 - var(--tm-p)) * 8px), 0);
}

.testimonials-page {
  position: relative;
  padding-top: 76px;
  overflow: clip;
  background: var(--page);
}

/* The page's shared measure: one container, one gutter. */
.tm-head,
.tm-numbers,
.tm-intro,
.tm-filters,
.tm-library,
.tm-final {
  max-width: 1560px;
  margin-inline: auto;
  padding-inline: clamp(24px, 5vw, 80px);
}

/* ── § head ────────────────────────────────────────────────────────────── */

.tm-head {
  padding-top: clamp(72px, 12vh, 140px);
  padding-bottom: var(--s6);
}

.tm-display {
  margin: var(--s4) 0;
  font-family: var(--font-display);
  font-weight: var(--display-weight);
  font-size: clamp(56px, 8vw, 142px);
  line-height: var(--display-leading);
  letter-spacing: var(--display-tracking);
  color: var(--ink);
}

.tm-lede {
  max-width: 54ch;
  font-size: clamp(17px, 1.35vw, 21px);
  line-height: var(--body-leading);
  color: var(--ink-60);
}

.tm-head-actions {
  margin-top: var(--s5);
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--s4);
}

/* The head's one ambient: a packet on a dashed track closing on a drawn
   tick — the same construction as .dash-rail, because it is the same claim.
   The tick draws WITH the reveal: its dash offset reads the rail's own
   --tm-p, so the current arrives and the confirmation lands, in order. */
.tm-head-rail {
  margin-top: var(--s6);
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--s3);
  min-width: 0;
}

.tm-track {
  position: relative;
  height: 0;
  border-top: 1.5px dashed var(--leaf-30);
}

/* A percentage translate resolves against this wrapper's own box, which is
   stretched across the track — so translateX(100%) is exactly one lap and
   nothing is ever measured. Same device as .dash-track-run. */
.tm-track-run {
  position: absolute;
  inset: 0;
  animation: tm-run 7.5s linear infinite;
  will-change: transform;
}

.tm-packet {
  position: absolute;
  left: -7px;
  top: -7px;
  width: 14px;
  height: 14px;
  border-radius: 50%;
  /* Copied verbatim from .dash-packet: a light source, not a surface. The
     halo is STATIC — never animated — so it breaks no rule. */
  background: radial-gradient(circle at 36% 30%, var(--leaf-hot), var(--leaf) 55%, var(--leaf-ink));
  box-shadow: 0 0 0 3px var(--leaf-14);
}

.tm-tick { width: 20px; height: 20px; display: block; }

.tm-tick path {
  fill: none;
  stroke: var(--leaf);
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
  stroke-dasharray: 1;
  stroke-dashoffset: calc(1 - var(--tm-p, 1));
}

/* ── § the numbers band ────────────────────────────────────────────────── */

.tm-numbers {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  column-gap: var(--s4);
}

/* Rules separate rows, gap separates columns — the register's grammar. */
.tm-numbers > div {
  min-height: 168px;
  padding: var(--s5) 0;
  border-top: var(--hairline);
  border-bottom: var(--hairline);
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: var(--s3);
}

.tm-numbers strong {
  font-family: var(--font-display);
  font-weight: var(--display-weight);
  font-size: clamp(34px, 4vw, 64px);
  line-height: 1;
  letter-spacing: var(--display-tracking);
  color: var(--ink);
}

.tm-numbers span {
  max-width: 22ch;
  font-family: var(--font-mono);
  font-size: 11px;
  line-height: 1.5;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-60);
}

/* ── § the message wall ────────────────────────────────────────────────── */

.tm-wall {
  padding: clamp(64px, 8vw, 104px) 0;
  border-bottom: var(--hairline);
  overflow: hidden;
}

.tm-lane { width: 100%; }
.tm-lane + .tm-lane { margin-top: var(--s3); }

.tm-lane ul {
  width: max-content;
  display: flex;
  list-style: none;
  margin: 0;
  padding: 0;
  gap: var(--s3);
  animation: tm-marquee 90s linear infinite;
  will-change: transform;
}

.tm-lane.reverse ul { animation-direction: reverse; animation-duration: 104s; }
.tm-wall:hover .tm-lane ul { animation-play-state: paused; }

.tm-message {
  width: clamp(300px, 30vw, 480px);
  min-height: 104px;
  display: grid;
  grid-template-columns: 40px minmax(0, 1fr) auto;
  gap: var(--s3);
  align-items: start;
  padding: var(--s3) var(--s4);
  background: var(--page);
  border: 1px solid var(--graphite);
}

.tm-avatar {
  width: 40px;
  height: 40px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  border: 1px solid var(--graphite);
  background: var(--page);
  color: var(--ink);
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.08em;
}

.tm-message p { font-size: 14px; line-height: 1.45; color: var(--ink); }

.tm-message small {
  display: block;
  margin-top: var(--s2);
  color: var(--ink-60);
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

/* A confirmation mark — one of the register's nine legal greens. */
.tm-message > i { color: var(--leaf-ink); font-style: normal; }

.tm-wall-note {
  margin: var(--s5) auto 0;
  padding: 0 var(--s4);
  text-align: center;
  color: var(--ink-60);
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.14em;
}

/* ── § intro ───────────────────────────────────────────────────────────── */

.tm-intro {
  padding-top: clamp(80px, 10vw, 148px);
  padding-bottom: var(--s6);
  display: grid;
  grid-template-columns: minmax(0, 1.4fr) minmax(280px, 0.6fr);
  gap: var(--s6);
  align-items: end;
}

.tm-tag {
  margin-bottom: var(--s3);
  color: var(--ink-60);
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: var(--eyebrow-tracking);
  text-transform: uppercase;
}

.tm-h2 {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: clamp(40px, 5.5vw, 92px);
  line-height: var(--display-leading);
  letter-spacing: var(--display-tracking);
  color: var(--ink);
}

.tm-intro > p {
  max-width: 46ch;
  color: var(--ink-60);
  line-height: var(--body-leading);
}

/* ── § filters ─────────────────────────────────────────────────────────── */

.tm-filters {
  position: sticky;
  top: 76px;
  z-index: 12;
  display: flex;
  align-items: center;
  gap: var(--s2);
  padding-top: var(--s2);
  padding-bottom: var(--s2);
  overflow-x: auto;
  background: var(--page);
  border-top: var(--hairline);
  border-bottom: var(--hairline);
  scrollbar-width: none;
}

.tm-filters::-webkit-scrollbar { display: none; }

/* Hairline rectangles, not pills: chips in the current register. */
.tm-filters button {
  flex: 0 0 auto;
  min-height: 44px;
  padding: 0 var(--s3);
  border: 1px solid var(--graphite);
  background: var(--page);
  color: var(--ink);
  cursor: pointer;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  transition: border-color 180ms var(--ease-out), background 180ms var(--ease-out), color 180ms var(--ease-out);
}

.tm-filters button:hover { border-color: var(--ink); }
.tm-filters button[aria-pressed='true'] { background: var(--ink); border-color: var(--ink); color: var(--page); }
.tm-filters button:focus-visible { outline: 1px solid var(--ink); outline-offset: 3px; }

.tm-filters > p {
  margin-left: auto;
  flex: 0 0 auto;
  color: var(--ink-60);
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.06em;
  font-variant-numeric: tabular-nums;
}

/* ── § one case ────────────────────────────────────────────────────────── */

.tm-case {
  position: relative;
  padding: clamp(72px, 9vw, 128px) 0;
}

.tm-case[hidden] { display: none; }

/* The case's rule DRAWS left to right as the article arrives, then darkens
   to ink under the cursor — the row grammar of /services/, kept exactly. */
.tm-case::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 0;
  border-top: var(--hairline);
  transform: scaleX(clamp(0, calc(var(--tm-in, 1) / 0.3), 1));
  transform-origin: left;
  transition: border-color 180ms var(--ease-out);
}

.tm-case:hover::before,
.tm-case:focus-within::before { border-top-color: var(--ink); }

.tm-case:last-child::after {
  content: '';
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  height: 0;
  border-top: var(--hairline);
}

.tm-case-index {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--s3);
  margin-bottom: var(--s5);
}

.tm-case-index span {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-60);
  font-variant-numeric: tabular-nums;
}

.tm-case-index span + span {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.tm-case-grid {
  display: grid;
  grid-template-columns: minmax(300px, 0.72fr) minmax(0, 1.28fr);
  gap: clamp(40px, 6vw, 104px);
  align-items: start;
}

/* ── the proof column ─────────────────────────────── */

.tm-source-label {
  color: var(--ink-60);
  font-family: var(--font-mono);
  font-size: 10px;
  line-height: 1.5;
  letter-spacing: 0.14em;
}

.tm-person {
  margin: var(--s4) 0 var(--s4);
  display: grid;
  grid-template-columns: 56px minmax(0, 1fr);
  gap: var(--s3);
  align-items: center;
}

.tm-person > .tm-avatar { width: 56px; height: 56px; font-size: 12px; }

.tm-person p { font-size: 14px; line-height: 1.4; color: var(--ink-60); }

.tm-person strong {
  display: block;
  margin-bottom: 2px;
  color: var(--ink);
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 21px;
  letter-spacing: var(--display-tracking);
}

.tm-person span { display: block; }

.tm-person small {
  display: block;
  margin-top: var(--s1);
  font-family: var(--font-mono);
  font-size: 9px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

/* The client's words carry the customer's speaker mark from the transcript
   register: a graphite rule, never a green one — quotes are not live. */
.tm-messages {
  margin: 0;
  display: grid;
  gap: var(--s3);
}

.tm-messages p {
  padding: var(--s1) 0 var(--s1) var(--s3);
  border-left: 2px solid var(--graphite);
  font-size: 15px;
  line-height: var(--body-leading);
  color: var(--ink);
}

.tm-metric {
  margin-top: var(--s5);
  padding: var(--s4) 0;
  border-top: var(--hairline);
  border-bottom: var(--hairline);
}

.tm-metric span {
  display: block;
  margin-bottom: var(--s2);
  color: var(--ink-60);
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.14em;
}

/* The figure HOLDS: no transition, no transform, on hover or ever. A number
   that moves when a cursor arrives is a number that looks negotiable. */
.tm-metric strong {
  display: block;
  font-family: var(--font-display);
  font-weight: 800;
  font-size: clamp(24px, 2.4vw, 40px);
  line-height: 1.08;
  letter-spacing: -0.045em;
  color: var(--ink);
}

.tm-brief {
  margin: var(--s4) 0;
  display: grid;
  gap: var(--s3);
}

.tm-brief div {
  display: grid;
  grid-template-columns: 88px minmax(0, 1fr);
  gap: var(--s3);
}

.tm-brief dt {
  color: var(--ink-60);
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.tm-brief dd { color: var(--ink-60); font-size: 13px; line-height: 1.5; }

.tm-source {
  display: inline-flex;
  align-items: center;
  gap: var(--s2);
  min-height: 44px;
  border-bottom: 1px solid var(--graphite);
  color: var(--ink);
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  transition: border-color 180ms var(--ease-out);
}

.tm-source span { transition: transform 180ms var(--ease-out); }
.tm-source:hover { border-bottom-color: var(--ink); }
.tm-source:hover span,
.tm-source:focus-visible span { transform: translate3d(2px, -2px, 0); }
.tm-source:focus-visible { outline: 1px solid var(--ink); outline-offset: 3px; }

/* ── the film: a ruled sheet ──────────────────────── */

.tm-film-slot { min-width: 0; }

.tm-film {
  --film-progress: 0;
  min-height: 560px;              /* the box exists before the loop runs */
  display: grid;
  grid-template-rows: auto auto minmax(0, 1fr) auto auto;
  background: var(--page);
  color: var(--ink);
}

/* Chrome, closed by the rule of record — the sheet's only 2px line. */
.tm-film-chrome {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--s3);
  min-height: 48px;
  border-bottom: 2px solid var(--ink);
}

.tm-film-kind {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: var(--eyebrow-tracking);
  text-transform: uppercase;
  color: var(--ink-60);
}

.tm-film-name {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 15px;
  letter-spacing: var(--display-tracking);
  line-height: 1;
  text-transform: uppercase;
  color: var(--ink);
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.tm-film-clock {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--ink-60);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* THE STAGE RAIL. A hairline between the first and last node centres; the
   reached segment is --leaf and advances stage by stage, so green is only
   ever under ground the run has actually covered. */
.tm-film-stagebar {
  position: relative;
  padding: var(--s5) 0 var(--s3);
}

.tm-film-rail {
  position: absolute;
  left: 12.5%;
  right: 12.5%;
  top: calc(var(--s5) + 4px);   /* through the 9px nodes' centres */
  height: 0;
  border-top: var(--hairline);
}

.tm-film-rail i {
  position: absolute;
  left: 0;
  right: 0;
  top: -1px;
  height: 1px;
  background: var(--leaf);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 600ms var(--ease-out);
  will-change: transform;
}

.tm-film[data-stage='1'] .tm-film-rail i { transform: scaleX(0.3333); }
.tm-film[data-stage='2'] .tm-film-rail i { transform: scaleX(0.6667); }
.tm-film[data-stage='3'] .tm-film-rail i { transform: scaleX(1); }

.tm-film-stages {
  position: relative;              /* above the rail */
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: var(--s2);
  list-style: none;
  margin: 0;
  padding: 0;
}

.tm-film-stages button {
  width: 100%;
  min-height: 64px;
  padding: 0 var(--s1);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--s2);
  border: 0;
  background: transparent;
  color: var(--ink-60);
  cursor: pointer;
  transition: color 260ms var(--ease-out);
}

.tm-film-stages button:focus-visible { outline: 1px solid var(--ink); outline-offset: 3px; }
.tm-film-stages button:hover .tm-node { border-color: var(--ink); }

/* The node: .dash-lane-node's construction, colour only, 260ms. */
.tm-node {
  position: relative;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--page);
  border: 1.5px solid var(--graphite);
  transition: background-color 260ms var(--ease-out), border-color 260ms var(--ease-out);
}

.tm-film-stages .is-done .tm-node,
.tm-film-stages .is-active .tm-node {
  background: var(--leaf);
  border-color: var(--leaf);
}

/* THE LIVE DOT RIDES THE ACTIVE STAGE: a scaling pseudo-ring, exactly
   .dash-live's pulse, and the only heartbeat on the sheet. */
.tm-film-stages .is-active .tm-node::after {
  content: '';
  position: absolute;
  inset: -1.5px;
  border-radius: 50%;
  background: var(--leaf-30);
  animation: tm-pulse 2s linear infinite;
  will-change: transform, opacity;
}

.tm-film-stages button > span {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.14em;
  color: var(--ink-60);
  font-variant-numeric: tabular-nums;
}

.tm-film-stages button > b {
  font-family: var(--font-mono);
  font-weight: 400;
  font-size: 10px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  line-height: 1.35;
  max-width: 13ch;
  text-align: center;
}

.tm-film-stages .is-active button { color: var(--ink); }

/* THE CURRENT STEP. Space for the tallest title and a two-line event text
   is reserved with min-heights, so a stage swap never moves the sheet. */
.tm-film-current {
  align-content: start;
  padding: var(--s4) 0;
  border-top: var(--hairline);
  min-height: 176px;
}

.tm-step-count {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.16em;
  color: var(--ink-60);
  font-variant-numeric: tabular-nums;
}

.tm-film-current h3 {
  margin: var(--s2) 0 var(--s3);
  font-family: var(--font-display);
  font-weight: 800;
  font-size: clamp(24px, 2.6vw, 38px);
  line-height: 1;
  letter-spacing: var(--display-tracking);
  color: var(--ink);
  min-height: 1em;
}

/* The event line carries the run's LIVE edge — the transcript's speaker
   mark, in leaf because this line is the one currently happening. */
.tm-film-action {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: var(--s3);
  align-items: start;
  padding-left: var(--s3);
  border-left: 2px solid var(--leaf);
}

.tm-film-action > p {
  font-size: 14px;
  line-height: 1.5;
  color: var(--ink);
  min-height: calc(2 * 1.5em);   /* two lines reserved: no reflow on swap */
}

.tm-film-action small {
  display: block;
  margin-top: var(--s1);
  color: var(--ink-60);
  font-family: var(--font-mono);
  font-size: 9px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.tm-film-action > b {
  color: var(--leaf-ink);
  font-family: var(--font-mono);
  font-weight: 400;
  font-size: 10px;
  letter-spacing: 0.16em;
}

/* Each step change leads the eye: heading first, the event a beat behind. */
.tm-film-current.stage-in h3 { animation: tm-stage 520ms var(--ease-out) both; }
.tm-film-current.stage-in .tm-film-action { animation: tm-stage 520ms var(--ease-out) 90ms both; }

/* THE OUTCOME ROW. The tick is stroke only — no circle, no filled badge —
   and draws when the run reaches its final stage. */
.tm-film-result {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) 20px;
  gap: var(--s3);
  align-items: center;
  padding: var(--s3) 0;
  border-top: var(--hairline);
}

.tm-film-result span {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.14em;
  color: var(--ink-60);
}

.tm-film-result strong {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 17px;
  letter-spacing: var(--display-tracking);
  color: var(--ink);
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.tm-film-tick { width: 20px; height: 20px; display: block; }

.tm-film-tick path {
  fill: none;
  stroke: var(--leaf);
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
  transition: stroke-dashoffset 600ms var(--ease-out);
}

.tm-film.is-final .tm-film-tick path { stroke-dashoffset: 0; }

/* The control rail: a real button, the meter, the loop's arithmetic. */
.tm-film-controls {
  display: flex;
  align-items: center;
  gap: var(--s3);
  min-height: 60px;
  padding-top: var(--s3);
  border-top: var(--hairline);
}

.tm-film-toggle {
  min-height: 44px;
  min-width: 64px;
  padding: 0 var(--s3);
  border: var(--hairline);
  background: none;
  color: var(--ink);
  cursor: pointer;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  transition: border-color 180ms var(--ease-out), color 180ms var(--ease-out);
}

.tm-film-toggle:hover { border-color: var(--leaf-ink); color: var(--leaf-ink); }
.tm-film-toggle:focus-visible { outline: 1px solid var(--ink); outline-offset: 3px; }

/* .dash-meter's construction: one mechanism, everywhere a fill is meant. */
.tm-film-progress {
  flex: 1 1 auto;
  height: 3px;
  border-radius: 2px;
  background: var(--graphite);
  overflow: hidden;
}

.tm-film-progress i {
  display: block;
  height: 100%;
  background: var(--leaf);
  transform: scaleX(var(--film-progress));
  transform-origin: left;
  will-change: transform;
}

.tm-film-controls > p {
  flex: 0 0 auto;
  white-space: nowrap;
  color: var(--ink-60);
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

/* A film the observer has ruled offscreen keeps no heartbeat. */
.tm-film.is-off .tm-node::after { animation-play-state: paused; }

/* ── § method ──────────────────────────────────────────────────────────── */

.tm-method {
  max-width: 1300px;
  margin-inline: auto;
  padding: clamp(72px, 9vw, 128px) clamp(24px, 5vw, 80px);
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(48px, 7vw, 104px);
}

.tm-method .tm-h2 { font-size: clamp(36px, 4.4vw, 68px); }

.tm-method-rows { display: grid; align-content: center; }

.tm-method-rows p {
  display: grid;
  grid-template-columns: 40px minmax(0, 1fr);
  column-gap: var(--s3);
  padding: var(--s4) 0;
  border-top: var(--hairline);
  color: var(--ink-60);
  font-size: 14px;
  line-height: 1.5;
}

.tm-method-rows p:last-child { border-bottom: var(--hairline); }

.tm-method-rows p > span {
  grid-row: 1 / span 2;
  color: var(--ink-60);
  font-family: var(--font-mono);
  font-size: 11px;
  font-variant-numeric: tabular-nums;
}

.tm-method-rows p > strong {
  color: var(--ink);
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 18px;
  letter-spacing: var(--display-tracking);
  margin-bottom: 2px;
}

/* ── § close ───────────────────────────────────────────────────────────── */

.tm-final {
  padding-top: clamp(96px, 12vh, 168px);
  padding-bottom: clamp(64px, 8vw, 104px);
  text-align: center;
}

.tm-final .tm-h2 { max-width: 14ch; margin: var(--s4) auto; }

.tm-final > p:not(.eyebrow) {
  max-width: 58ch;
  margin: 0 auto var(--s5);
  color: var(--ink-60);
  line-height: var(--body-leading);
}

/* ── keyframes ─────────────────────────────────────────────────────────── */

@keyframes tm-run { from { transform: translateX(0); } to { transform: translateX(100%); } }
@keyframes tm-marquee { to { transform: translateX(calc(-50% - var(--s2))); } }
@keyframes tm-pulse { from { transform: scale(1); opacity: 0.9; } to { transform: scale(2.6); opacity: 0; } }
@keyframes tm-stage { from { opacity: 0; transform: translate3d(0, 8px, 0); } to { opacity: 1; transform: none; } }

/* Ambience is paused when its section leaves the viewport (the observer
   sets .is-off) and while the tab is hidden (body.tm-hidden). */
.tm-ambient.is-off ul,
.tm-ambient.is-off .tm-track-run,
.tm-hidden .tm-lane ul,
.tm-hidden .tm-track-run,
.tm-hidden .tm-node::after { animation-play-state: paused; }

/* ── breakpoints ───────────────────────────────────────────────────────── */

@media (max-width: 1100px) {
  .tm-case-grid { grid-template-columns: minmax(280px, 0.8fr) minmax(0, 1.2fr); gap: var(--s6); }
  .tm-film-controls > p { display: none; }
}

@media (max-width: 940px) {
  .tm-numbers { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  /* Two-up rows share one drawn rule; the lower pair keeps its own. */
  .tm-numbers > div:nth-child(-n + 2) { border-bottom: 0; }
  .tm-intro { grid-template-columns: minmax(0, 1fr); gap: var(--s4); align-items: start; }
  .tm-case-grid { grid-template-columns: minmax(0, 1fr); gap: var(--s5); }
  .tm-proof { max-width: 640px; }
  .tm-method { grid-template-columns: minmax(0, 1fr); gap: var(--s5); }
}

@media (max-width: 620px) {
  .testimonials-page { padding-top: 69px; }
  .tm-head,
  .tm-numbers,
  .tm-intro,
  .tm-filters,
  .tm-library,
  .tm-final { padding-inline: 20px; }
  .tm-head { padding-top: 64px; }
  .tm-display { font-size: clamp(44px, 13vw, 64px); }
  .tm-lede { font-size: 16px; }
  .tm-head-actions { flex-direction: column; align-items: stretch; }
  .tm-head-actions .ghost-link { text-align: center; }
  .tm-numbers > div { min-height: 128px; padding: var(--s4) 0; }
  .tm-numbers strong { font-size: 32px; }
  .tm-numbers span { font-size: 9px; }
  .tm-message { width: 300px; }
  .tm-h2 { font-size: clamp(36px, 11vw, 56px); }
  .tm-filters { top: 69px; }
  .tm-filters > p { display: none; }
  .tm-case { padding: 72px 0; }

  /* The film at phone width: the rail hands over to a ruled 2×2 step list —
     the same data, read as rows, with the pulse still on the active node. */
  .tm-film { min-height: 620px; }
  .tm-film-rail { display: none; }
  .tm-film-stagebar { padding: var(--s3) 0; }
  .tm-film-stages { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0 var(--s3); }
  .tm-film-stages button {
    flex-direction: row;
    justify-content: flex-start;
    text-align: left;
    min-height: 48px;
    padding: var(--s2) 0;
    border-top: var(--hairline);
  }
  .tm-film-stages button > b { max-width: none; text-align: left; }
  .tm-film-current { min-height: 190px; }
  .tm-film-current h3 { font-size: 27px; }
  .tm-film-action > p { min-height: calc(3 * 1.5em); }  /* narrower: 3 lines */
  .tm-film-action > b { display: none; }
  .tm-method { padding: 64px 20px; }
}

/* ── reduced motion ────────────────────────────────────────────────────── */

/* Composed, not frozen. The module paints every film settled at its final
   stage — rail full, tick drawn, meter at the end of its travel — and this
   block makes sure nothing CSS owns keeps moving underneath that, exactly
   as dashboard.css does for its sheets. The pulse ring is REMOVED, not
   paused: a paused ring is a stalled halo at an arbitrary scale. */
@media (prefers-reduced-motion: reduce) {
  .tm-rise { opacity: 1; transform: none; }
  .tm-case::before { transform: none; transition: none; }
  .tm-tick path { stroke-dashoffset: 0; }
  .tm-lane ul { animation: none; transform: none; }
  .tm-track-run { animation: none; transform: translateX(100%); } /* parked */
  .tm-film-stages .is-active .tm-node::after { display: none; }
  .tm-film *,
  .tm-film *::before,
  .tm-film *::after { animation: none !important; transition: none !important; }
  .tm-source span,
  .tm-filters button { transition: none; }
}
