# Incident review

> A post-incident review that puts the summary, the release, latency, the slowest trace, and the timeline on one page.

A shadcn/ui block from the [@overtrue](https://ui.overtrue.xyz/?utm_source=shadcn.exchange) registry, listed on [shadcn.exchange](https://shadcn.exchange/r/overtrue/incident-review).

- Page, with a live preview: https://shadcn.exchange/r/overtrue/incident-review
- Screenshot: https://shadcn.exchange/shot/overtrue/incident-review/light.png
- Registry item: https://ui.overtrue.xyz/r/incident-review.json
- Categories: blocks
- Listed: 2026-10-28, source last changed 2026-10-28

## Install

```bash
npx shadcn@latest add https://shadcn.exchange/r/overtrue/incident-review.json
```

Run it in a project that has shadcn/ui set up. It adds the files below and installs what they depend on.

## Dependencies

- npm packages: `@tabler/icons-react`

## Notes from the registry

Documentation: https://ui.overtrue.xyz/blocks/incident-review. Requires an initialized shadcn/ui project with Tailwind CSS v4.

## Files

### `src/registry/overtrue/incident-review.tsx`

```tsx
"use client";

import * as React from "react";
import { IconAlertTriangle, IconClockHour4 } from "@tabler/icons-react";

import { cn } from "@/lib/utils";
import { InsightCard, type InsightSource } from "./insight-card";
import { LatencyHistogram } from "./latency-histogram";
import { TraceWaterfall, type TraceSpan } from "./trace-waterfall";
import { DeployPipeline, type PipelineStage } from "./deploy-pipeline";
import { LogStream, type LogEntry } from "./log-stream";

export type IncidentSeverity = "sev1" | "sev2" | "sev3";
export type IncidentState = "investigating" | "mitigated" | "resolved";

export interface IncidentReviewData {
  id: string;
  title: string;
  service: string;
  severity: IncidentSeverity;
  state: IncidentState;
  /** Human-readable duration, e.g. "18 min". */
  duration: string;
  /** Summary with optional `{{metric:…}}` and `{{cite:n}}` tokens. */
  summary: string;
  sources?: InsightSource[];
  latency: {
    /** Request latencies before the incident, in milliseconds. */
    before: number[];
    /** Request latencies during the incident. */
    during: number[];
    /** Objective drawn on the histogram. */
    threshold: number;
  };
  trace: { title: string; spans: TraceSpan[] };
  release: { title: string; meta?: React.ReactNode; stages: PipelineStage[] };
  events: LogEntry[];
}

export interface IncidentReviewProps
  extends Omit<React.ComponentProps<"section">, "title"> {
  incident: IncidentReviewData;
  /** Ask your model for a new summary; the card shows a thinking state meanwhile. */
  onRegenerate?: () => void;
  /** Stream the summary in; leave false to show it complete. */
  streaming?: boolean;
}

const severityStyle: Record<IncidentSeverity, string> = {
  sev1: "bg-destructive text-white",
  sev2: "bg-amber-500 text-black",
  sev3: "bg-muted text-foreground",
};
const stateStyle: Record<IncidentState, string> = {
  investigating: "border-destructive/30 bg-destructive/10 text-destructive",
  mitigated:
    "border-amber-500/30 bg-amber-500/10 text-amber-800 dark:text-amber-300",
  resolved:
    "border-emerald-500/30 bg-emerald-500/10 text-emerald-800 dark:text-emerald-300",
};
const stateLabel: Record<IncidentState, string> = {
  investigating: "Investigating",
  mitigated: "Mitigated",
  resolved: "Resolved",
};

/** A post-incident review: what happened, the evidence, and what changed. */
export function IncidentReview({
  incident,
  onRegenerate,
  streaming = false,
  className,
  ...props
}: IncidentReviewProps) {
  return (
    <section
      data-slot="incident-review"
      aria-label={`${incident.id}: ${incident.title}`}
      className={cn(
        "@container/incident flex min-w-0 flex-col gap-3 text-foreground sm:gap-4",
        className,
      )}
      {...props}
    >
      <header
        data-slot="incident-review-header"
        className="flex flex-wrap items-end justify-between gap-3"
      >
        <div className="flex min-w-0 items-center gap-3">
          <span
            className={cn(
              "inline-flex h-6 shrink-0 items-center gap-1 rounded-md px-2 font-mono text-[11px] font-semibold uppercase",
              severityStyle[incident.severity],
            )}
          >
            <IconAlertTriangle aria-hidden="true" className="size-3.5" stroke={2.25} />
            {incident.severity}
          </span>
          <div className="min-w-0">
            <h2 className="truncate text-base font-semibold tracking-tight">
              {incident.title}
            </h2>
            <p className="truncate font-mono text-xs text-muted-foreground">
              {incident.id} · {incident.service}
            </p>
          </div>
        </div>
        <div className="flex items-center gap-2 text-xs">
          <span className="inline-flex items-center gap-1 text-muted-foreground tabular-nums">
            <IconClockHour4 aria-hidden="true" className="size-3.5" />
            {incident.duration}
          </span>
          <span
            className={cn(
              "inline-flex h-6 items-center rounded-full border px-2.5 font-medium",
              stateStyle[incident.state],
            )}
          >
            {stateLabel[incident.state]}
          </span>
        </div>
      </header>

      <div className="grid gap-3 sm:gap-4">
        <div className="grid gap-3 sm:gap-4 @4xl/incident:grid-cols-[minmax(0,1.1fr)_minmax(0,1fr)]">
          <InsightCard
            title="What happened"
            source="Incident summary"
            text={incident.summary}
            status={streaming ? "streaming" : "done"}
            sources={incident.sources}
            onRegenerate={onRegenerate}
          />
          <DeployPipeline
            title={incident.release.title}
            meta={incident.release.meta}
            stages={incident.release.stages}
            orientation="auto"
          />
        </div>
        <LatencyHistogram
          title="Latency during the incident"
          description="Checkout requests, compared with the hour before"
          values={incident.latency.during}
          compare={incident.latency.before}
          compareLabel="Before"
          seriesLabel="During"
          threshold={incident.latency.threshold}
          thresholdLabel="SLO"
        />
        <TraceWaterfall
          title={incident.trace.title}
          description="Slowest trace in the incident window"
          spans={incident.trace.spans}
          height={340}
        />
        <LogStream
          entries={incident.events}
          title="Timeline"
          height={220}
          live={false}
        />
      </div>
    </section>
  );
}

/* Sample incident ---------------------------------------------------------- */

function random(seed: number) {
  return () => {
    seed |= 0;
    seed = (seed + 0x6d2b79f5) | 0;
    let t = Math.imul(seed ^ (seed >>> 15), 1 | seed);
    t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;
    return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
  };
}
function logNormal(count: number, median: number, spread: number, seed: number) {
  const next = random(seed);
  return Array.from({ length: count }, () => {
    const u = Math.max(next(), 1e-9);
    const v = next();
    const z = Math.sqrt(-2 * Math.log(u)) * Math.cos(2 * Math.PI * v);
    return Math.round(median * Math.exp(spread * z));
  });
}

const at = (minute: number, second = 0) =>
  Date.UTC(2026, 9, 14, 14, minute, second);

/** A fictional checkout regression, for demos and tests. */
export const sampleIncident: IncidentReviewData = {
  id: "INC-2041",
  title: "Checkout latency regression after release",
  service: "checkout-api",
  severity: "sev2",
  state: "resolved",
  duration: "18 min",
  summary:
    "p95 checkout latency rose to {{metric:p95|412 ms|negative}} two minutes after release web@4f9c2ab reached production {{cite:1}}. The slowest traces spend most of their time in pricing.quote, which ran one promotions query per cart item {{cite:2}}. Rolling back restored p95 to {{metric:p95|186 ms|positive}} within six minutes {{cite:3}}. Follow-up: batch the promotions lookup and give the pricing service a query budget.",
  sources: [
    { id: "1", label: "Release web@4f9c2ab" },
    { id: "2", label: "Trace 9c41e2" },
    { id: "3", label: "Latency dashboard" },
  ],
  latency: {
    before: logNormal(3000, 168, 0.42, 7),
    during: [
      ...logNormal(2100, 236, 0.48, 11),
      ...logNormal(900, 520, 0.38, 13),
    ],
    threshold: 400,
  },
  trace: {
    title: "POST /api/checkout",
    spans: [
      { id: "root", name: "POST /api/checkout", service: "gateway", start: 0, duration: 1240 },
      { id: "auth", parentId: "root", name: "auth.verify_session", service: "auth", start: 6, duration: 38 },
      { id: "sess", parentId: "auth", name: "GET session", service: "redis", start: 9, duration: 3 },
      { id: "cart", parentId: "root", name: "cart.load", service: "cart", start: 48, duration: 84 },
      { id: "cartdb", parentId: "cart", name: "SELECT cart_items", service: "postgres", start: 56, duration: 61 },
      { id: "price", parentId: "root", name: "pricing.quote", service: "pricing", start: 136, duration: 962, attributes: { "cart.items": 14, "db.queries": 15 } },
      ...Array.from({ length: 12 }, (_, index) => ({
        id: `promo-${index}`,
        parentId: "price",
        name: "SELECT promotions WHERE sku = $1",
        service: "postgres",
        start: 148 + index * 76,
        duration: 66 + ((index * 17) % 9),
        attributes: { "db.rows": 1 + (index % 3) },
      })),
      { id: "tax", parentId: "price", name: "tax.calculate", service: "pricing", start: 1060, duration: 30 },
      { id: "pay", parentId: "root", name: "payments.authorize", service: "payments", start: 1104, duration: 118 },
      { id: "psp", parentId: "pay", name: "POST provider /authorize", service: "payments", start: 1110, duration: 104 },
    ],
  },
  release: {
    title: "web@4f9c2ab",
    meta: "Rolled back to 7d1e3fa",
    stages: [
      { id: "build", label: "Build", jobs: [{ id: "compile", label: "Compile", status: "success", duration: 72000 }] },
      {
        id: "test",
        label: "Test",
        jobs: [
          { id: "unit", label: "Unit", status: "success", duration: 48000 },
          { id: "e2e", label: "E2E", status: "success", duration: 161000 },
        ],
      },
      { id: "canary", label: "Canary 10%", jobs: [{ id: "canary-job", label: "Canary", status: "success", duration: 300000, detail: "p95 within budget at 10% traffic" }] },
      { id: "prod", label: "Production", jobs: [{ id: "prod-job", label: "Rollout", status: "canceled", duration: 240000, detail: "Stopped at 100% by rollback" }] },
      { id: "rollback", label: "Rollback", jobs: [{ id: "rollback-job", label: "7d1e3fa", status: "success", duration: 96000 }] },
    ],
  },
  events: [
    { id: "e1", time: at(2, 10), level: "info", source: "deploy", message: "web@4f9c2ab promoted to 100% of production traffic" },
    { id: "e2", time: at(4, 32), level: "warn", source: "alerts", message: "checkout p95 412 ms over 400 ms objective for 2 min" },
    { id: "e3", time: at(5, 5), level: "info", source: "pager", message: "On-call acknowledged INC-2041" },
    { id: "e4", time: at(9, 48), level: "error", source: "pricing", message: "pricing.quote issued 15 queries for a 14-item cart" },
    { id: "e5", time: at(11, 20), level: "info", source: "deploy", message: "Rollback to 7d1e3fa started" },
    { id: "e6", time: at(14, 2), level: "info", source: "alerts", message: "checkout p95 186 ms, back within objective" },
    { id: "e7", time: at(20, 0), level: "info", source: "pager", message: "INC-2041 resolved; follow-up PRICE-311 created" },
  ],
};
```

### `src/registry/overtrue/insight-card.tsx`

```tsx
"use client";

import * as React from "react";
import {
  IconAlertTriangle as AlertTriangle,
  IconArrowDownRight as ArrowDownRight,
  IconArrowUpRight as ArrowUpRight,
  IconCheck as Check,
  IconCopy as Copy,
  IconPlayerStopFilled as Stop,
  IconRefresh as Refresh,
  IconSparkles as Sparkles,
  IconThumbDown as ThumbDown,
  IconThumbDownFilled as ThumbDownFilled,
  IconThumbUp as ThumbUp,
  IconThumbUpFilled as ThumbUpFilled,
} from "@tabler/icons-react";

import { cn } from "@/lib/utils";

export type InsightStatus =
  "idle" | "thinking" | "streaming" | "done" | "error";
export type InsightTone = "positive" | "negative" | "neutral";
export type InsightFeedback = "up" | "down" | null;

/**
 * An inline token parsed from `{{kind:arg|arg|arg}}`.
 * Built in: `{{metric:Label|+12.8%}}`, `{{metric:Churn|-0.4 pts|positive}}`, `{{cite:1}}`.
 */
export interface InsightToken {
  /** The word before the colon, e.g. "metric" or "cite". */
  kind: string;
  /** First argument: the metric label or the source number / id. */
  label: string;
  /** Second argument: the metric value. */
  value?: string;
  /** Third argument when it is positive, negative or neutral; otherwise inferred from the value's sign. */
  tone: InsightTone;
  /** Which way the value moved, from its sign: drives the arrow, while tone drives the color. */
  direction: "up" | "down" | "flat";
  /** Every argument after the colon, trimmed. */
  args: string[];
  /** The original markup. */
  raw: string;
}

export type InsightSegment = string | InsightToken;

export interface InsightSource {
  id: string;
  label: string;
  href?: string;
}

export interface InsightCardLabels {
  thinking: string;
  streaming: string;
  idle: string;
  generate: string;
  regenerate: string;
  stop: string;
  copy: string;
  copied: string;
  helpful: string;
  notHelpful: string;
  sources: string;
  feedback: string;
  error: string;
  retry: string;
}

export interface InsightCardColors {
  /** Caret, sparkle and the moving border. */
  accent?: string;
  /** Second stop of the moving border. */
  glow?: string;
  positive?: string;
  negative?: string;
}

export interface InsightCardProps extends Omit<
  React.ComponentProps<"div">,
  "title" | "children" | "onCopy"
> {
  title?: React.ReactNode;
  /** Model, dataset or time range, shown at the top right. */
  source?: React.ReactNode;
  /** Replaces the sparkle. */
  icon?: React.ReactNode;
  /** The insight, with optional `{{kind:arg|arg}}` tokens. Append to it while streaming. */
  text?: string;
  /** Shorthand for `status="streaming"` while you append to `text`. */
  streaming?: boolean;
  /** Defaults to streaming, done or idle from `streaming`, `text` and `stream`. */
  status?: InsightStatus;
  /** Consumed internally; drives thinking, streaming, done and error. Pass a new iterable to regenerate. */
  stream?: AsyncIterable<string>;
  /** Message for the error state. */
  error?: React.ReactNode;
  sources?: InsightSource[];
  /** Shows Regenerate, and Try again in the error state. */
  onRegenerate?: () => void;
  /** Shows Stop while thinking or streaming. */
  onStop?: () => void;
  /** Called with the plain text. Without it, Copy writes to the clipboard. */
  onCopy?: (text: string) => void;
  feedback?: InsightFeedback;
  defaultFeedback?: InsightFeedback;
  onFeedback?: (feedback: InsightFeedback) => void;
  /** Render a token yourself. Return `undefined` to keep the built-in rendering. */
  renderToken?: (
    token: InsightToken,
    index: number,
  ) => React.ReactNode | undefined;
  /** Replace the token parser. */
  parse?: (text: string) => InsightSegment[];
  /** Characters per second for revealing new text. 0 shows it immediately. */
  speed?: number;
  /** Called once streamed text has fully revealed. */
  onStreamEnd?: () => void;
  /** Extra buttons after Copy. */
  actions?: React.ReactNode;
  colors?: InsightCardColors;
  labels?: Partial<InsightCardLabels>;
}

const LABELS: InsightCardLabels = {
  thinking: "Thinking…",
  streaming: "Writing…",
  idle: "No insight yet.",
  generate: "Generate",
  regenerate: "Regenerate",
  stop: "Stop",
  copy: "Copy",
  copied: "Copied",
  helpful: "Helpful",
  notHelpful: "Not helpful",
  sources: "Sources",
  feedback: "Feedback",
  error: "Couldn’t generate this insight.",
  retry: "Try again",
};

const TOKEN = /\{\{\s*([A-Za-z][\w-]*)\s*:([^{}]*?)\}\}/g;
const TONES = new Set<string>(["positive", "negative", "neutral"]);

function direction(value: string | undefined): InsightToken["direction"] {
  const sign = value?.trim()[0];
  if (sign === "+" || sign === "↑") return "up";
  if (sign === "-" || sign === "−" || sign === "↓") return "down";
  return "flat";
}

/** Split text into strings and tokens. A token cut off at the end is dropped while it streams in. */
export function parseInsight(text: string): InsightSegment[] {
  const segments: InsightSegment[] = [];
  let from = 0;
  for (const match of text.matchAll(TOKEN)) {
    if (match.index > from) segments.push(text.slice(from, match.index));
    const args = match[2].split("|").map((arg) => arg.trim());
    const [label = "", value, third] = args;
    const moved = direction(value);
    segments.push({
      kind: match[1].toLowerCase(),
      label,
      value,
      direction: moved,
      tone:
        third && TONES.has(third)
          ? (third as InsightTone)
          : moved === "up"
            ? "positive"
            : moved === "down"
              ? "negative"
              : "neutral",
      args,
      raw: match[0],
    });
    from = match.index + match[0].length;
  }
  let rest = text.slice(from);
  const open = rest.lastIndexOf("{{");
  if (open !== -1 && !rest.includes("}}", open)) rest = rest.slice(0, open);
  if (rest) segments.push(rest);
  return segments;
}

/** Plain text for copying and screen readers: metrics read "Revenue +12.8%", citations "[1]". */
export function insightToPlainText(
  text: string,
  parse: (text: string) => InsightSegment[] = parseInsight,
) {
  return parse(text)
    .map((segment) =>
      typeof segment === "string"
        ? segment
        : segment.kind === "cite"
          ? `[${segment.label}]`
          : [segment.label, segment.value].filter(Boolean).join(" "),
    )
    .join("")
    .trim();
}

const focusRing =
  "outline-none focus-visible:ring-2 focus-visible:ring-ring/50 focus-visible:ring-offset-1 focus-visible:ring-offset-card";

const useIsoLayoutEffect =
  typeof window === "undefined" ? React.useEffect : React.useLayoutEffect;

const REDUCED = "(prefers-reduced-motion: reduce)";
function useReducedMotion() {
  return React.useSyncExternalStore(
    (callback) => {
      const query = window.matchMedia(REDUCED);
      query.addEventListener("change", callback);
      return () => query.removeEventListener("change", callback);
    },
    () => window.matchMedia(REDUCED).matches,
    () => false,
  );
}

// One reader per iterable, so StrictMode's double effects and remounts share progress.
interface StreamSession {
  text: string;
  status: "thinking" | "streaming" | "done" | "error";
  error?: unknown;
  listeners: Set<() => void>;
  stop: () => void;
}
const sessions = new WeakMap<AsyncIterable<string>, StreamSession>();

function openSession(stream: AsyncIterable<string>) {
  const existing = sessions.get(stream);
  if (existing) return existing;
  const iterator = stream[Symbol.asyncIterator]();
  let stopped = false;
  const session: StreamSession = {
    text: "",
    status: "thinking",
    listeners: new Set(),
    stop: () => {
      if (stopped) return;
      stopped = true;
      if (session.status === "thinking" || session.status === "streaming")
        session.status = "done";
      void iterator.return?.();
    },
  };
  const emit = () => session.listeners.forEach((listener) => listener());
  sessions.set(stream, session);
  void (async () => {
    try {
      while (!stopped) {
        const result = await iterator.next();
        if (stopped) return;
        if (result.done) break;
        session.text += String(result.value ?? "");
        session.status = "streaming";
        emit();
      }
      if (!stopped) {
        session.status = "done";
        emit();
      }
    } catch (error) {
      if (stopped) return;
      session.status = "error";
      session.error = error;
      emit();
    }
  })();
  return session;
}

function useStreamSession(stream: AsyncIterable<string> | undefined) {
  const [, rerender] = React.useReducer((count: number) => count + 1, 0);
  React.useEffect(() => {
    if (!stream) return;
    const session = openSession(stream);
    session.listeners.add(rerender);
    rerender();
    return () => {
      session.listeners.delete(rerender);
      // Stop reading only if nothing resubscribed (StrictMode remounts immediately).
      window.setTimeout(() => {
        if (!session.listeners.size) session.stop();
      }, 0);
    };
  }, [stream]);
  return stream ? (sessions.get(stream) ?? null) : null;
}

/** Move a reveal position past a whole token so chips appear complete. */
function snap(text: string, position: number) {
  const open = text.lastIndexOf("{{", position - 1);
  if (open === -1) return position;
  const close = text.indexOf("}}", open);
  if (close === -1) return open;
  return close + 2 > position ? close + 2 : position;
}

function useReveal(text: string, animate: boolean, speed: number) {
  const [shown, setShown] = React.useState(() => (animate ? 0 : text.length));
  const shownRef = React.useRef(shown);
  const previous = React.useRef(text);

  useIsoLayoutEffect(() => {
    const set = (value: number) => {
      shownRef.current = value;
      setShown(value);
    };
    let start = shownRef.current;
    // Replaced rather than appended: start over.
    if (!text.startsWith(previous.current.slice(0, start))) start = 0;
    previous.current = text;
    if (!animate || !(speed > 0) || !Number.isFinite(speed))
      start = text.length;
    start = Math.min(start, text.length);
    set(start);
    if (start >= text.length) return;

    let frame = 0;
    let last = performance.now();
    let carry = start;
    const tick = (now: number) => {
      const dt = Math.min(now - last, 100);
      last = now;
      // Catch up when the source runs ahead, so the reveal never lags by more than ~2s.
      const backlog = text.length - carry;
      carry = Math.min(
        text.length,
        carry + (speed * Math.max(1, backlog / (speed * 2)) * dt) / 1000,
      );
      const next = snap(text, Math.floor(carry));
      if (next > shownRef.current) set(next);
      // Wait for the rest of a half-received token before going on.
      if (next < Math.floor(carry)) return;
      if (next < text.length) frame = requestAnimationFrame(tick);
    };
    frame = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(frame);
  }, [text, animate, speed]);

  return Math.min(shown, text.length);
}

const toneClass: Record<InsightTone, string> = {
  positive:
    "border-(--insight-positive)/25 bg-(--insight-positive)/8 [--chip:var(--insight-positive)]",
  negative:
    "border-(--insight-negative)/25 bg-(--insight-negative)/8 [--chip:var(--insight-negative)]",
  neutral: "border-border bg-muted/60 [--chip:var(--color-muted-foreground)]",
};

function MetricChip({ token }: { token: InsightToken }) {
  const Arrow =
    token.direction === "up"
      ? ArrowUpRight
      : token.direction === "down"
        ? ArrowDownRight
        : null;
  return (
    <span
      data-slot="insight-token"
      data-kind="metric"
      data-tone={token.tone}
      className={cn(
        "mx-px inline-flex translate-y-[-1px] items-center gap-1 rounded-md border px-1.5 align-middle text-[12.5px] leading-5 whitespace-nowrap",
        "transition-[opacity,scale] duration-300 ease-out starting:scale-90 starting:opacity-0 motion-reduce:transition-none",
        toneClass[token.tone],
      )}
    >
      {token.label && (
        <span className="font-medium text-foreground">{token.label}</span>
      )}
      {token.value && (
        <span className="inline-flex items-center gap-0.5 font-mono text-[12px] font-medium text-[color-mix(in_oklab,var(--chip)_82%,var(--color-foreground))] tabular-nums">
          {Arrow && (
            <Arrow className="size-3" aria-hidden="true" stroke={2.25} />
          )}
          {token.value}
        </span>
      )}
    </span>
  );
}

const styles = `@property --insight-angle{syntax:"<angle>";inherits:false;initial-value:0deg}@keyframes insight-spin{to{--insight-angle:360deg}}@keyframes insight-shimmer{from{background-position:100% 0}to{background-position:-100% 0}}@keyframes insight-caret{0%,50%{opacity:1}50.01%,100%{opacity:0}}`;

const ring =
  "conic-gradient(from var(--insight-angle), transparent 0%, var(--insight-accent) 12%, var(--insight-glow) 22%, transparent 34%, transparent 50%, var(--insight-glow) 62%, var(--insight-accent) 72%, transparent 84%)";

const ringMask: React.CSSProperties = {
  padding: 1,
  WebkitMask:
    "linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0)",
  WebkitMaskComposite: "xor",
  mask: "linear-gradient(#000 0 0) content-box exclude, linear-gradient(#000 0 0)",
};

/**
 * An AI summary for dashboards: streams text with a caret, turns `{{metric:…}}` markup
 * into delta chips, cites numbered sources, and offers regenerate, copy and feedback.
 */
export function InsightCard({
  title = "Insight",
  source,
  icon,
  text = "",
  streaming,
  status: statusProp,
  stream,
  error,
  sources,
  onRegenerate,
  onStop,
  onCopy,
  feedback: feedbackProp,
  defaultFeedback = null,
  onFeedback,
  renderToken,
  parse = parseInsight,
  speed = 90,
  onStreamEnd,
  actions,
  colors,
  labels: labelsProp,
  className,
  style,
  ...props
}: InsightCardProps) {
  const labels = { ...LABELS, ...labelsProp };
  const reduced = useReducedMotion();
  const session = useStreamSession(stream);

  const fullText = stream ? (session?.text ?? "") : text;
  const sourceStatus: InsightStatus = stream
    ? (statusProp ?? session?.status ?? "thinking")
    : (statusProp ?? (streaming ? "streaming" : text ? "done" : "idle"));
  const active = sourceStatus === "thinking" || sourceStatus === "streaming";

  const [feedbackState, setFeedbackState] =
    React.useState<InsightFeedback>(defaultFeedback);
  const feedback = feedbackProp !== undefined ? feedbackProp : feedbackState;

  // "Live" spans one generation: from thinking/streaming until the reveal catches up.
  const [live, setLive] = React.useState(active);
  if (active && !live) {
    setLive(true);
    // Feedback belongs to the previous answer.
    setFeedbackState(null);
  }

  // Hold the reveal while thinking, so text supplied early still streams in afterwards.
  const revealText = sourceStatus === "thinking" ? "" : fullText;
  const shown = useReveal(revealText, live && !reduced, speed);
  const revealing = shown < revealText.length;
  const status: InsightStatus =
    sourceStatus === "error"
      ? "error"
      : sourceStatus === "thinking"
        ? "thinking"
        : sourceStatus === "streaming" || (live && revealing)
          ? "streaming"
          : fullText
            ? "done"
            : "idle";

  const onStreamEndRef = React.useRef(onStreamEnd);
  onStreamEndRef.current = onStreamEnd;
  React.useEffect(() => {
    if (live && !active && !revealing) {
      setLive(false);
      if (sourceStatus === "done") onStreamEndRef.current?.();
    }
  }, [live, active, revealing, sourceStatus]);

  const setFeedback = (value: InsightFeedback) => {
    const next = value === feedback ? null : value;
    if (feedbackProp === undefined) setFeedbackState(next);
    onFeedback?.(next);
  };

  const [copied, setCopied] = React.useState(false);
  React.useEffect(() => {
    if (!copied) return;
    const timer = window.setTimeout(() => setCopied(false), 1600);
    return () => window.clearTimeout(timer);
  }, [copied]);

  const [hoveredSource, setHoveredSource] = React.useState<string | null>(null);

  const plain = React.useMemo(
    () => insightToPlainText(fullText, parse),
    [fullText, parse],
  );
  const visible =
    shown >= fullText.length ? fullText : fullText.slice(0, shown);
  const segments = React.useMemo(() => parse(visible), [parse, visible]);

  const copy = async () => {
    if (onCopy) onCopy(plain);
    else {
      try {
        await navigator.clipboard?.writeText(plain);
      } catch {
        return;
      }
    }
    setCopied(true);
  };

  const findSource = (ref: string) => {
    if (!sources) return undefined;
    const index = /^\d+$/.test(ref)
      ? Number(ref) - 1
      : sources.findIndex((item) => item.id === ref);
    return index >= 0 && index < sources.length
      ? { source: sources[index], number: index + 1 }
      : undefined;
  };

  const renderSegment = (
    segment: InsightSegment,
    index: number,
  ): React.ReactNode => {
    if (typeof segment === "string") return segment;
    const custom = renderToken?.(segment, index);
    if (custom !== undefined) return custom;
    if (segment.kind === "metric") return <MetricChip token={segment} />;
    if (segment.kind === "cite") {
      const found = findSource(segment.label);
      const number = found?.number ?? segment.label;
      const chip = cn(
        "mx-px inline-flex h-4 min-w-4 -translate-y-px items-center justify-center rounded-[4px] bg-muted px-1 align-middle font-mono text-[10px] leading-none font-medium text-muted-foreground transition-colors",
        "transition-[opacity,background-color,color] duration-300 starting:opacity-0 motion-reduce:transition-none",
      );
      const highlight = {
        onPointerEnter: () => found && setHoveredSource(found.source.id),
        onPointerLeave: () => setHoveredSource(null),
        onFocus: () => found && setHoveredSource(found.source.id),
        onBlur: () => setHoveredSource(null),
      };
      return found?.source.href ? (
        <a
          data-slot="insight-token"
          data-kind="cite"
          href={found.source.href}
          target="_blank"
          rel="noreferrer"
          aria-label={`${labels.sources} ${number}: ${found.source.label}`}
          className={cn(
            chip,
            "hover:bg-(--insight-accent)/12 hover:text-(--insight-accent)",
            focusRing,
          )}
          {...highlight}
        >
          {number}
        </a>
      ) : (
        <span
          data-slot="insight-token"
          data-kind="cite"
          title={found?.source.label}
          className={cn(
            chip,
            found &&
              "cursor-default hover:bg-(--insight-accent)/12 hover:text-(--insight-accent)",
          )}
          {...highlight}
        >
          {number}
        </span>
      );
    }
    return (
      <span
        data-slot="insight-token"
        data-kind={segment.kind}
        className="font-medium"
      >
        {segment.label}
      </span>
    );
  };

  // Paragraphs on blank lines, line breaks on single newlines. A paragraph made only
  // of tokens becomes a row of highlights.
  const paragraphs: { nodes: React.ReactNode[]; prose: boolean }[] = [
    { nodes: [], prose: false },
  ];
  segments.forEach((segment, index) => {
    if (typeof segment !== "string") {
      paragraphs[paragraphs.length - 1].nodes.push(
        <React.Fragment key={index}>
          {renderSegment(segment, index)}
        </React.Fragment>,
      );
      return;
    }
    segment.split(/\n{2,}/).forEach((chunk, part) => {
      if (part > 0) paragraphs.push({ nodes: [], prose: false });
      chunk.split("\n").forEach((line, row) => {
        const target = paragraphs[paragraphs.length - 1];
        if (row > 0)
          target.nodes.push(<br key={`${index}-${part}-${row}-br`} />);
        if (line.trim()) target.prose = true;
        if (line)
          target.nodes.push(
            <React.Fragment key={`${index}-${part}-${row}`}>
              {line}
            </React.Fragment>,
          );
      });
    });
  });

  const busy = status === "thinking" || status === "streaming";
  const colorVars = colors
    ? ({
        ...(colors.accent && { "--insight-accent": colors.accent }),
        ...(colors.glow && { "--insight-glow": colors.glow }),
        ...(colors.positive && { "--insight-positive": colors.positive }),
        ...(colors.negative && { "--insight-negative": colors.negative }),
      } as React.CSSProperties)
    : undefined;

  const button = cn(
    "inline-flex h-7 items-center justify-center gap-1.5 rounded-md text-xs font-medium text-muted-foreground transition-colors hover:bg-muted hover:text-foreground disabled:pointer-events-none disabled:opacity-40 motion-reduce:transition-none",
    focusRing,
  );

  return (
    <div
      data-slot="insight-card"
      data-status={status}
      aria-busy={busy || undefined}
      className={cn(
        "@container/insight relative isolate flex min-w-0 flex-col rounded-xl border bg-card text-card-foreground shadow-xs",
        "[--insight-accent:var(--color-primary)] [--insight-glow:var(--color-chart-4)] [--insight-negative:var(--color-destructive)] [--insight-positive:var(--color-emerald-600)] dark:[--insight-positive:var(--color-emerald-400)]",
        className,
      )}
      style={{ ...colorVars, ...style }}
      {...props}
    >
      <style href="overtrue-insight-card" precedence="default">
        {styles}
      </style>

      {/* Moving border and soft glow while the model works. */}
      <span
        aria-hidden="true"
        data-slot="insight-glow"
        className={cn(
          "pointer-events-none absolute -inset-px -z-10 rounded-[inherit] blur-md transition-opacity duration-700 motion-safe:animate-[insight-spin_3.2s_linear_infinite] motion-reduce:transition-none",
          busy ? "opacity-35 dark:opacity-45" : "opacity-0",
        )}
        style={{ background: ring }}
      />
      {/* The surface sits above the glow so only its spill outside the card shows. */}
      <span
        aria-hidden="true"
        className="pointer-events-none absolute inset-0 -z-5 rounded-[inherit] bg-card"
      />
      <span
        aria-hidden="true"
        className={cn(
          "pointer-events-none absolute -inset-px rounded-[inherit] transition-opacity duration-700 motion-safe:animate-[insight-spin_3.2s_linear_infinite] motion-reduce:transition-none",
          busy ? "opacity-100" : "opacity-0",
        )}
        style={{ ...ringMask, background: ring }}
      />
      {/* A faint wash behind the header keeps the card recognisable as generated. */}
      <span
        aria-hidden="true"
        className="pointer-events-none absolute inset-x-0 top-0 h-24 rounded-t-[inherit] bg-[radial-gradient(120%_100%_at_0%_0%,color-mix(in_oklab,var(--insight-accent)_9%,transparent),transparent_60%)]"
      />

      <div className="relative flex flex-wrap items-center gap-x-3 gap-y-2 px-4 pt-3.5 @sm/insight:px-5 @sm/insight:pt-4">
        <div className="flex min-w-0 flex-1 basis-full items-center gap-2.5 @lg/insight:basis-44">
          <span
            aria-hidden="true"
            className="relative flex size-7 shrink-0 items-center justify-center rounded-lg border border-(--insight-accent)/20 bg-[linear-gradient(135deg,color-mix(in_oklab,var(--insight-accent)_16%,var(--color-card)),color-mix(in_oklab,var(--insight-glow)_14%,var(--color-card)))] text-(--insight-accent)"
          >
            {icon ?? (
              <Sparkles
                className={cn("size-4", busy && "motion-safe:animate-pulse")}
                stroke={1.75}
              />
            )}
          </span>
          <div className="flex min-w-0 flex-wrap items-baseline gap-x-2 gap-y-0.5">
            <div className="text-sm leading-5 font-semibold tracking-tight [overflow-wrap:anywhere]">
              {title}
            </div>
            {busy && (
              <div
                data-slot="insight-progress"
                className="hidden shrink-0 bg-linear-to-r from-muted-foreground @xs/insight:block via-foreground to-muted-foreground bg-size-[200%_100%] bg-clip-text text-xs text-transparent motion-safe:animate-[insight-shimmer_1.8s_linear_infinite] motion-reduce:text-muted-foreground"
              >
                {status === "thinking" ? labels.thinking : labels.streaming}
              </div>
            )}
          </div>
        </div>
        {source && (
          <div
            data-slot="insight-source-label"
            className="flex min-w-0 items-center gap-1.5 pl-9.5 text-xs leading-5 text-muted-foreground [overflow-wrap:anywhere] @lg/insight:pl-0"
          >
            {source}
          </div>
        )}
      </div>

      <div className="relative px-4 pt-3 pb-4 @sm/insight:px-5">
        {status === "thinking" ? (
          <div
            data-slot="insight-skeleton"
            className="space-y-2.5 py-1"
            aria-hidden="true"
          >
            {[92, 100, 78, 56].map((width, index) => (
              <div
                key={index}
                className="h-2.5 rounded-full bg-linear-to-r from-muted via-foreground/[0.07] to-muted bg-size-[200%_100%] motion-safe:animate-[insight-shimmer_1.6s_linear_infinite] dark:via-foreground/[0.1]"
                style={{
                  width: `${width}%`,
                  animationDelay: `${index * 120}ms`,
                }}
              />
            ))}
          </div>
        ) : status === "error" ? (
          <div
            data-slot="insight-error"
            role="alert"
            className="flex items-start gap-3 rounded-lg border border-destructive/25 bg-destructive/[0.06] p-3"
          >
            <AlertTriangle
              className="mt-0.5 size-4 shrink-0 text-destructive"
              aria-hidden="true"
            />
            <div className="min-w-0 flex-1">
              <div className="text-sm font-medium">{labels.error}</div>
              {error && (
                <div className="mt-0.5 text-xs leading-5 text-muted-foreground">
                  {error}
                </div>
              )}
              {onRegenerate && (
                <button
                  type="button"
                  onClick={onRegenerate}
                  className={cn(
                    "mt-2 inline-flex h-7 items-center gap-1.5 rounded-md border bg-card px-2.5 text-xs font-medium shadow-xs transition-colors hover:bg-muted motion-reduce:transition-none",
                    focusRing,
                  )}
                >
                  <Refresh className="size-3.5" aria-hidden="true" />
                  {labels.retry}
                </button>
              )}
            </div>
          </div>
        ) : status === "idle" ? (
          <div className="flex items-center justify-between gap-3 rounded-lg border border-dashed px-3 py-2.5">
            <span className="text-sm text-muted-foreground">{labels.idle}</span>
            {onRegenerate && (
              <button
                type="button"
                onClick={onRegenerate}
                className={cn(
                  "inline-flex h-7 items-center gap-1.5 rounded-md bg-primary px-2.5 text-xs font-medium text-primary-foreground shadow-xs transition-opacity hover:opacity-90 motion-reduce:transition-none",
                  focusRing,
                )}
              >
                <Sparkles className="size-3.5" aria-hidden="true" />
                {labels.generate}
              </button>
            )}
          </div>
        ) : (
          <div
            data-slot="insight-body"
            className="space-y-3 text-sm leading-6 text-pretty text-foreground/90"
          >
            {paragraphs.map((paragraph, index) => {
              const caret = status === "streaming" &&
                index === paragraphs.length - 1 && (
                  <span
                    aria-hidden="true"
                    data-slot="insight-caret"
                    className="ml-0.5 inline-block h-[1.05em] w-[2px] translate-y-[0.18em] rounded-full bg-(--insight-accent) motion-safe:animate-[insight-caret_1s_linear_infinite]"
                  />
                );
              return paragraph.prose || paragraph.nodes.length === 0 ? (
                <p key={index} className="break-words">
                  {paragraph.nodes}
                  {caret}
                </p>
              ) : (
                <div
                  key={index}
                  data-slot="insight-highlights"
                  className="flex flex-wrap items-center gap-1.5 [&_[data-slot=insight-token]]:mx-0"
                >
                  {paragraph.nodes}
                  {caret}
                </div>
              );
            })}
          </div>
        )}

        {status === "done" && sources && sources.length > 0 && (
          <div
            data-slot="insight-sources"
            className="mt-3.5 flex flex-wrap items-center gap-1.5 transition-[opacity,translate] duration-500 ease-out starting:translate-y-1 starting:opacity-0 motion-reduce:transition-none"
          >
            <span className="mr-0.5 text-xs text-muted-foreground">
              {labels.sources}
            </span>
            {sources.map((item, index) => {
              const content = (
                <>
                  <span className="flex h-4 min-w-4 items-center justify-center rounded-[4px] bg-muted px-1 font-mono text-[10px] leading-none font-medium text-muted-foreground">
                    {index + 1}
                  </span>
                  <span className="min-w-0 truncate">{item.label}</span>
                  {item.href && (
                    <ArrowUpRight
                      className="size-3 shrink-0 text-muted-foreground"
                      aria-hidden="true"
                    />
                  )}
                </>
              );
              const chip = cn(
                "inline-flex h-6 max-w-full min-w-0 items-center gap-1.5 rounded-md border bg-card pr-2 pl-1 text-xs transition-colors motion-reduce:transition-none",
                hoveredSource === item.id &&
                  "border-(--insight-accent)/40 bg-(--insight-accent)/[0.06]",
              );
              return item.href ? (
                <a
                  key={item.id}
                  data-slot="insight-source"
                  data-active={hoveredSource === item.id || undefined}
                  href={item.href}
                  target="_blank"
                  rel="noreferrer"
                  className={cn(chip, "hover:bg-muted", focusRing)}
                >
                  {content}
                </a>
              ) : (
                <span
                  key={item.id}
                  data-slot="insight-source"
                  data-active={hoveredSource === item.id || undefined}
                  className={chip}
                >
                  {content}
                </span>
              );
            })}
          </div>
        )}
      </div>

      {status !== "idle" && status !== "error" && (
        <div
          data-slot="insight-actions"
          className="relative mt-auto flex items-center gap-1 border-t px-2 py-1.5 @sm/insight:px-3"
        >
          {busy && onStop ? (
            <button
              type="button"
              onClick={onStop}
              className={cn(button, "px-2")}
            >
              <Stop className="size-3" aria-hidden="true" />
              {labels.stop}
            </button>
          ) : (
            onRegenerate && (
              <button
                type="button"
                onClick={onRegenerate}
                disabled={busy}
                aria-label={labels.regenerate}
                title={labels.regenerate}
                className={cn(button, "px-2")}
              >
                <Refresh className="size-3.5" aria-hidden="true" />
                <span className="hidden @xs/insight:inline">
                  {labels.regenerate}
                </span>
              </button>
            )
          )}
          <button
            type="button"
            onClick={copy}
            disabled={busy || !plain}
            aria-label={copied ? labels.copied : labels.copy}
            title={labels.copy}
            className={cn(button, "px-2")}
          >
            {copied ? (
              <Check
                className="size-3.5 text-(--insight-positive)"
                aria-hidden="true"
              />
            ) : (
              <Copy className="size-3.5" aria-hidden="true" />
            )}
            <span className="hidden @xs/insight:inline">
              {copied ? labels.copied : labels.copy}
            </span>
          </button>
          {actions}
          <div
            className="ml-auto flex items-center gap-0.5"
            role="group"
            aria-label={labels.feedback}
          >
            <button
              type="button"
              aria-pressed={feedback === "up"}
              aria-label={labels.helpful}
              title={labels.helpful}
              disabled={busy || status !== "done"}
              onClick={() => setFeedback("up")}
              className={cn(
                button,
                "size-7",
                feedback === "up" &&
                  "text-(--insight-accent) hover:text-(--insight-accent)",
              )}
            >
              {feedback === "up" ? (
                <ThumbUpFilled className="size-3.5" aria-hidden="true" />
              ) : (
                <ThumbUp className="size-3.5" aria-hidden="true" />
              )}
            </button>
            <button
              type="button"
              aria-pressed={feedback === "down"}
              aria-label={labels.notHelpful}
              title={labels.notHelpful}
              disabled={busy || status !== "done"}
              onClick={() => setFeedback("down")}
              className={cn(
                button,
                "size-7",
                feedback === "down" && "text-foreground",
              )}
            >
              {feedback === "down" ? (
                <ThumbDownFilled className="size-3.5" aria-hidden="true" />
              ) : (
                <ThumbDown className="size-3.5" aria-hidden="true" />
              )}
            </button>
          </div>
        </div>
      )}

      {/* Announce once: the finished text, not every token. */}
      <div className="sr-only" aria-live="polite" aria-atomic="true">
        {status === "done"
          ? plain
          : status === "thinking"
            ? labels.thinking
            : ""}
      </div>
    </div>
  );
}
```

### `src/registry/overtrue/latency-histogram.tsx`

```tsx
"use client";

import * as React from "react";
import { IconX as X } from "@tabler/icons-react";

import { cn } from "@/lib/utils";

export type LatencyScale = "linear" | "log";

export type LatencyRange = [min: number, max: number];

export interface LatencyBucket {
  /** Inclusive lower edge. */
  start: number;
  /** Exclusive upper edge. */
  end: number;
  count: number;
}

/** One bar as drawn, passed to `renderTooltip`. */
export interface LatencyHistogramBucket extends LatencyBucket {
  index: number;
  /** Share of all requests in this bucket, 0–1. */
  share: number;
  /** Share of requests at or below this bucket's upper edge, 0–1. */
  cumulative: number;
  /** Raw comparison count in the same range, when `compare` is set. */
  compare?: number;
  /** Comparison share of its own total, 0–1. */
  compareShare?: number;
  /** The catch-all bar for values past the linear domain. */
  overflow: boolean;
  /** Whether the bucket lies past `threshold`. */
  overThreshold: boolean;
}

export interface LatencyHistogramColors {
  bar: string;
  compare: string;
  threshold: string;
  marker: string;
  selection: string;
}

export interface LatencyHistogramProps extends Omit<
  React.ComponentProps<"div">,
  "title" | "children" | "color"
> {
  /** Raw samples. Bucketed for you, with exact percentiles. */
  values?: number[];
  /** Pre-bucketed counts, used when `values` is not given. Percentiles are interpolated. */
  buckets?: LatencyBucket[];
  /** A comparison distribution, e.g. yesterday. Scaled to the main total so shapes compare. */
  compare?: number[] | LatencyBucket[];
  /** Name of the comparison in the legend and tooltip. */
  compareLabel?: string;
  /** Name of the main series in the legend. */
  seriesLabel?: string;
  /** Draw the comparison as a stepped line or as outlined bars. */
  compareStyle?: "step" | "outline";
  /** Percentiles to mark, as numbers such as 50 or 99.9. */
  percentiles?: number[];
  /** Latency objective. The slow tail past it is shaded and measured. */
  threshold?: number;
  thresholdLabel?: string;
  /** X scale. Pass with `onScaleChange` to control the built-in toggle. */
  scale?: LatencyScale;
  defaultScale?: LatencyScale;
  onScaleChange?: (scale: LatencyScale) => void;
  /** Show the linear/log toggle. Defaults to true. */
  showScaleToggle?: boolean;
  /** Brushed range. Pass `null` for none; leave undefined to let the component manage it. */
  range?: LatencyRange | null;
  defaultRange?: LatencyRange | null;
  onRangeChange?: (range: LatencyRange | null) => void;
  title?: React.ReactNode;
  description?: React.ReactNode;
  /** Controls placed at the top right, before the scale toggle. */
  actions?: React.ReactNode;
  /** Unit of the values. Defaults to "ms"; ms readouts switch to seconds from 1,000. */
  unit?: string;
  /** Formats latencies in readouts, markers, and ticks. */
  valueFormatter?: (value: number) => string;
  /** Target number of bars. Defaults to 40. */
  bucketCount?: number;
  /** Fix the latency domain. Linear charts otherwise end near p99.5 and gather the rest in an overflow bar. */
  domain?: LatencyRange;
  /** Plot height in pixels. Defaults to a third of the plot width, between 140 and 220. */
  height?: number;
  /** Override any series color with a CSS color. */
  colors?: Partial<LatencyHistogramColors>;
  /** Replaces the hover tooltip content. */
  renderTooltip?: (bucket: LatencyHistogramBucket) => React.ReactNode;
  /** Show the percentile summary above the plot. Defaults to true. */
  showSummary?: boolean;
}

/* ------------------------------------------------------------------------ */
/* Formatting                                                                */
/* ------------------------------------------------------------------------ */

const tidy = (value: number) => +value.toPrecision(12);
const compact = new Intl.NumberFormat("en-US", {
  notation: "compact",
  maximumFractionDigits: 1,
});
const whole = new Intl.NumberFormat("en-US");

function makeFormatter(unit: string) {
  const tight = unit.length <= 2;
  const join = (text: string, u: string) =>
    u ? `${text}${tight ? "" : " "}${u}` : text;
  return (value: number) => {
    if (!Number.isFinite(value)) return "—";
    const a = Math.abs(value);
    if (unit === "ms" && a >= 1000)
      return `${tidy(+(value / 1000).toFixed(a >= 10_000 ? 1 : 2))}s`;
    const digits = a >= 100 || a === 0 ? 0 : a >= 10 ? 1 : a >= 1 ? 2 : 3;
    return join(String(tidy(+value.toFixed(digits))), unit);
  };
}

function makeTickFormatter(unit: string) {
  const tight = unit.length <= 2;
  return (value: number) => {
    if (value === 0) return "0";
    if (unit === "ms" && Math.abs(value) >= 1000)
      return `${tidy(value / 1000)}s`;
    return `${tidy(value)}${tight ? "" : " "}${unit}`;
  };
}

function percentLabel(share: number) {
  const pct = share * 100;
  if (pct === 0) return "0%";
  if (pct < 0.1) return "<0.1%";
  if (pct > 99.9 && pct < 100) return ">99.9%";
  return `${pct >= 10 ? pct.toFixed(1) : pct.toFixed(2)}%`;
}

function niceStep(raw: number) {
  if (!(raw > 0)) return 1;
  const magnitude = 10 ** Math.floor(Math.log10(raw));
  const r = raw / magnitude;
  return (
    (r <= 1 ? 1 : r <= 2 ? 2 : r <= 2.5 ? 2.5 : r <= 5 ? 5 : 10) * magnitude
  );
}

/** Round down or up to the nearest 1, 2, or 5 times a power of ten. */
function nice125(value: number, up: boolean) {
  const magnitude = 10 ** Math.floor(Math.log10(value));
  const r = value / magnitude;
  const steps = [1, 2, 5, 10];
  if (up) return (steps.find((s) => s >= r - 1e-9) ?? 10) * magnitude;
  return ([...steps].reverse().find((s) => s <= r + 1e-9) ?? 1) * magnitude;
}

function lowerBound(sorted: Float64Array, value: number) {
  let lo = 0;
  let hi = sorted.length;
  while (lo < hi) {
    const mid = (lo + hi) >> 1;
    if (sorted[mid] < value) lo = mid + 1;
    else hi = mid;
  }
  return lo;
}

function upperBound(sorted: Float64Array, value: number) {
  let lo = 0;
  let hi = sorted.length;
  while (lo < hi) {
    const mid = (lo + hi) >> 1;
    if (sorted[mid] <= value) lo = mid + 1;
    else hi = mid;
  }
  return lo;
}

/* ------------------------------------------------------------------------ */
/* Model                                                                     */
/* ------------------------------------------------------------------------ */

interface Bar extends LatencyBucket {
  overflow: boolean;
  /** Left and right edges as 0–1 positions. */
  x0: number;
  x1: number;
}

interface Distribution {
  sorted: Float64Array | null;
  buckets: LatencyBucket[] | null;
  total: number;
  min: number;
  max: number;
  mean: number;
}

function distributionOf(
  values?: number[],
  buckets?: LatencyBucket[],
): Distribution {
  if (values) {
    const clean = values.filter((value) => Number.isFinite(value));
    const sorted = Float64Array.from(clean).sort();
    let sum = 0;
    for (const value of sorted) sum += value;
    return {
      sorted,
      buckets: null,
      total: sorted.length,
      min: sorted.length ? sorted[0] : 0,
      max: sorted.length ? sorted[sorted.length - 1] : 0,
      mean: sorted.length ? sum / sorted.length : 0,
    };
  }
  const list = (buckets ?? [])
    .filter(
      (b) =>
        Number.isFinite(b.start) && Number.isFinite(b.end) && b.end > b.start,
    )
    .sort((a, b) => a.start - b.start);
  let total = 0;
  let sum = 0;
  for (const b of list) {
    total += Math.max(0, b.count);
    sum += (Math.max(0, b.count) * (b.start + b.end)) / 2;
  }
  return {
    sorted: null,
    buckets: list,
    total,
    min: list.length ? list[0].start : 0,
    max: list.length ? list[list.length - 1].end : 0,
    mean: total ? sum / total : 0,
  };
}

/** Nearest-rank percentile from samples; interpolated inside buckets otherwise. */
function quantile(d: Distribution, p: number) {
  if (!d.total) return 0;
  if (d.sorted)
    return d.sorted[
      Math.min(d.total - 1, Math.max(0, Math.ceil(p * d.total) - 1))
    ];
  const target = p * d.total;
  let cumulative = 0;
  for (const b of d.buckets!) {
    if (cumulative + b.count >= target && b.count > 0)
      return b.start + ((target - cumulative) / b.count) * (b.end - b.start);
    cumulative += b.count;
  }
  return d.max;
}

/** Requests with a value in [a, b]. Partial buckets count in proportion. */
function countBetween(d: Distribution, a: number, b: number) {
  if (d.sorted) return upperBound(d.sorted, b) - lowerBound(d.sorted, a);
  let count = 0;
  for (const bucket of d.buckets!) {
    const overlap = Math.min(b, bucket.end) - Math.max(a, bucket.start);
    if (overlap > 0)
      count += (bucket.count * overlap) / (bucket.end - bucket.start);
  }
  return count;
}

function countAbove(d: Distribution, value: number) {
  if (d.sorted) return d.total - upperBound(d.sorted, value);
  return countBetween(d, value, Infinity);
}

interface Layout {
  bars: Bar[];
  lo: number;
  hi: number;
  /** Largest value covered, including the overflow bar. */
  top: number;
  pos: (value: number) => number;
  inv: (x: number) => number;
}

function layoutOf(
  d: Distribution,
  scale: LatencyScale,
  bucketCount: number,
  reach: number,
  domain?: LatencyRange,
): Layout {
  const count = Math.max(4, Math.round(bucketCount));
  // Pre-bucketed data keeps its own edges.
  if (d.buckets) {
    const list = d.buckets;
    const first = list[0]?.start ?? 0;
    const last = list[list.length - 1]?.end ?? 1;
    if (scale === "log") {
      const positive =
        list.find((b) => b.start > 0)?.start ?? list[0]?.end ?? 1;
      const lo = first > 0 ? first : positive / 2;
      const span = Math.log(last / lo) || 1;
      const pos = (v: number) =>
        Math.min(1, Math.max(0, Math.log(Math.max(v, lo) / lo) / span));
      const inv = (x: number) => lo * Math.exp(x * span);
      return {
        bars: list.map((b) => ({
          ...b,
          overflow: false,
          x0: pos(b.start),
          x1: pos(b.end),
        })),
        lo,
        hi: last,
        top: last,
        pos,
        inv,
      };
    }
    const span = last - first || 1;
    const pos = (v: number) => Math.min(1, Math.max(0, (v - first) / span));
    const inv = (x: number) => first + x * span;
    return {
      bars: list.map((b) => ({
        ...b,
        overflow: false,
        x0: pos(b.start),
        x1: pos(b.end),
      })),
      lo: first,
      hi: last,
      top: last,
      pos,
      inv,
    };
  }

  const sorted = d.sorted!;
  if (scale === "log") {
    const positive = sorted[lowerBound(sorted, Number.MIN_VALUE)] ?? 1;
    const lo =
      domain?.[0] && domain[0] > 0
        ? domain[0]
        : nice125(Math.max(positive, 1e-9), false);
    const hi = Math.max(
      domain?.[1] ?? nice125(Math.max(d.max, lo * 10), true),
      lo * 1.0001,
    );
    const span = Math.log(hi / lo);
    const step = span / count;
    const bars: Bar[] = Array.from({ length: count }, (_, i) => ({
      start: lo * Math.exp(i * step),
      end: lo * Math.exp((i + 1) * step),
      count: 0,
      overflow: false,
      x0: i / count,
      x1: (i + 1) / count,
    }));
    for (const v of sorted) {
      const i = v <= lo ? 0 : Math.floor(Math.log(v / lo) / step);
      bars[Math.min(count - 1, Math.max(0, i))].count += 1;
    }
    const pos = (v: number) =>
      Math.min(1, Math.max(0, Math.log(Math.max(v, lo) / lo) / span));
    return { bars, lo, hi, top: hi, pos, inv: (x) => lo * Math.exp(x * span) };
  }

  const lo = domain?.[0] ?? (d.min >= 0 ? 0 : -niceStep(-d.min));
  const wanted = domain?.[1] ?? Math.max(reach, lo + 1e-9);
  const step = niceStep((wanted - lo) / count);
  const n = Math.max(1, Math.ceil((wanted - lo) / step - 1e-9));
  const hi = lo + n * step;
  const overflowCount = d.total - upperBound(sorted, hi);
  const units = overflowCount > 0 ? n + 1.7 : n;
  const bars: Bar[] = Array.from({ length: n }, (_, i) => ({
    start: tidy(lo + i * step),
    end: tidy(lo + (i + 1) * step),
    count: 0,
    overflow: false,
    x0: i / units,
    x1: (i + 1) / units,
  }));
  for (
    let k = lowerBound(sorted, lo), end = upperBound(sorted, hi);
    k < end;
    k++
  )
    bars[Math.min(n - 1, Math.floor((sorted[k] - lo) / step))].count += 1;
  // Values below a fixed domain fold into the first bar.
  bars[0].count += lowerBound(sorted, lo);
  const top = Math.max(hi, d.max);
  if (overflowCount > 0)
    bars.push({
      start: hi,
      end: top,
      count: overflowCount,
      overflow: true,
      x0: (n + 0.7) / units,
      x1: 1,
    });
  const mainEnd = n / units;
  const overflowStart = (n + 0.7) / units;
  const pos = (v: number) => {
    if (v <= hi) return Math.max(0, ((v - lo) / (hi - lo)) * mainEnd);
    if (overflowCount <= 0 || top <= hi) return mainEnd;
    return Math.min(
      1,
      overflowStart + ((v - hi) / (top - hi)) * (1 - overflowStart),
    );
  };
  const inv = (x: number) => {
    if (x <= mainEnd) return lo + (x / mainEnd) * (hi - lo);
    if (x < overflowStart || overflowCount <= 0) return hi;
    return hi + ((x - overflowStart) / (1 - overflowStart)) * (top - hi);
  };
  return { bars, lo, hi, top, pos, inv };
}

/** Bin a comparison into the main bars' edges. */
function binCompare(compare: number[] | LatencyBucket[], bars: Bar[]) {
  const counts = new Array<number>(bars.length).fill(0);
  if (!bars.length) return { counts, total: 0 };
  const find = (v: number) => {
    let lo = 0;
    let hi = bars.length - 1;
    while (lo < hi) {
      const mid = (lo + hi + 1) >> 1;
      if (bars[mid].start <= v) lo = mid;
      else hi = mid - 1;
    }
    return lo;
  };
  let total = 0;
  for (const item of compare as (number | LatencyBucket)[]) {
    if (typeof item === "number") {
      if (!Number.isFinite(item)) continue;
      counts[find(item)] += 1;
      total += 1;
    } else if (Number.isFinite(item.count)) {
      counts[find((item.start + item.end) / 2)] += item.count;
      total += item.count;
    }
  }
  return { counts, total };
}

/* ------------------------------------------------------------------------ */
/* Hooks                                                                     */
/* ------------------------------------------------------------------------ */

function useReducedMotion() {
  return React.useSyncExternalStore(
    (onChange) => {
      const query = window.matchMedia("(prefers-reduced-motion: reduce)");
      query.addEventListener("change", onChange);
      return () => query.removeEventListener("change", onChange);
    },
    () => window.matchMedia("(prefers-reduced-motion: reduce)").matches,
    () => false,
  );
}

function useControllable<T>(
  value: T | undefined,
  defaultValue: T,
  onChange?: (value: T) => void,
) {
  const [inner, setInner] = React.useState(defaultValue);
  const controlled = value !== undefined;
  const set = React.useCallback(
    (next: T) => {
      if (!controlled) setInner(next);
      onChange?.(next);
    },
    [controlled, onChange],
  );
  return [controlled ? value : inner, set] as const;
}

const focusRing =
  "outline-none focus-visible:ring-2 focus-visible:ring-ring/50";
const percentileName = (p: number) => `p${tidy(p)}`;

/* ------------------------------------------------------------------------ */
/* LatencyHistogram                                                          */
/* ------------------------------------------------------------------------ */

/**
 * A latency distribution: bucketed requests with percentile markers, an SLO tail,
 * an optional comparison, and brushing to measure any range.
 */
export function LatencyHistogram({
  values,
  buckets,
  compare,
  compareLabel = "Previous",
  seriesLabel = "Current",
  compareStyle = "step",
  percentiles = [50, 90, 95, 99],
  threshold,
  thresholdLabel = "SLO",
  scale: scaleProp,
  defaultScale = "linear",
  onScaleChange,
  showScaleToggle = true,
  range: rangeProp,
  defaultRange = null,
  onRangeChange,
  title,
  description,
  actions,
  unit = "ms",
  valueFormatter,
  bucketCount = 40,
  domain,
  height,
  colors: colorsProp,
  renderTooltip,
  showSummary = true,
  className,
  ...props
}: LatencyHistogramProps) {
  const id = React.useId();
  const reduced = useReducedMotion();
  const format = React.useMemo(
    () => valueFormatter ?? makeFormatter(unit),
    [valueFormatter, unit],
  );
  const formatTick = React.useMemo(
    () => valueFormatter ?? makeTickFormatter(unit),
    [valueFormatter, unit],
  );
  const colors: LatencyHistogramColors = {
    bar: "var(--color-chart-1)",
    compare: "var(--color-muted-foreground)",
    threshold: "var(--color-destructive)",
    marker: "var(--color-foreground)",
    selection: "var(--color-primary)",
    ...colorsProp,
  };
  const [scale, setScale] = useControllable(
    scaleProp,
    defaultScale,
    onScaleChange,
  );
  const [range, setRange] = useControllable<LatencyRange | null>(
    rangeProp,
    defaultRange,
    onRangeChange,
  );
  const hasThreshold = threshold != null && Number.isFinite(threshold);

  const dist = React.useMemo(
    () => distributionOf(values, buckets),
    [values, buckets],
  );
  const sortedPercentiles = React.useMemo(
    () =>
      [...new Set(percentiles.filter((p) => p > 0 && p < 100))].sort(
        (a, b) => a - b,
      ),
    [percentiles],
  );
  const empty = dist.total === 0;
  const marks = React.useMemo(
    () =>
      dist.total === 0
        ? []
        : sortedPercentiles.map((p) => ({ p, value: quantile(dist, p / 100) })),
    [dist, sortedPercentiles],
  );

  // Linear charts end just past the slow tail (and the SLO); the rest lands in an overflow bar.
  const reach = Math.max(
    quantile(dist, 0.995),
    (marks[marks.length - 1]?.value ?? 0) * 1.04,
    hasThreshold ? threshold! * 1.12 : 0,
  );
  const layout = React.useMemo(
    () => layoutOf(dist, scale, bucketCount, reach, domain),
    [dist, scale, bucketCount, reach, domain],
  );
  const { bars, pos, inv } = layout;

  const comparison = React.useMemo(() => {
    if (!compare?.length) return null;
    const { counts, total } = binCompare(compare, bars);
    const percentilesOf = (() => {
      if (typeof compare[0] === "number") {
        const d = distributionOf(compare as number[]);
        return sortedPercentiles.map((p) => quantile(d, p / 100));
      }
      const d = distributionOf(undefined, compare as LatencyBucket[]);
      return sortedPercentiles.map((p) => quantile(d, p / 100));
    })();
    const factor = total ? dist.total / total : 0;
    return {
      counts,
      total,
      scaled: counts.map((c) => c * factor),
      percentiles: percentilesOf,
    };
  }, [compare, bars, dist.total, sortedPercentiles]);

  const maxCount = Math.max(
    1,
    ...bars.map((b) => b.count),
    ...(comparison?.scaled ?? [0]),
  );
  // The tallest bar fills the plot; gridlines sit at round counts below it.
  const yMax = maxCount * 1.06;
  const yStep = niceStep(maxCount / 3.2);
  const yTicks = Array.from(
    { length: Math.floor(yMax / yStep + 1e-9) + 1 },
    (_, i) => tidy(i * yStep),
  );

  const over = hasThreshold ? countAbove(dist, threshold!) : 0;
  const overShare = dist.total ? over / dist.total : 0;
  const thresholdX = hasThreshold ? pos(threshold!) : 1;

  const cumulative = React.useMemo(() => {
    let running = 0;
    return bars.map((b) => (running += b.count) / (dist.total || 1));
  }, [bars, dist.total]);

  const bucketAt = (index: number): LatencyHistogramBucket => {
    const b = bars[index];
    return {
      index,
      start: b.start,
      end: b.end,
      count: b.count,
      share: dist.total ? b.count / dist.total : 0,
      cumulative: cumulative[index] ?? 0,
      compare: comparison ? comparison.counts[index] : undefined,
      compareShare: comparison?.total
        ? comparison.counts[index] / comparison.total
        : undefined,
      overflow: b.overflow,
      overThreshold: hasThreshold && b.start >= threshold!,
    };
  };

  /* -------------------------------------------------------------- layout */

  const plotRef = React.useRef<HTMLDivElement>(null);
  const [width, setWidth] = React.useState(0);
  React.useLayoutEffect(() => {
    const el = plotRef.current;
    if (!el) return;
    const measure = () => setWidth(el.clientWidth);
    measure();
    const observer = new ResizeObserver(measure);
    observer.observe(el);
    return () => observer.disconnect();
  }, []);
  const W = width || 560;

  // Percentile chips stack into lanes only when they would collide.
  // With the summary on show, crowded chips drop their values, which the summary repeats.
  const chips = React.useMemo(() => {
    const place = (withValue: boolean) => {
      const lanes: number[] = [];
      return marks.map((mark) => {
        const text = withValue
          ? `${percentileName(mark.p)} ${format(mark.value)}`
          : percentileName(mark.p);
        const w = text.length * 6.1 + 14;
        const x = pos(mark.value) * W;
        const left = Math.min(Math.max(0, x - w / 2), Math.max(0, W - w));
        let lane = lanes.findIndex((right) => right + 4 <= left);
        if (lane < 0) lane = lanes.push(0) - 1;
        lanes[lane] = left + w;
        return { ...mark, x, left, lane, w, withValue };
      });
    };
    const full = place(true);
    if (!showSummary || full.every((chip) => chip.lane === 0)) return full;
    return place(false);
  }, [marks, pos, W, format, showSummary]);
  const laneCount = Math.max(1, ...chips.map((chip) => chip.lane + 1));
  const chipTop = laneCount * 20 + 6;
  // Without a fixed height the plot follows the card width, shorter on narrow cards.
  const H = Math.max(
    80,
    height ?? Math.round(Math.min(220, Math.max(140, W * 0.34))),
  );
  const barsHeight = H - chipTop;

  const xTicks = React.useMemo(() => {
    const ticks: number[] = [];
    if (empty) return ticks;
    if (scale === "log" || dist.buckets) {
      if (scale === "log") {
        const lo = layout.lo;
        const hi = layout.hi;
        const candidates: number[] = [];
        for (
          let e = Math.floor(Math.log10(lo));
          e <= Math.ceil(Math.log10(hi));
          e++
        )
          for (const m of [1, 2, 5]) {
            const v = tidy(m * 10 ** e);
            if (v >= lo * 0.999 && v <= hi * 1.001) candidates.push(v);
          }
        // Thin out 2s and then 5s until labels have room.
        for (const keep of [[1, 2, 5], [1, 5], [1]]) {
          const list = candidates.filter((v) =>
            keep.includes(
              Math.round(v / 10 ** Math.floor(Math.log10(v) + 1e-9)),
            ),
          );
          let ok = true;
          for (let i = 1; i < list.length; i++)
            if ((pos(list[i]) - pos(list[i - 1])) * W < 44) ok = false;
          if (ok || keep.length === 1) return list;
        }
      }
    }
    const lo = layout.lo;
    const hi = layout.hi;
    const step = niceStep((hi - lo) / Math.max(2, Math.floor(W / 76)));
    for (
      let v = Math.ceil(lo / step - 1e-9) * step;
      v <= hi + step * 1e-6;
      v += step
    )
      ticks.push(tidy(v));
    return ticks;
  }, [scale, dist.buckets, layout, pos, W, empty]);

  /* ----------------------------------------------------------- animation */

  // Bars grow in on mount and whenever the bucket layout changes; data updates tween.
  // Keyed on scale and bar count only, so live data with a drifting tail tweens instead of regrowing.
  const structure = `${scale}:${bars.length}`;
  const [grown, setGrown] = React.useState<string | null>(null);
  const [intro, setIntro] = React.useState(true);
  React.useEffect(() => {
    if (reduced) {
      setGrown(structure);
      setIntro(false);
      return;
    }
    setIntro(true);
    let frame = requestAnimationFrame(() => {
      frame = requestAnimationFrame(() => setGrown(structure));
    });
    const timer = window.setTimeout(
      () => setIntro(false),
      900 + bars.length * 9,
    );
    return () => {
      cancelAnimationFrame(frame);
      window.clearTimeout(timer);
    };
  }, [structure, reduced, bars.length]);
  const isGrown = grown === structure;

  /* --------------------------------------------------------- interaction */

  const [hover, setHover] = React.useState<number | null>(null);
  const [active, setActive] = React.useState<number | null>(null);
  const [brush, setBrush] = React.useState<LatencyRange | null>(null);
  const drag = React.useRef<{
    x: number;
    value: number;
    moved: boolean;
  } | null>(null);
  const anchor = React.useRef<number | null>(null);

  const xToFraction = (clientX: number) => {
    const rect = plotRef.current!.getBoundingClientRect();
    return Math.min(1, Math.max(0, (clientX - rect.left) / (rect.width || 1)));
  };
  const barAt = (x: number) => {
    for (let i = 0; i < bars.length; i++)
      if (x >= bars[i].x0 && x <= bars[i].x1) return i;
    // In a gap: the nearest bar.
    let best = -1;
    let distance = Infinity;
    bars.forEach((b, i) => {
      const dd = Math.min(Math.abs(x - b.x0), Math.abs(x - b.x1));
      if (dd < distance) {
        distance = dd;
        best = i;
      }
    });
    return best < 0 ? null : best;
  };

  const clampRange = (a: number, b: number): LatencyRange => [
    Math.min(a, b),
    Math.max(a, b),
  ];

  const onPointerDown = (event: React.PointerEvent<HTMLDivElement>) => {
    if (event.button !== 0 || !bars.length) return;
    const x = xToFraction(event.clientX);
    drag.current = { x: event.clientX, value: inv(x), moved: false };
    event.currentTarget.setPointerCapture(event.pointerId);
  };
  const onPointerMove = (event: React.PointerEvent<HTMLDivElement>) => {
    if (!bars.length) return;
    const x = xToFraction(event.clientX);
    const d = drag.current;
    if (d) {
      if (!d.moved && Math.abs(event.clientX - d.x) > 3) d.moved = true;
      if (d.moved) {
        setBrush(clampRange(d.value, inv(x)));
        setHover(null);
        return;
      }
    }
    setHover(barAt(x));
  };
  const onPointerUp = (event: React.PointerEvent<HTMLDivElement>) => {
    const d = drag.current;
    drag.current = null;
    if (!d) return;
    if (d.moved) {
      const next = clampRange(d.value, inv(xToFraction(event.clientX)));
      setBrush(null);
      setRange(next[1] - next[0] > 0 ? next : null);
    } else if (range) setRange(null);
  };

  const onKeyDown = (event: React.KeyboardEvent<HTMLDivElement>) => {
    if (!bars.length) return;
    const current = active ?? -1;
    const step = (delta: number) =>
      Math.min(
        bars.length - 1,
        Math.max(
          0,
          current < 0 ? (delta > 0 ? 0 : bars.length - 1) : current + delta,
        ),
      );
    let next: number | null = null;
    if (event.key === "ArrowRight") next = step(1);
    else if (event.key === "ArrowLeft") next = step(-1);
    else if (event.key === "Home") next = 0;
    else if (event.key === "End") next = bars.length - 1;
    else if (event.key === "Enter" && current >= 0) {
      setRange([bars[current].start, bars[current].end]);
      event.preventDefault();
      return;
    } else if (event.key === "Escape") {
      if (range) setRange(null);
      else setActive(null);
      anchor.current = null;
      event.preventDefault();
      return;
    }
    if (next == null) return;
    event.preventDefault();
    if (event.shiftKey) {
      if (anchor.current == null) anchor.current = current < 0 ? next : current;
      const a = Math.min(anchor.current, next);
      const b = Math.max(anchor.current, next);
      setRange([bars[a].start, bars[b].end]);
    } else anchor.current = null;
    setActive(next);
  };

  const shownRange = brush ?? range;
  const rangeCount = shownRange
    ? countBetween(dist, shownRange[0], shownRange[1])
    : 0;
  const rangeShare = dist.total ? rangeCount / dist.total : 0;
  const focusIndex = hover ?? active;
  const focusBucket =
    focusIndex != null && bars[focusIndex] ? bucketAt(focusIndex) : null;

  /* -------------------------------------------------------------- render */

  const describeBucket = (b: LatencyHistogramBucket) =>
    `${b.overflow ? `${format(b.start)} and above` : `${format(b.start)} to ${format(b.end)}`}: ${whole.format(Math.round(b.count))} requests, ${percentLabel(b.share)}`;
  const summaryText = [
    `${whole.format(Math.round(dist.total))} requests.`,
    marks
      .map((mark) => `${percentileName(mark.p)} ${format(mark.value)}`)
      .join(", ") + ".",
    hasThreshold
      ? `${percentLabel(overShare)} over the ${thresholdLabel} of ${format(threshold!)}.`
      : "",
  ]
    .filter(Boolean)
    .join(" ");
  const hasHeader =
    title != null || description != null || actions != null || showScaleToggle;
  const transition = intro
    ? "transform 760ms cubic-bezier(.16,1,.3,1)"
    : "transform 520ms cubic-bezier(.16,1,.3,1)";
  const barFill = (color: string) =>
    `color-mix(in oklab, ${color} 72%, var(--color-card))`;

  // The comparison as one stepped path across the bars.
  const comparePath = React.useMemo(() => {
    if (!comparison || compareStyle !== "step") return null;
    let path = "";
    let previousEnd = -1;
    bars.forEach((b, i) => {
      const y = 100 - (comparison.scaled[i] / yMax) * 100;
      const x0 = b.x0 * 1000;
      const x1 = b.x1 * 1000;
      if (Math.abs(x0 - previousEnd) > 0.5)
        path += `${path ? "V100" : ""}M${x0.toFixed(2)} 100`;
      path += `V${y.toFixed(2)}H${x1.toFixed(2)}`;
      previousEnd = x1;
    });
    return path + "V100";
  }, [comparison, compareStyle, bars, yMax]);

  return (
    <div
      data-slot="latency-histogram"
      data-scale={scale}
      data-brushing={brush ? true : undefined}
      className={cn(
        "@container/histogram flex min-w-0 flex-col rounded-xl border bg-card text-card-foreground shadow-xs",
        className,
      )}
      {...props}
    >
      {hasHeader && (
        <div className="flex items-start gap-3 px-4 pt-3.5">
          <div className="min-w-0 flex-1 space-y-1">
            {title != null && (
              <h3 className="truncate text-sm leading-6 font-semibold tracking-tight">
                {title}
              </h3>
            )}
            {description != null && (
              <p
                id={`${id}-description`}
                className="text-xs text-muted-foreground"
              >
                {description}
              </p>
            )}
          </div>
          <div className="flex shrink-0 items-center gap-2">
            {actions}
            {showScaleToggle && (
              <div
                role="group"
                aria-label="X axis scale"
                data-slot="histogram-scale-toggle"
                className="inline-flex h-7 items-center rounded-md border bg-muted/40 p-0.5"
              >
                {(["linear", "log"] as const).map((option) => (
                  <button
                    key={option}
                    type="button"
                    aria-pressed={scale === option}
                    onClick={() => setScale(option)}
                    className={cn(
                      "h-full rounded-[5px] px-2 text-xs font-medium text-muted-foreground transition-colors hover:text-foreground aria-pressed:bg-card aria-pressed:text-foreground aria-pressed:shadow-xs motion-reduce:transition-none",
                      focusRing,
                    )}
                  >
                    {option === "linear" ? "Linear" : "Log"}
                  </button>
                ))}
              </div>
            )}
          </div>
        </div>
      )}

      {showSummary && (marks.length > 0 || hasThreshold) && (
        // Narrow cards trade the stat grid for one line, so the distribution stays in view.
        <dl
          data-slot="histogram-summary-compact"
          className={cn(
            "mx-4 flex flex-wrap items-baseline gap-x-3 gap-y-1 text-xs @md/histogram:hidden",
            hasHeader ? "mt-1.5" : "mt-4",
          )}
        >
          {marks.map((mark, i) => {
            const previous = comparison?.percentiles[i];
            const delta = previous != null ? mark.value - previous : null;
            const hot = hasThreshold && mark.value > threshold!;
            return (
              <div key={mark.p} className="flex items-baseline gap-1">
                <dt className="font-mono text-[11px] text-muted-foreground">
                  {percentileName(mark.p)}
                </dt>
                <dd
                  className={cn(
                    "font-semibold tabular-nums",
                    hot && "text-destructive",
                  )}
                >
                  {format(mark.value)}
                </dd>
                {delta != null && Math.abs(delta) > 0 && (
                  <dd
                    className={cn(
                      "font-mono text-[10px] tabular-nums",
                      delta > 0
                        ? "text-destructive"
                        : "text-emerald-700 dark:text-emerald-400",
                    )}
                  >
                    {delta > 0 ? "▲" : "▼"}
                    {format(Math.abs(delta))}
                  </dd>
                )}
              </div>
            );
          })}
          {hasThreshold && (
            <div className="flex items-baseline gap-1">
              <dd
                className={cn(
                  "font-semibold tabular-nums",
                  over > 0
                    ? "text-destructive"
                    : "text-emerald-700 dark:text-emerald-400",
                )}
              >
                {percentLabel(overShare)}
              </dd>
              <dt className="text-[11px] text-muted-foreground">
                over {thresholdLabel}
              </dt>
            </div>
          )}
        </dl>
      )}

      {showSummary && (marks.length > 0 || hasThreshold) && (
        <dl
          data-slot="histogram-summary"
          className={cn(
            "mx-4 hidden overflow-hidden rounded-lg bg-muted/50 @md/histogram:grid dark:bg-muted/30",
            hasHeader ? "mt-3" : "mt-4",
          )}
          style={{
            gridTemplateColumns: `repeat(${marks.length + (hasThreshold ? 1 : 0)}, minmax(0, 1fr))`,
          }}
        >
          {marks.map((mark, i) => {
            const previous = comparison?.percentiles[i];
            const delta = previous != null ? mark.value - previous : null;
            const hot = hasThreshold && mark.value > threshold!;
            return (
              <div
                key={mark.p}
                className="min-w-0 border-s border-border/60 px-2 py-1.5 first:border-s-0 @sm/histogram:px-2.5 @md/histogram:px-3 @md/histogram:py-2"
              >
                <dt className="font-mono text-[11px] leading-4 text-muted-foreground">
                  {percentileName(mark.p)}
                </dt>
                <dd
                  className={cn(
                    "truncate text-sm leading-6 font-semibold tracking-tight tabular-nums @sm/histogram:text-base @md/histogram:text-lg",
                    hot && "text-destructive",
                  )}
                >
                  {format(mark.value)}
                </dd>
                {delta != null && Math.abs(delta) > 0 && (
                  <dd
                    className={cn(
                      "truncate font-mono text-[11px] leading-4 whitespace-nowrap tabular-nums",
                      delta > 0
                        ? "text-destructive"
                        : "text-emerald-700 dark:text-emerald-400",
                    )}
                    title={`${compareLabel}: ${format(previous!)}`}
                  >
                    {delta > 0 ? "▲" : "▼"} {format(Math.abs(delta))}
                  </dd>
                )}
              </div>
            );
          })}
          {hasThreshold && (
            <div className="min-w-0 border-s border-border/60 px-2 py-1.5 first:border-s-0 @sm/histogram:px-2.5 @md/histogram:px-3 @md/histogram:py-2">
              <dt className="truncate text-[11px] leading-4 text-muted-foreground">
                Over {thresholdLabel}
              </dt>
              <dd
                className={cn(
                  "truncate text-sm leading-6 font-semibold tracking-tight tabular-nums @sm/histogram:text-base @md/histogram:text-lg",
                  over > 0
                    ? "text-destructive"
                    : "text-emerald-700 dark:text-emerald-400",
                )}
              >
                {percentLabel(overShare)}
              </dd>
              <dd className="truncate font-mono text-[11px] leading-4 text-muted-foreground tabular-nums">
                {whole.format(Math.round(over))}
                <span className="hidden @sm/histogram:inline">
                  {" "}
                  of {compact.format(dist.total).replace("K", "k")}
                </span>
              </dd>
            </div>
          )}
        </dl>
      )}

      <div className="mt-3 flex px-4 @md/histogram:mt-4">
        <div className="min-w-0 flex-1">
          <div
            ref={plotRef}
            data-slot="histogram-plot"
            role="group"
            aria-roledescription="histogram"
            aria-label={`${typeof title === "string" ? `${title}. ` : ""}${summaryText} Use the arrow keys to read buckets, Shift to select a range.`}
            aria-describedby={
              description != null ? `${id}-description` : undefined
            }
            tabIndex={0}
            onPointerDown={onPointerDown}
            onPointerMove={onPointerMove}
            onPointerUp={onPointerUp}
            onPointerCancel={() => {
              drag.current = null;
              setBrush(null);
            }}
            onPointerLeave={() => {
              if (!drag.current) setHover(null);
            }}
            onKeyDown={onKeyDown}
            onBlur={() => setActive(null)}
            className={cn(
              "relative cursor-crosshair touch-pan-y rounded-sm select-none",
              "outline-none focus-visible:ring-2 focus-visible:ring-ring/50 focus-visible:ring-offset-4 focus-visible:ring-offset-card",
            )}
            style={{ height: H }}
          >
            {empty && (
              <p className="absolute inset-0 grid place-items-center text-xs text-muted-foreground">
                No requests to show.
              </p>
            )}

            {/* Value grid */}
            <div
              aria-hidden="true"
              className="pointer-events-none absolute inset-x-0 bottom-0"
              style={{ top: chipTop }}
            >
              {yTicks.map((tick) => (
                <span
                  key={tick}
                  className={cn(
                    "absolute inset-x-0 h-px",
                    tick === 0 ? "bg-border" : "bg-border/55",
                  )}
                  style={{ bottom: `${(tick / yMax) * 100}%` }}
                />
              ))}
            </div>

            {/* SLO tail */}
            {hasThreshold && thresholdX < 1 && (
              <div
                aria-hidden="true"
                data-slot="histogram-threshold-region"
                className="pointer-events-none absolute inset-y-0 right-0"
                style={{
                  left: `${thresholdX * 100}%`,
                  background: `linear-gradient(to bottom, color-mix(in oklab, ${colors.threshold} 9%, transparent), color-mix(in oklab, ${colors.threshold} 3%, transparent)), repeating-linear-gradient(-45deg, color-mix(in oklab, ${colors.threshold} 9%, transparent) 0 1px, transparent 1px 6px)`,
                }}
              />
            )}

            {/* Bars */}
            <div
              aria-hidden="true"
              className="pointer-events-none absolute inset-x-0 bottom-0"
              style={{ top: chipTop }}
            >
              {comparison &&
                compareStyle === "outline" &&
                bars.map((b, i) => (
                  <span
                    key={`c-${structure}-${i}`}
                    className="absolute bottom-0 origin-bottom rounded-t-[2px] border border-b-0 border-dashed"
                    style={{
                      left: `calc(${b.x0 * 100}% + 1px)`,
                      width: `calc(${(b.x1 - b.x0) * 100}% - 2px)`,
                      height: `${(comparison.scaled[i] / yMax) * 100}%`,
                      borderColor: `color-mix(in oklab, ${colors.compare} 70%, transparent)`,
                      transform: `scaleY(${isGrown ? 1 : 0})`,
                      transition: reduced ? undefined : transition,
                    }}
                  />
                ))}
              {bars.map((b, i) => {
                const h = b.count / yMax;
                const inRange = shownRange
                  ? b.end > shownRange[0] && b.start < shownRange[1]
                  : true;
                const dim =
                  (focusIndex != null && focusIndex !== i) || !inRange;
                const split =
                  hasThreshold && b.start < threshold! && b.end > threshold!;
                const hot = hasThreshold && b.start >= threshold!;
                const color = hot ? colors.threshold : colors.bar;
                const cut = split
                  ? ((thresholdX - b.x0) / (b.x1 - b.x0)) * 100
                  : 0;
                const fill = split
                  ? `linear-gradient(to right, ${barFill(colors.bar)} ${cut}%, ${barFill(colors.threshold)} ${cut}%)`
                  : barFill(color);
                const cap = split
                  ? `linear-gradient(to right, ${colors.bar} ${cut}%, ${colors.threshold} ${cut}%)`
                  : color;
                return (
                  <span
                    key={`${structure}-${i}`}
                    data-slot="histogram-bar"
                    data-index={i}
                    data-over={hot || undefined}
                    data-overflow={b.overflow || undefined}
                    className={cn(
                      "absolute inset-y-0 transition-opacity duration-200 motion-reduce:transition-none",
                      dim &&
                        (shownRange && !inRange ? "opacity-30" : "opacity-55"),
                    )}
                    style={{
                      left: `${b.x0 * 100}%`,
                      width: `${(b.x1 - b.x0) * 100}%`,
                    }}
                  >
                    <span
                      className="absolute inset-x-px bottom-0 h-full origin-bottom @lg/histogram:inset-x-[1.5px]"
                      style={{
                        transform: `scaleY(${isGrown ? h : 0})`,
                        transition: reduced ? undefined : transition,
                        transitionDelay:
                          intro && !reduced ? `${i * 9}ms` : undefined,
                      }}
                    >
                      <span
                        className={cn(
                          "absolute inset-0 rounded-t-[2px]",
                          b.overflow &&
                            "[mask-image:repeating-linear-gradient(-45deg,#000_0_3px,rgb(0_0_0/0.55)_3px_5px)]",
                        )}
                        style={{ background: fill }}
                      />
                    </span>
                    {/* The cap is drawn unscaled so it stays a crisp line at any height. */}
                    {b.count > 0 && (
                      <span
                        className="absolute inset-x-px h-[1.5px] rounded-full @lg/histogram:inset-x-[1.5px]"
                        style={{
                          bottom: `calc(${(isGrown ? h : 0) * 100}% - 1px)`,
                          background: cap,
                          transition: reduced
                            ? undefined
                            : intro
                              ? "bottom 760ms cubic-bezier(.16,1,.3,1)"
                              : "bottom 520ms cubic-bezier(.16,1,.3,1)",
                          transitionDelay:
                            intro && !reduced ? `${i * 9}ms` : undefined,
                        }}
                      />
                    )}
                  </span>
                );
              })}
              {comparePath && (
                <svg
                  data-slot="histogram-compare"
                  className="absolute inset-0 size-full origin-bottom overflow-visible"
                  viewBox="0 0 1000 100"
                  preserveAspectRatio="none"
                  style={{
                    transform: `scaleY(${isGrown ? 1 : 0})`,
                    transition: reduced ? undefined : transition,
                  }}
                >
                  <path
                    d={comparePath}
                    fill="none"
                    stroke={colors.compare}
                    strokeWidth={1.5}
                    strokeDasharray="4 3"
                    strokeLinejoin="round"
                    vectorEffect="non-scaling-stroke"
                    opacity={0.85}
                  />
                </svg>
              )}
            </div>

            {/* Selection */}
            {shownRange && (
              <div
                aria-hidden="true"
                data-slot="histogram-selection"
                className="pointer-events-none absolute inset-y-0"
                style={{
                  left: `${pos(shownRange[0]) * 100}%`,
                  width: `${Math.max(0, pos(shownRange[1]) - pos(shownRange[0])) * 100}%`,
                  background: `color-mix(in oklab, ${colors.selection} 9%, transparent)`,
                  boxShadow: `inset 1.5px 0 0 ${colors.selection}, inset -1.5px 0 0 ${colors.selection}`,
                }}
              >
                <span
                  className="absolute top-1/2 -left-[3px] h-5 w-1.5 -translate-y-1/2 rounded-full border border-card"
                  style={{ background: colors.selection }}
                />
                <span
                  className="absolute top-1/2 -right-[3px] h-5 w-1.5 -translate-y-1/2 rounded-full border border-card"
                  style={{ background: colors.selection }}
                />
              </div>
            )}

            {/* Threshold line */}
            {hasThreshold && thresholdX < 1 && (
              <div
                aria-hidden="true"
                data-slot="histogram-threshold"
                className="pointer-events-none absolute bottom-0"
                style={{ left: `${thresholdX * 100}%`, top: chipTop - 2 }}
              >
                <span
                  className="absolute inset-y-0 w-0 border-l-[1.5px] border-dashed"
                  style={{ borderColor: colors.threshold }}
                />
                <span
                  className="absolute top-1 left-1 rounded-sm bg-card/85 px-1 font-mono text-[10px] leading-4 font-medium whitespace-nowrap"
                  style={{ color: colors.threshold }}
                >
                  {thresholdLabel} {format(threshold!)}
                </span>
              </div>
            )}

            {/* Percentile markers */}
            {chips.map((chip) => {
              const hot = hasThreshold && chip.value > threshold!;
              const color = hot ? colors.threshold : colors.marker;
              return (
                <div
                  key={chip.p}
                  data-slot="histogram-marker"
                  data-percentile={chip.p}
                  aria-hidden="true"
                  className="pointer-events-none"
                >
                  <span
                    className="absolute bottom-0 w-0 border-l border-dashed opacity-55"
                    style={{
                      left: chip.x,
                      top: chip.lane * 20 + 18,
                      borderColor: color,
                    }}
                  />
                  <span
                    className={cn(
                      "absolute flex h-[18px] items-center gap-1 rounded-[5px] border bg-card px-1.5 font-mono text-[10px] leading-none whitespace-nowrap shadow-xs tabular-nums",
                      intro &&
                        !reduced &&
                        "motion-safe:animate-[histogram-rise_.5s_.35s_cubic-bezier(.16,1,.3,1)_both]",
                    )}
                    style={{
                      left: chip.left,
                      top: chip.lane * 20,
                      borderColor: `color-mix(in oklab, ${color} 28%, var(--color-border))`,
                    }}
                  >
                    <span className="text-muted-foreground">
                      {percentileName(chip.p)}
                    </span>
                    {chip.withValue && (
                      <span className="font-semibold" style={{ color }}>
                        {format(chip.value)}
                      </span>
                    )}
                  </span>
                </div>
              );
            })}

            {/* Tooltip */}
            {focusBucket && !brush && (
              <div
                data-slot="histogram-tooltip"
                aria-hidden="true"
                className="pointer-events-none absolute z-10 min-w-36 rounded-lg border bg-popover px-2.5 py-2 text-xs text-popover-foreground shadow-md"
                style={{
                  top: chipTop + 4,
                  // Sit beside the bar, on the side with more room, so it never hides it.
                  ...(bars[focusBucket.index].x0 + bars[focusBucket.index].x1 <
                  1
                    ? { left: bars[focusBucket.index].x1 * W + 8 }
                    : { right: W - bars[focusBucket.index].x0 * W + 8 }),
                }}
              >
                {renderTooltip ? (
                  renderTooltip(focusBucket)
                ) : (
                  <>
                    <p className="font-mono text-[11px] text-muted-foreground tabular-nums">
                      {focusBucket.overflow
                        ? `≥ ${format(focusBucket.start)}`
                        : `${format(focusBucket.start)} – ${format(focusBucket.end)}`}
                    </p>
                    <p className="mt-0.5 flex items-baseline gap-1.5">
                      <span className="text-sm font-semibold tabular-nums">
                        {whole.format(Math.round(focusBucket.count))}
                      </span>
                      <span className="text-muted-foreground tabular-nums">
                        {percentLabel(focusBucket.share)}
                      </span>
                    </p>
                    <p className="mt-1 text-[11px] text-muted-foreground tabular-nums">
                      {percentLabel(focusBucket.cumulative)} at or faster
                    </p>
                    {focusBucket.compare != null && comparison && (
                      <p className="mt-1.5 flex items-center gap-1.5 border-t border-dashed pt-1.5 text-[11px] text-muted-foreground tabular-nums">
                        <span
                          aria-hidden="true"
                          className="w-3 border-t-[1.5px] border-dashed"
                          style={{ borderColor: colors.compare }}
                        />
                        {compareLabel}
                        <span className="ml-auto font-medium text-foreground">
                          {whole.format(Math.round(focusBucket.compare))}
                        </span>
                        <span>
                          {percentLabel(focusBucket.compareShare ?? 0)}
                        </span>
                      </p>
                    )}
                  </>
                )}
              </div>
            )}
          </div>

          {/* Latency axis */}
          <div
            aria-hidden="true"
            className="relative mt-1.5 h-4 font-mono text-[10px] leading-4 text-muted-foreground tabular-nums"
          >
            {xTicks.map((tick, i) => {
              const x = pos(tick);
              if (x > layout.pos(layout.hi) + 1e-6) return null;
              return (
                <span
                  key={tick}
                  className={cn(
                    "absolute whitespace-nowrap",
                    i === 0 && x < 0.02
                      ? ""
                      : x > 0.97
                        ? "-translate-x-full"
                        : "-translate-x-1/2",
                  )}
                  style={{ left: `${x * 100}%` }}
                >
                  {formatTick(tick)}
                </span>
              );
            })}
            {bars[bars.length - 1]?.overflow && (
              <span
                className="absolute -translate-x-1/2 whitespace-nowrap"
                style={{
                  left: `${((bars[bars.length - 1].x0 + 1) / 2) * 100}%`,
                }}
              >
                +
              </span>
            )}
          </div>
        </div>
        <div
          aria-hidden="true"
          className="relative ml-2 w-8 shrink-0"
          style={{ height: H }}
        >
          {yTicks.map((tick) => (
            <span
              key={tick}
              className="absolute right-0 translate-y-1/2 font-mono text-[10px] leading-none text-muted-foreground tabular-nums"
              style={{ bottom: `${(tick / yMax) * (barsHeight / H) * 100}%` }}
            >
              {tick === 0 ? "0" : compact.format(tick).replace("K", "k")}
            </span>
          ))}
        </div>
      </div>

      <div
        data-slot="histogram-footer"
        className="mt-3 flex min-h-11 flex-wrap items-center justify-between gap-x-4 gap-y-2 border-t px-4 py-2"
      >
        <div
          data-slot="histogram-status"
          className="flex min-w-0 flex-wrap items-center gap-x-2 gap-y-0.5 text-xs"
        >
          {shownRange ? (
            <>
              <span
                className="rounded-[4px] px-1.5 py-px font-mono text-[11px] tabular-nums"
                style={{
                  background: `color-mix(in oklab, ${colors.selection} 10%, transparent)`,
                  color: colors.selection,
                }}
              >
                {format(shownRange[0])} – {format(shownRange[1])}
              </span>
              <span className="font-semibold tabular-nums">
                {percentLabel(rangeShare)}
              </span>
              <span className="text-muted-foreground tabular-nums">
                {whole.format(Math.round(rangeCount))} of{" "}
                {whole.format(Math.round(dist.total))} requests
              </span>
              {!brush && (
                <button
                  type="button"
                  onClick={() => setRange(null)}
                  className={cn(
                    "inline-flex size-5 items-center justify-center rounded text-muted-foreground hover:bg-muted hover:text-foreground",
                    focusRing,
                  )}
                >
                  <X className="size-3.5" aria-hidden="true" />
                  <span className="sr-only">Clear selection</span>
                </button>
              )}
            </>
          ) : (
            <span className="text-muted-foreground tabular-nums">
              <span className="font-medium text-foreground">
                {whole.format(Math.round(dist.total))}
              </span>{" "}
              requests
              <span aria-hidden="true"> · </span>mean{" "}
              <span className="font-medium text-foreground">
                {format(dist.mean)}
              </span>
              <span className="hidden @md/histogram:inline">
                <span aria-hidden="true"> · </span>max{" "}
                <span className="font-medium text-foreground">
                  {format(dist.max)}
                </span>
              </span>
              <span className="hidden @lg/histogram:inline">
                {" "}
                · drag to measure a range
              </span>
            </span>
          )}
        </div>
        {comparison && (
          <div
            data-slot="histogram-legend"
            className="flex items-center gap-3 text-[11px] text-muted-foreground"
          >
            <span className="flex items-center gap-1.5">
              <span
                aria-hidden="true"
                className="size-2.5 rounded-[2px]"
                style={{
                  background: barFill(colors.bar),
                  boxShadow: `inset 0 1.5px 0 ${colors.bar}`,
                }}
              />
              {seriesLabel}
            </span>
            <span className="flex items-center gap-1.5">
              <span
                aria-hidden="true"
                className="w-3.5 border-t-[1.5px] border-dashed"
                style={{ borderColor: colors.compare }}
              />
              {compareLabel}
            </span>
          </div>
        )}
      </div>

      <div className="sr-only">
        <table>
          <caption>{summaryText}</caption>
          <thead>
            <tr>
              <th scope="col">Latency</th>
              <th scope="col">Requests</th>
              {comparison && <th scope="col">{compareLabel}</th>}
            </tr>
          </thead>
          <tbody>
            {bars.map((b, i) =>
              b.count > 0 || comparison?.counts[i] ? (
                <tr key={i}>
                  <th scope="row">
                    {b.overflow
                      ? `${format(b.start)} and above`
                      : `${format(b.start)} to ${format(b.end)}`}
                  </th>
                  <td>{whole.format(Math.round(b.count))}</td>
                  {comparison && (
                    <td>{whole.format(Math.round(comparison.counts[i]))}</td>
                  )}
                </tr>
              ) : null,
            )}
          </tbody>
        </table>
      </div>
      <p className="sr-only" aria-live="polite">
        {active != null && bars[active]
          ? describeBucket(bucketAt(active))
          : range
            ? `Selected ${format(range[0])} to ${format(range[1])}: ${percentLabel(dist.total ? countBetween(dist, range[0], range[1]) / dist.total : 0)} of requests.`
            : ""}
      </p>

      <style href="overtrue-latency-histogram" precedence="default">
        {`@keyframes histogram-rise{from{opacity:0;transform:translateY(4px)}to{opacity:1;transform:none}}`}
      </style>
    </div>
  );
}
```

### `src/registry/overtrue/trace-waterfall.tsx`

```tsx
"use client";

import * as React from "react";
import {
  IconAlertTriangleFilled as AlertTriangle,
  IconChevronRight as ChevronRight,
  IconFoldDown as FoldDown,
  IconFoldUp as FoldUp,
  IconRoute as Route,
  IconX as X,
  IconZoomReset as ZoomReset,
} from "@tabler/icons-react";

import { cn } from "@/lib/utils";

export type TraceSpanStatus = "ok" | "error";

export type TraceSpanAttributeValue = string | number | boolean;

export interface TraceSpan {
  id: string;
  /** The calling span. Spans without a known parent are drawn as roots. */
  parentId?: string | null;
  /** Operation name, e.g. "POST /api/checkout" or "SELECT orders". */
  name: string;
  /** Emitting service. Spans of one service share a color. */
  service: string;
  /** Milliseconds from the start of the trace. */
  start: number;
  /** Milliseconds. */
  duration: number;
  status?: TraceSpanStatus;
  attributes?: Record<string, TraceSpanAttributeValue>;
}

/** Everything derived about one span, passed to `renderDetail`. */
export interface TraceSpanInfo {
  span: TraceSpan;
  parent: TraceSpan | null;
  children: TraceSpan[];
  depth: number;
  /** All spans below this one, at any depth. */
  descendantCount: number;
  /** Time not covered by any child span, in milliseconds. */
  selfTime: number;
  /** Duration as a 0–1 share of the whole trace. */
  share: number;
  /** Whether the span is on the trace's critical path. */
  critical: boolean;
  /** The resolved service color. */
  color: string;
  /** Start and end of the whole trace, in milliseconds. */
  trace: { start: number; end: number; duration: number };
}

export type TraceTimeRange = [start: number, end: number];

export interface TraceWaterfallProps extends Omit<
  React.ComponentProps<"div">,
  "title" | "children"
> {
  spans: TraceSpan[];
  title?: React.ReactNode;
  description?: React.ReactNode;
  /** Controls placed at the top right, before the built-in tools. */
  actions?: React.ReactNode;
  /** Selected span. Pass `null` for none; leave undefined to let the component manage it. */
  selectedId?: string | null;
  defaultSelectedId?: string | null;
  onSelectedChange?: (id: string | null, span: TraceSpan | null) => void;
  /** Emphasise the longest blocking chain. Pass with `onHighlightCriticalPathChange` to control it. */
  highlightCriticalPath?: boolean;
  defaultHighlightCriticalPath?: boolean;
  onHighlightCriticalPathChange?: (highlight: boolean) => void;
  /** Spans that start collapsed. */
  defaultCollapsedIds?: string[];
  /** Colors by service name. Unlisted services take the chart palette in order of appearance. */
  serviceColors?: Record<string, string>;
  /** Formats every duration and offset except axis ticks. */
  durationFormatter?: (ms: number) => string;
  /** Replaces the attribute table in the detail panel. Compose `TraceSpanAttributes` to keep it. */
  renderDetail?: (span: TraceSpan, info: TraceSpanInfo) => React.ReactNode;
  /** Row height in pixels. Defaults to 28. */
  rowHeight?: number;
  /** Maximum height of the scrolling span list in pixels. Defaults to 360. */
  height?: number;
  /** Width of the span tree as a 0.2–0.7 share of the card. Drag the divider to change it. */
  treeWidth?: number;
  /** Show the whole-trace minimap above the list. Defaults to true. */
  showOverview?: boolean;
  /** Show the service legend, which doubles as a filter. Defaults to true. */
  showLegend?: boolean;
  /** Called when the visible time range changes, with `null` when zoom resets. */
  onZoomChange?: (range: TraceTimeRange | null) => void;
}

/* ------------------------------------------------------------------------ */
/* Formatting                                                                */
/* ------------------------------------------------------------------------ */

function formatDuration(ms: number) {
  if (!Number.isFinite(ms)) return "—";
  const a = Math.abs(ms);
  if (a === 0) return "0ms";
  if (a < 1) return `${Math.round(ms * 1000)}µs`;
  if (a < 10) return `${ms.toFixed(2)}ms`;
  if (a < 100) return `${ms.toFixed(1)}ms`;
  if (a < 1000) return `${Math.round(ms)}ms`;
  if (a < 10_000) return `${(ms / 1000).toFixed(2)}s`;
  if (a < 60_000) return `${(ms / 1000).toFixed(1)}s`;
  const minutes = Math.floor(ms / 60_000);
  return `${minutes}m ${Math.round((ms - minutes * 60_000) / 1000)}s`;
}

function formatPercent(share: number) {
  const pct = share * 100;
  if (pct > 0 && pct < 0.1) return "<0.1%";
  return `${pct >= 10 ? pct.toFixed(0) : pct.toFixed(1)}%`;
}

const tidy = (value: number) => +value.toPrecision(12);

function niceStep(span: number, count: number) {
  const raw = span / Math.max(1, count);
  const magnitude = 10 ** Math.floor(Math.log10(raw));
  const r = raw / magnitude;
  return (
    (r <= 1 ? 1 : r <= 2 ? 2 : r <= 2.5 ? 2.5 : r <= 5 ? 5 : 10) * magnitude
  );
}

/** Tick labels carry exactly the precision of the step, so neighbors never read alike. */
function tickLabel(value: number, step: number) {
  if (value === 0) return "0";
  if (step >= 1000 || (Math.abs(value) >= 1000 && step >= 100)) {
    const digits = Math.max(0, -Math.floor(Math.log10(step / 1000) + 1e-9));
    return `${(value / 1000).toFixed(Math.min(3, digits))}s`;
  }
  if (step < 1 && step < 0.01) return `${tidy(value * 1000)}µs`;
  const digits = Math.max(0, -Math.floor(Math.log10(step) + 1e-9));
  return `${value.toFixed(Math.min(3, digits))}ms`;
}

/* ------------------------------------------------------------------------ */
/* Model                                                                     */
/* ------------------------------------------------------------------------ */

interface TraceNode {
  span: TraceSpan;
  order: number;
  parent: TraceNode | null;
  children: TraceNode[];
  depth: number;
  end: number;
  self: number;
  descendants: number;
  critical: boolean;
}

interface TraceModel {
  nodes: Map<string, TraceNode>;
  roots: TraceNode[];
  /** Every node in tree order. */
  ordered: TraceNode[];
  start: number;
  end: number;
  duration: number;
  services: { name: string; count: number; errors: number }[];
  errors: number;
}

const PALETTE = [
  "var(--color-chart-1)",
  "var(--color-chart-2)",
  "var(--color-chart-3)",
  "var(--color-chart-4)",
  "var(--color-chart-5)",
  // Blends of the theme's own chart colors keep extra services on-palette.
  "color-mix(in oklab, var(--color-chart-1) 50%, var(--color-chart-2))",
  "color-mix(in oklab, var(--color-chart-2) 50%, var(--color-chart-3))",
  "color-mix(in oklab, var(--color-chart-4) 55%, var(--color-chart-5))",
];

const DESTRUCTIVE = "var(--color-destructive)";
const errorFill = `repeating-linear-gradient(-45deg, ${DESTRUCTIVE} 0 3px, color-mix(in oklab, ${DESTRUCTIVE} 58%, var(--color-card)) 3px 6px)`;

function buildModel(spans: TraceSpan[]): TraceModel {
  const nodes = new Map<string, TraceNode>();
  spans.forEach((span, order) => {
    if (nodes.has(span.id)) return;
    const start = Number.isFinite(span.start) ? span.start : 0;
    const duration = Number.isFinite(span.duration)
      ? Math.max(0, span.duration)
      : 0;
    nodes.set(span.id, {
      span,
      order,
      parent: null,
      children: [],
      depth: 0,
      end: start + duration,
      self: duration,
      descendants: 0,
      critical: false,
    });
  });

  const roots: TraceNode[] = [];
  for (const node of nodes.values()) {
    const parentId = node.span.parentId;
    const parent =
      parentId != null && parentId !== node.span.id
        ? nodes.get(parentId)
        : undefined;
    if (parent) {
      node.parent = parent;
      parent.children.push(node);
    } else roots.push(node);
  }

  const byStart = (a: TraceNode, b: TraceNode) =>
    a.span.start - b.span.start || a.order - b.order;
  const ordered: TraceNode[] = [];
  const visited = new Set<TraceNode>();
  const visit = (node: TraceNode, depth: number) => {
    visited.add(node);
    node.depth = depth;
    ordered.push(node);
    node.children = node.children
      .filter((child) => !visited.has(child))
      .sort(byStart);
    let descendants = 0;
    for (const child of node.children) {
      visit(child, depth + 1);
      descendants += 1 + child.descendants;
    }
    node.descendants = descendants;
    // Self time: the span's duration minus the union of its children's time inside it.
    const start = node.span.start;
    const intervals = node.children
      .map(
        (child) =>
          [
            Math.max(child.span.start, start),
            Math.min(child.end, node.end),
          ] as const,
      )
      .filter(([a, b]) => b > a)
      .sort((a, b) => a[0] - b[0]);
    let covered = 0;
    let cursor = -Infinity;
    for (const [a, b] of intervals) {
      if (b <= cursor) continue;
      covered += b - Math.max(a, cursor);
      cursor = b;
    }
    node.self = Math.max(0, node.end - start - covered);
  };
  roots.sort(byStart);
  for (const root of roots) visit(root, 0);
  // Spans caught in a parent cycle are never reached from a root; draw them as roots.
  for (const node of nodes.values())
    if (!visited.has(node)) {
      node.parent = null;
      roots.push(node);
      visit(node, 0);
    }

  let start = 0;
  let end = 0;
  let errors = 0;
  const services = new Map<
    string,
    { name: string; count: number; errors: number }
  >();
  for (const node of ordered) {
    start = Math.min(start, node.span.start);
    end = Math.max(end, node.end);
    const isError = node.span.status === "error";
    if (isError) errors += 1;
    const entry = services.get(node.span.service) ?? {
      name: node.span.service,
      count: 0,
      errors: 0,
    };
    entry.count += 1;
    if (isError) entry.errors += 1;
    services.set(node.span.service, entry);
  }

  // Critical path: from the longest root, walk back from each span's end through the
  // child that finished last, then whatever finished before that child started.
  const markCritical = (node: TraceNode) => {
    node.critical = true;
    let cursor = node.end + 1e-9;
    const byEnd = [...node.children].sort((a, b) => b.end - a.end);
    for (const child of byEnd) {
      if (child.end <= cursor && child.end > node.span.start) {
        markCritical(child);
        cursor = child.span.start + 1e-9;
      }
    }
  };
  const main = roots.reduce<TraceNode | null>(
    (best, root) =>
      !best || root.end - root.span.start > best.end - best.span.start
        ? root
        : best,
    null,
  );
  if (main) markCritical(main);

  return {
    nodes,
    roots,
    ordered,
    start,
    end,
    duration: end - start || 1,
    services: [...services.values()],
    errors,
  };
}

interface TraceRowModel {
  node: TraceNode;
  depth: number;
  /** For each ancestor column, whether a guide line continues through this row. */
  lines: boolean[];
  last: boolean;
  childCount: number;
  collapsed: boolean;
  hiddenCount: number;
  /** Descendants hidden by collapsing, drawn as a faint summary. */
  summary: TraceNode[];
  parentId: string | null;
  position: number;
  setSize: number;
}

function visibleChildren(
  children: TraceNode[],
  hidden: Set<string>,
): TraceNode[] {
  if (!hidden.size) return children;
  let lifted = false;
  const out: TraceNode[] = [];
  for (const child of children) {
    if (hidden.has(child.span.service)) {
      lifted = true;
      out.push(...visibleChildren(child.children, hidden));
    } else out.push(child);
  }
  return lifted
    ? out.sort((a, b) => a.span.start - b.span.start || a.order - b.order)
    : out;
}

function buildRows(
  model: TraceModel,
  collapsed: Set<string>,
  hidden: Set<string>,
) {
  const rows: TraceRowModel[] = [];
  const flat: TraceNode[] = [];
  const collect = (node: TraceNode, into: TraceNode[]) => {
    for (const child of visibleChildren(node.children, hidden)) {
      into.push(child);
      collect(child, into);
    }
  };
  const visit = (
    node: TraceNode,
    depth: number,
    lines: boolean[],
    last: boolean,
    parentId: string | null,
    position: number,
    setSize: number,
  ) => {
    const kids = visibleChildren(node.children, hidden);
    const isCollapsed = kids.length > 0 && collapsed.has(node.span.id);
    const summary: TraceNode[] = [];
    if (isCollapsed) collect(node, summary);
    rows.push({
      node,
      depth,
      lines,
      last,
      childCount: kids.length,
      collapsed: isCollapsed,
      hiddenCount: summary.length,
      summary: summary.slice(0, 60),
      parentId,
      position,
      setSize,
    });
    if (isCollapsed) return;
    const childLines = depth === 0 ? [] : [...lines, !last];
    kids.forEach((kid, i) =>
      visit(
        kid,
        depth + 1,
        childLines,
        i === kids.length - 1,
        node.span.id,
        i + 1,
        kids.length,
      ),
    );
  };
  const roots = visibleChildren(model.roots, hidden);
  roots.forEach((root, i) =>
    visit(root, 0, [], i === roots.length - 1, null, i + 1, roots.length),
  );
  // The overview ignores collapsing but follows the service filter.
  for (const root of roots) {
    flat.push(root);
    collect(root, flat);
  }
  return { rows, flat };
}

/* ------------------------------------------------------------------------ */
/* Hooks                                                                     */
/* ------------------------------------------------------------------------ */

function useReducedMotion() {
  return React.useSyncExternalStore(
    (onChange) => {
      const query = window.matchMedia("(prefers-reduced-motion: reduce)");
      query.addEventListener("change", onChange);
      return () => query.removeEventListener("change", onChange);
    },
    () => window.matchMedia("(prefers-reduced-motion: reduce)").matches,
    () => false,
  );
}

function useControllable<T>(
  value: T | undefined,
  defaultValue: T,
  onChange?: (value: T) => void,
) {
  const [inner, setInner] = React.useState(defaultValue);
  const controlled = value !== undefined;
  const current = controlled ? value : inner;
  const set = React.useCallback(
    (next: T) => {
      if (!controlled) setInner(next);
      onChange?.(next);
    },
    [controlled, onChange],
  );
  return [current, set] as const;
}

const focusRing =
  "outline-none focus-visible:ring-2 focus-visible:ring-ring/50";
const toolButton = cn(
  "inline-flex size-7 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-muted hover:text-foreground disabled:pointer-events-none disabled:opacity-40 aria-pressed:bg-muted aria-pressed:text-foreground motion-reduce:transition-none",
  focusRing,
);

/** Position inside the timeline column from the animated view variables. */
const at = (ms: number) =>
  `calc((${tidy(ms)} - var(--trace-v0)) / var(--trace-vs) * 100%)`;
const span = (ms: number) => `calc(${tidy(ms)} / var(--trace-vs) * 100%)`;

const INDENT = 12;
const PAD = 10;

/* ------------------------------------------------------------------------ */
/* Row                                                                       */
/* ------------------------------------------------------------------------ */

interface TraceRowProps {
  row: TraceRowModel;
  index: number;
  rowHeight: number;
  color: string;
  colorOf: (service: string) => string;
  selected: boolean;
  tabStop: boolean;
  emphasis: "critical" | "dim" | "normal";
  labelSide: "after" | "before" | "inside";
  /** The span lies outside the zoomed time range. */
  outside: boolean;
  format: (ms: number) => string;
  onToggle: (id: string) => void;
  onActivate: (id: string) => void;
  onFocusRow: (id: string) => void;
}

const TraceRow = React.memo(function TraceRow({
  row,
  index,
  rowHeight,
  color,
  colorOf,
  selected,
  tabStop,
  emphasis,
  labelSide,
  outside,
  format,
  onToggle,
  onActivate,
  onFocusRow,
}: TraceRowProps) {
  const { node, depth } = row;
  const { span: s } = node;
  const isError = s.status === "error";
  const barHeight = Math.max(6, Math.round(rowHeight * 0.43));
  const elbowX = (column: number) => PAD + column * INDENT + 7;
  const duration = format(s.duration);

  return (
    <div
      role="treeitem"
      data-slot="trace-row"
      data-span-id={s.id}
      data-selected={selected || undefined}
      data-outside={outside || undefined}
      data-error={isError || undefined}
      data-critical={node.critical || undefined}
      aria-level={depth + 1}
      aria-setsize={row.setSize}
      aria-posinset={row.position}
      aria-expanded={row.childCount > 0 ? !row.collapsed : undefined}
      aria-selected={selected}
      aria-label={`${s.name}, ${s.service}, ${duration}${isError ? ", error" : ""}${row.collapsed ? `, ${row.hiddenCount} hidden` : ""}`}
      tabIndex={tabStop ? 0 : -1}
      onFocus={() => onFocusRow(s.id)}
      onClick={() => onActivate(s.id)}
      className={cn(
        "group/row absolute inset-x-0 grid cursor-default grid-cols-(--trace-cols) transition-colors duration-100 outline-none motion-reduce:transition-none",
        "hover:bg-muted/55 focus-visible:z-[1] focus-visible:ring-2 focus-visible:ring-ring/50 focus-visible:ring-inset",
        selected &&
          "bg-primary/[0.07] shadow-[inset_2px_0_0_var(--color-primary)] hover:bg-primary/10",
      )}
      style={{ top: index * rowHeight, height: rowHeight }}
    >
      <div
        data-slot="trace-row-label"
        className="relative flex min-w-0 items-center gap-1.5 border-r pr-2.5"
        style={{ paddingLeft: PAD + depth * INDENT }}
      >
        {depth > 0 && (
          <span
            aria-hidden="true"
            className="pointer-events-none absolute inset-y-0 left-0"
          >
            {row.lines.map((continues, column) =>
              continues ? (
                <span
                  key={column}
                  className="absolute inset-y-0 w-px bg-border"
                  style={{ left: elbowX(column) }}
                />
              ) : null,
            )}
            <span
              className="absolute top-0 w-px bg-border"
              style={{
                left: elbowX(depth - 1),
                height: row.last ? "50%" : "100%",
              }}
            />
            <span
              className="absolute top-1/2 h-px bg-border"
              style={{
                left: elbowX(depth - 1),
                width: row.childCount > 0 ? 6 : 12,
              }}
            />
          </span>
        )}
        {row.childCount > 0 ? (
          // Not a tab stop: the row itself takes Left and Right to collapse and expand.
          <span
            aria-hidden="true"
            data-slot="trace-row-toggle"
            onClick={(event) => {
              event.stopPropagation();
              onToggle(s.id);
            }}
            className="relative -mx-px inline-flex size-3.5 shrink-0 cursor-pointer items-center justify-center rounded-[3px] text-muted-foreground transition-colors hover:bg-muted hover:text-foreground"
          >
            <ChevronRight
              className={cn(
                "size-3 transition-transform duration-150 motion-reduce:transition-none",
                !row.collapsed && "rotate-90",
              )}
              strokeWidth={2.25}
            />
          </span>
        ) : (
          <span aria-hidden="true" className="w-3.5 shrink-0" />
        )}
        <span
          aria-hidden="true"
          className="relative size-2 shrink-0 rounded-full"
          style={{
            background: color,
            boxShadow: `0 0 0 2px color-mix(in oklab, ${color} 18%, transparent)`,
          }}
        />
        <span
          className={cn(
            "min-w-0 truncate text-xs transition-opacity duration-200 motion-reduce:transition-none",
            depth === 0 ? "font-semibold" : "font-medium text-foreground/90",
            outside && "opacity-45",
          )}
        >
          {s.name}
        </span>
        {isError && (
          <AlertTriangle
            aria-hidden="true"
            className="size-3 shrink-0 text-destructive"
          />
        )}
        {row.collapsed && (
          <span className="shrink-0 rounded-[4px] border px-1 font-mono text-[10px] leading-3.5 text-muted-foreground tabular-nums">
            +{row.hiddenCount}
          </span>
        )}
        <span
          className={cn(
            "ml-auto shrink-0 pl-1 font-mono text-[11px] tabular-nums @max-sm/trace:hidden",
            isError
              ? "text-destructive"
              : emphasis === "critical"
                ? "font-medium text-foreground"
                : "text-muted-foreground",
          )}
        >
          {duration}
        </span>
      </div>

      <div
        data-slot="trace-row-timeline"
        className="relative min-w-0 overflow-hidden"
      >
        {row.collapsed &&
          row.summary.map((child) => (
            <span
              key={child.span.id}
              aria-hidden="true"
              className="absolute h-[3px] rounded-full opacity-60"
              style={{
                left: at(child.span.start),
                width: `max(2px, ${span(child.end - child.span.start)})`,
                bottom: Math.max(
                  2,
                  Math.round((rowHeight - barHeight) / 2) - 5,
                ),
                background:
                  child.span.status === "error"
                    ? DESTRUCTIVE
                    : colorOf(child.span.service),
              }}
            />
          ))}
        <span
          data-slot="trace-bar"
          aria-hidden="true"
          className={cn(
            "absolute top-1/2 -translate-y-1/2 rounded-[3px] transition-[opacity,box-shadow,filter] duration-200 motion-reduce:transition-none",
            emphasis === "dim" && "opacity-40 group-hover/row:opacity-75",
            selected && "ring-2 ring-primary/55 ring-offset-1 ring-offset-card",
            isError && "ring-1 ring-destructive/70 ring-inset",
          )}
          style={{
            left: at(s.start),
            width: `max(2px, ${span(node.end - s.start)})`,
            height: barHeight,
            background: isError ? errorFill : color,
            boxShadow:
              emphasis === "critical" && !selected
                ? `0 0 0 1px color-mix(in oklab, ${color} 55%, transparent), 0 1px 6px -1px color-mix(in oklab, ${color} 55%, transparent)`
                : undefined,
          }}
        >
          <span
            className={cn(
              "pointer-events-none absolute top-1/2 -translate-y-1/2 rounded-[3px] font-mono text-[10px] leading-4 whitespace-nowrap tabular-nums opacity-0 transition-opacity duration-150 group-hover/row:opacity-100 motion-reduce:transition-none @max-sm/trace:opacity-100",
              selected && "opacity-100",
              labelSide === "after" && "left-full ml-1.5 text-foreground",
              labelSide === "before" && "right-full mr-1.5 text-foreground",
              labelSide === "inside" &&
                "right-1 bg-card/90 px-1 text-foreground shadow-xs",
            )}
          >
            {duration}
          </span>
        </span>
      </div>
    </div>
  );
});

/* ------------------------------------------------------------------------ */
/* Attributes                                                                */
/* ------------------------------------------------------------------------ */

export interface TraceSpanAttributesProps extends React.ComponentProps<"dl"> {
  attributes?: Record<string, TraceSpanAttributeValue>;
}

/** The default attribute table of the detail panel, exported for custom detail layouts. */
export function TraceSpanAttributes({
  attributes,
  className,
  ...props
}: TraceSpanAttributesProps) {
  const entries = Object.entries(attributes ?? {});
  if (!entries.length)
    return (
      <p className="py-1 text-xs text-muted-foreground">
        No attributes recorded.
      </p>
    );
  return (
    <dl
      data-slot="trace-attributes"
      className={cn(
        "grid grid-cols-[minmax(6rem,auto)_minmax(0,1fr)] gap-x-5 text-xs",
        className,
      )}
      {...props}
    >
      {entries.map(([key, value]) => (
        <React.Fragment key={key}>
          <dt className="truncate border-t border-dashed py-1.5 font-mono text-[11px] text-muted-foreground first-of-type:border-t-0">
            {key}
          </dt>
          <dd
            className={cn(
              "min-w-0 border-t border-dashed py-1.5 font-mono text-[11px] break-all tabular-nums first-of-type:border-t-0",
              typeof value === "boolean" &&
                (value
                  ? "text-emerald-700 dark:text-emerald-400"
                  : "text-muted-foreground"),
              typeof value === "number" && "text-foreground",
            )}
          >
            {typeof value === "number"
              ? value.toLocaleString("en-US")
              : String(value)}
          </dd>
        </React.Fragment>
      ))}
    </dl>
  );
}

/* ------------------------------------------------------------------------ */
/* TraceWaterfall                                                            */
/* ------------------------------------------------------------------------ */

/**
 * A distributed-trace waterfall: a collapsible span tree beside a time axis. Drag across
 * the axis to zoom, click a span for its detail, and follow the critical path at a glance.
 */
export function TraceWaterfall({
  spans,
  title,
  description,
  actions,
  selectedId: selectedProp,
  defaultSelectedId = null,
  onSelectedChange,
  highlightCriticalPath: highlightProp,
  defaultHighlightCriticalPath = true,
  onHighlightCriticalPathChange,
  defaultCollapsedIds,
  serviceColors,
  durationFormatter = formatDuration,
  renderDetail,
  rowHeight = 28,
  height = 360,
  treeWidth,
  showOverview = true,
  showLegend = true,
  onZoomChange,
  className,
  style,
  ...props
}: TraceWaterfallProps) {
  const id = React.useId();
  const reduced = useReducedMotion();
  const model = React.useMemo(() => buildModel(spans), [spans]);
  const format = durationFormatter;

  const colors = React.useMemo(() => {
    const map = new Map<string, string>();
    model.services.forEach((service, i) =>
      map.set(
        service.name,
        serviceColors?.[service.name] ?? PALETTE[i % PALETTE.length],
      ),
    );
    return map;
  }, [model, serviceColors]);
  const colorOf = React.useCallback(
    (service: string) => colors.get(service) ?? PALETTE[0],
    [colors],
  );

  const [selectedId, setSelectedRaw] = useControllable<string | null>(
    selectedProp,
    defaultSelectedId,
  );
  const [highlight, setHighlight] = useControllable(
    highlightProp,
    defaultHighlightCriticalPath,
    onHighlightCriticalPathChange,
  );
  const [collapsed, setCollapsed] = React.useState(
    () => new Set(defaultCollapsedIds ?? []),
  );
  const [hidden, setHidden] = React.useState<Set<string>>(() => new Set());
  const [view, setViewState] = React.useState<TraceTimeRange | null>(null);
  const [focusId, setFocusId] = React.useState<string | null>(null);
  const [frac, setFrac] = React.useState<number | null>(null);
  const [width, setWidth] = React.useState(0);
  const [axisWidth, setAxisWidth] = React.useState(0);
  const [scroll, setScroll] = React.useState({ top: 0, height });

  const rootRef = React.useRef<HTMLDivElement>(null);
  const scrollRef = React.useRef<HTMLDivElement>(null);
  const axisRef = React.useRef<HTMLDivElement>(null);
  const treeRef = React.useRef<HTMLDivElement>(null);
  const cursorRef = React.useRef<HTMLDivElement>(null);
  const readoutRef = React.useRef<HTMLDivElement>(null);
  const brushRef = React.useRef<HTMLDivElement>(null);
  const overviewCursorRef = React.useRef<HTMLDivElement>(null);
  const pendingFocus = React.useRef<string | null>(null);
  const suppressClick = React.useRef(false);

  const selectedNode = selectedId
    ? (model.nodes.get(selectedId) ?? null)
    : null;

  const select = React.useCallback(
    (next: string | null) => {
      setSelectedRaw(next);
      onSelectedChange?.(
        next,
        next ? (model.nodes.get(next)?.span ?? null) : null,
      );
    },
    [model, onSelectedChange, setSelectedRaw],
  );

  // A selection inside a collapsed branch opens the branch so the row can be seen.
  React.useEffect(() => {
    if (!selectedNode) return;
    setCollapsed((current) => {
      let next: Set<string> | null = null;
      for (let p = selectedNode.parent; p; p = p.parent)
        if (current.has(p.span.id))
          (next ??= new Set(current)).delete(p.span.id);
      return next ?? current;
    });
  }, [selectedNode]);

  const { rows, flat } = React.useMemo(
    () => buildRows(model, collapsed, hidden),
    [model, collapsed, hidden],
  );
  const indexOf = React.useMemo(() => {
    const map = new Map<string, number>();
    rows.forEach((row, i) => map.set(row.node.span.id, i));
    return map;
  }, [rows]);

  /* ---------------------------------------------------------------- view */

  const t0 = model.start;
  const total = model.duration;
  const target = view ?? ([t0, t0 + total] as TraceTimeRange);
  const v0 = target[0];
  const vs = Math.max(1e-6, target[1] - target[0]);
  const zoomed = view != null;
  const displayed = React.useRef({ v0, vs });

  const setView = React.useCallback(
    (next: TraceTimeRange | null) => {
      setViewState(next);
      onZoomChange?.(next);
    },
    [onZoomChange],
  );

  // Clear a zoom that no longer fits new data.
  React.useEffect(() => {
    setViewState((current) =>
      current && (current[1] <= model.start || current[0] >= model.end)
        ? null
        : current,
    );
  }, [model]);

  // Tween the view variables; React only renders the target, so zooming never re-renders per frame.
  React.useLayoutEffect(() => {
    const root = rootRef.current;
    if (!root) return;
    const apply = (a: number, s: number) => {
      displayed.current = { v0: a, vs: s };
      root.style.setProperty("--trace-v0", String(tidy(a)));
      root.style.setProperty("--trace-vs", String(tidy(s)));
    };
    const from = displayed.current;
    if (
      reduced ||
      (Math.abs(from.v0 - v0) < 1e-9 && Math.abs(from.vs - vs) < 1e-9)
    ) {
      apply(v0, vs);
      return;
    }
    apply(from.v0, from.vs);
    const started = performance.now();
    let frame = 0;
    const tick = (now: number) => {
      const p = Math.min(1, (now - started) / 460);
      const e = 1 - (1 - p) ** 4;
      // Interpolate the span geometrically so zooming feels even at every scale.
      const s = from.vs * (vs / from.vs) ** e;
      const fromCenter = from.v0 + from.vs / 2;
      const toCenter = v0 + vs / 2;
      apply(fromCenter + (toCenter - fromCenter) * e - s / 2, s);
      if (p < 1) frame = requestAnimationFrame(tick);
      else apply(v0, vs);
    };
    frame = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(frame);
  }, [v0, vs, reduced]);

  const isEmpty = model.ordered.length === 0;
  const ticks = React.useMemo(() => {
    if (isEmpty) return { step: 1, list: [] };
    const count = Math.max(2, Math.floor((axisWidth || 360) / 84));
    const step = niceStep(vs, count);
    const out: { value: number; label: string }[] = [];
    for (
      let t = Math.ceil(v0 / step - 1e-9) * step;
      t <= v0 + vs + step * 1e-6;
      t += step
    )
      out.push({ value: tidy(t), label: tickLabel(tidy(t), step) });
    return { step, list: out };
  }, [v0, vs, axisWidth, isEmpty]);

  // After zooming, bring the first span inside the new range into view if none is showing.
  React.useEffect(() => {
    const el = scrollRef.current;
    if (!view || !el) return;
    const overlaps = (row: TraceRowModel) =>
      row.depth > 0 &&
      row.node.end >= view[0] &&
      row.node.span.start <= view[1];
    const top = Math.floor(el.scrollTop / rowHeight);
    const bottom = Math.ceil((el.scrollTop + el.clientHeight - 28) / rowHeight);
    if (rows.slice(top, bottom).some(overlaps)) return;
    const index = rows.findIndex(overlaps);
    if (index < 0) return;
    el.scrollTo({
      top: Math.max(0, (index - 1) * rowHeight),
      behavior: reduced ? "auto" : "smooth",
    });
    // Rows are only read when the zoom changes, not when they do.
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [view]);

  /* -------------------------------------------------------------- layout */

  React.useLayoutEffect(() => {
    const root = rootRef.current;
    const axis = axisRef.current;
    if (!root || !axis) return;
    const measure = () => {
      setWidth(root.clientWidth);
      setAxisWidth(axis.clientWidth);
    };
    measure();
    const observer = new ResizeObserver(measure);
    observer.observe(root);
    observer.observe(axis);
    return () => observer.disconnect();
  }, []);

  const treeShare = Math.min(
    0.7,
    Math.max(0.2, frac ?? treeWidth ?? (width && width < 560 ? 0.5 : 0.4)),
  );
  const contentHeight = rows.length * rowHeight;
  // The axis row is 28px; an empty list keeps room for its message.
  const viewportHeight = rows.length
    ? Math.min(height, contentHeight + 28)
    : 128;

  const onScroll = () => {
    const el = scrollRef.current;
    if (!el) return;
    const top = el.scrollTop;
    const h = el.clientHeight;
    setScroll((current) =>
      Math.floor(current.top / rowHeight) === Math.floor(top / rowHeight) &&
      current.height === h
        ? current
        : { top, height: h },
    );
  };

  const overscan = 8;
  const first = Math.max(0, Math.floor(scroll.top / rowHeight) - overscan);
  const last = Math.min(
    rows.length,
    Math.ceil((scroll.top + scroll.height) / rowHeight) + overscan,
  );
  const stopId =
    focusId && indexOf.has(focusId)
      ? focusId
      : selectedId && indexOf.has(selectedId)
        ? selectedId
        : (rows[0]?.node.span.id ?? null);
  const stopIndex = stopId ? (indexOf.get(stopId) ?? -1) : -1;

  const scrollToIndex = React.useCallback(
    (index: number, center = false) => {
      const el = scrollRef.current;
      if (!el || index < 0) return;
      const header = 28;
      const top = index * rowHeight;
      const view = el.clientHeight - header;
      if (center) {
        if (top < el.scrollTop || top + rowHeight > el.scrollTop + view)
          el.scrollTop = Math.max(0, top - view / 2 + rowHeight / 2);
      } else if (top < el.scrollTop) el.scrollTop = top;
      else if (top + rowHeight > el.scrollTop + view)
        el.scrollTop = top + rowHeight - view;
    },
    [rowHeight],
  );

  // Bring an outside selection into view.
  const lastSelected = React.useRef<string | null>(null);
  React.useLayoutEffect(() => {
    if (selectedId === lastSelected.current) return;
    lastSelected.current = selectedId;
    if (selectedId && indexOf.has(selectedId))
      scrollToIndex(indexOf.get(selectedId)!, true);
  }, [selectedId, indexOf, scrollToIndex]);

  React.useLayoutEffect(() => {
    const target = pendingFocus.current;
    if (!target) return;
    pendingFocus.current = null;
    const element = treeRef.current?.querySelector<HTMLElement>(
      `[data-span-id="${CSS.escape(target)}"]`,
    );
    element?.focus({ preventScroll: true });
  });

  /* --------------------------------------------------------- interaction */

  const toggle = React.useCallback((spanId: string) => {
    setCollapsed((current) => {
      const next = new Set(current);
      if (next.has(spanId)) next.delete(spanId);
      else next.add(spanId);
      return next;
    });
  }, []);

  const selectedRef = React.useRef(selectedId);
  selectedRef.current = selectedId;
  const activate = React.useCallback(
    (spanId: string) => {
      if (suppressClick.current) return;
      setFocusId(spanId);
      select(selectedRef.current === spanId ? null : spanId);
    },
    [select],
  );

  const moveFocus = (index: number) => {
    const row = rows[Math.max(0, Math.min(rows.length - 1, index))];
    if (!row) return;
    pendingFocus.current = row.node.span.id;
    setFocusId(row.node.span.id);
    scrollToIndex(indexOf.get(row.node.span.id)!);
  };

  const onTreeKeyDown = (event: React.KeyboardEvent<HTMLDivElement>) => {
    const target = event.target as HTMLElement;
    const spanId = target.dataset.spanId;
    if (!spanId || target.dataset.slot !== "trace-row") return;
    const index = indexOf.get(spanId) ?? 0;
    const row = rows[index];
    const page = Math.max(1, Math.floor((scroll.height - 28) / rowHeight) - 1);
    switch (event.key) {
      case "ArrowDown":
        moveFocus(index + 1);
        break;
      case "ArrowUp":
        moveFocus(index - 1);
        break;
      case "Home":
        moveFocus(0);
        break;
      case "End":
        moveFocus(rows.length - 1);
        break;
      case "PageDown":
        moveFocus(index + page);
        break;
      case "PageUp":
        moveFocus(index - page);
        break;
      case "ArrowRight":
        if (row.childCount > 0 && row.collapsed) toggle(spanId);
        else if (row.childCount > 0) moveFocus(index + 1);
        break;
      case "ArrowLeft":
        if (row.childCount > 0 && !row.collapsed) toggle(spanId);
        else if (row.parentId && indexOf.has(row.parentId))
          moveFocus(indexOf.get(row.parentId)!);
        break;
      case "Enter":
      case " ":
        select(selectedId === spanId ? null : spanId);
        break;
      case "Escape":
        if (selectedId) select(null);
        else if (zoomed) setView(null);
        else return;
        break;
      default:
        return;
    }
    event.preventDefault();
  };

  // Pointer: hover draws a cursor with a time readout; dragging across the axis zooms.
  const drag = React.useRef<{ x: number; id: number; active: boolean } | null>(
    null,
  );
  const axisRect = () => axisRef.current?.getBoundingClientRect() ?? null;
  const timeAtX = (x: number, rect: DOMRect) => {
    const f = Math.min(1, Math.max(0, (x - rect.left) / (rect.width || 1)));
    return displayed.current.v0 + f * displayed.current.vs;
  };

  const showCursor = (clientX: number | null) => {
    const rect = axisRect();
    const cursor = cursorRef.current;
    const readout = readoutRef.current;
    const overview = overviewCursorRef.current;
    const inside =
      rect && clientX !== null && clientX >= rect.left && clientX <= rect.right;
    for (const el of [cursor, readout, overview])
      if (el) el.style.opacity = inside ? "1" : "0";
    if (!inside || !rect) return;
    const x = clientX - rect.left;
    const time = timeAtX(clientX, rect);
    if (cursor) cursor.style.transform = `translateX(${x}px)`;
    if (readout) {
      const brush = drag.current?.active ? drag.current : null;
      if (brush) {
        const a = timeAtX(brush.x, rect);
        const [lo, hi] = a < time ? [a, time] : [time, a];
        readout.textContent = `${tickLabel(lo, vs / 50)} – ${tickLabel(hi, vs / 50)} · ${format(hi - lo)}`;
      } else readout.textContent = format(time - t0);
      const w = readout.offsetWidth;
      readout.style.transform = `translateX(${Math.min(Math.max(0, x - w / 2), rect.width - w)}px)`;
    }
    if (overview) overview.style.left = `${((time - t0) / total) * 100}%`;
  };

  const onPointerDown = (event: React.PointerEvent<HTMLDivElement>) => {
    if (event.button !== 0 || event.pointerType === "touch") return;
    const rect = axisRect();
    if (!rect || event.clientX < rect.left || event.clientX > rect.right)
      return;
    if ((event.target as HTMLElement).closest('[role="separator"]')) return;
    drag.current = { x: event.clientX, id: event.pointerId, active: false };
  };

  const onPointerMove = (event: React.PointerEvent<HTMLDivElement>) => {
    const d = drag.current;
    const rect = axisRect();
    if (d && rect && event.pointerId === d.id) {
      if (!d.active && Math.abs(event.clientX - d.x) > 4) {
        d.active = true;
        event.currentTarget.setPointerCapture(event.pointerId);
      }
      if (d.active && brushRef.current) {
        const a = Math.min(Math.max(d.x, rect.left), rect.right) - rect.left;
        const b =
          Math.min(Math.max(event.clientX, rect.left), rect.right) - rect.left;
        brushRef.current.style.display = "block";
        brushRef.current.style.left = `${Math.min(a, b)}px`;
        brushRef.current.style.width = `${Math.abs(b - a)}px`;
      }
    }
    showCursor(event.clientX);
  };

  const endDrag = (
    event: React.PointerEvent<HTMLDivElement>,
    commit: boolean,
  ) => {
    const d = drag.current;
    drag.current = null;
    if (brushRef.current) brushRef.current.style.display = "none";
    if (!d?.active) return;
    const rect = axisRect();
    if (commit && rect) {
      const a = timeAtX(d.x, rect);
      const b = timeAtX(event.clientX, rect);
      const lo = Math.max(t0, Math.min(a, b));
      const hi = Math.min(t0 + total, Math.max(a, b));
      if (hi - lo > Math.max(total / 5000, 1e-3)) setView([lo, hi]);
    }
    suppressClick.current = true;
    window.setTimeout(() => (suppressClick.current = false), 0);
    showCursor(event.clientX);
  };

  const onDoubleClick = (event: React.MouseEvent<HTMLDivElement>) => {
    const rect = axisRect();
    if (
      zoomed &&
      rect &&
      event.clientX >= rect.left &&
      event.clientX <= rect.right
    )
      setView(null);
  };

  // Column divider: drag or use the arrow keys.
  const onSeparatorPointerDown = (
    event: React.PointerEvent<HTMLDivElement>,
  ) => {
    if (event.button !== 0) return;
    event.preventDefault();
    const root = rootRef.current;
    if (!root) return;
    const rect =
      scrollRef.current?.getBoundingClientRect() ??
      root.getBoundingClientRect();
    const target = event.currentTarget;
    target.setPointerCapture(event.pointerId);
    const move = (e: PointerEvent) =>
      setFrac(
        Math.min(0.7, Math.max(0.2, (e.clientX - rect.left) / rect.width)),
      );
    const up = () => {
      target.removeEventListener("pointermove", move);
      target.removeEventListener("pointerup", up);
      target.removeEventListener("pointercancel", up);
    };
    target.addEventListener("pointermove", move);
    target.addEventListener("pointerup", up);
    target.addEventListener("pointercancel", up);
  };

  const collapsibleIds = React.useMemo(
    () =>
      model.ordered
        .filter((node) => node.depth > 0 && node.children.length > 0)
        .map((node) => node.span.id),
    [model],
  );
  const anyCollapsed = rows.some((row) => row.collapsed);

  /* ------------------------------------------------------------ derived */

  const emphasisOf = (node: TraceNode): TraceRowProps["emphasis"] =>
    highlight ? (node.critical ? "critical" : "dim") : "normal";
  const labelSideOf = (node: TraceNode): TraceRowProps["labelSide"] => {
    const a = (node.span.start - v0) / vs;
    const b = (node.end - v0) / vs;
    if (b < 0.78) return "after";
    if (a > 0.22) return "before";
    return "inside";
  };

  const info = (node: TraceNode): TraceSpanInfo => ({
    span: node.span,
    parent: node.parent?.span ?? null,
    children: node.children.map((child) => child.span),
    depth: node.depth,
    descendantCount: node.descendants,
    selfTime: node.self,
    share: (node.end - node.span.start) / total,
    critical: node.critical,
    color: colorOf(node.span.service),
    trace: { start: t0, end: t0 + total, duration: total },
  });

  // Keep the last span while the panel animates closed.
  const [shownNode, setShownNode] = React.useState<TraceNode | null>(
    selectedNode,
  );
  if (selectedNode && selectedNode !== shownNode) setShownNode(selectedNode);

  const label = typeof title === "string" ? title : "Trace spans";
  const services = model.services;
  const renderIndices: number[] = [];
  for (let i = first; i < last; i++) renderIndices.push(i);
  if (stopIndex >= 0 && (stopIndex < first || stopIndex >= last))
    renderIndices.push(stopIndex);

  return (
    <div
      ref={rootRef}
      data-slot="trace-waterfall"
      data-zoomed={zoomed || undefined}
      className={cn(
        "@container/trace flex min-w-0 flex-col overflow-hidden rounded-xl border bg-card text-card-foreground shadow-xs",
        className,
      )}
      style={
        {
          "--trace-v0": tidy(v0),
          "--trace-vs": tidy(vs),
          "--trace-t0": tidy(t0),
          "--trace-total": tidy(total),
          "--trace-tree": `${(treeShare * 100).toFixed(2)}%`,
          "--trace-cols": "minmax(0, var(--trace-tree)) minmax(0, 1fr)",
          ...style,
        } as React.CSSProperties
      }
      {...props}
    >
      <div
        data-slot="trace-header"
        className="flex items-start gap-3 px-4 pt-3.5 pb-3"
      >
        <div className="min-w-0 flex-1 space-y-1">
          {title != null && (
            <h3 className="truncate text-sm leading-5 font-semibold tracking-tight">
              {title}
            </h3>
          )}
          <div
            data-slot="trace-summary"
            className="flex flex-wrap items-center gap-x-2 gap-y-1 font-mono text-[11px] leading-4 text-muted-foreground tabular-nums"
          >
            <span>
              <span className="font-medium text-foreground">
                {isEmpty ? "—" : format(total)}
              </span>
            </span>
            <span aria-hidden="true" className="text-border">
              /
            </span>
            <span>
              {spans.length} {spans.length === 1 ? "span" : "spans"}
            </span>
            <span
              aria-hidden="true"
              className="hidden text-border @sm/trace:inline"
            >
              /
            </span>
            <span className="hidden @sm/trace:inline">
              {services.length} {services.length === 1 ? "service" : "services"}
            </span>
            {model.errors > 0 && (
              <span className="inline-flex items-center gap-1 rounded-full bg-destructive/10 px-1.5 font-sans text-[11px] font-medium text-destructive">
                <AlertTriangle aria-hidden="true" className="size-3" />
                {model.errors} {model.errors === 1 ? "error" : "errors"}
              </span>
            )}
          </div>
          {description != null && (
            <p
              id={`${id}-description`}
              className="text-xs text-muted-foreground"
            >
              {description}
            </p>
          )}
        </div>
        <div className="flex shrink-0 items-center gap-1">
          {actions}
          <div
            role="toolbar"
            aria-label="Trace tools"
            className="flex items-center gap-0.5"
          >
            <button
              type="button"
              className={toolButton}
              aria-pressed={highlight}
              title="Highlight the critical path"
              onClick={() => setHighlight(!highlight)}
            >
              <Route className="size-4" aria-hidden="true" />
              <span className="sr-only">Highlight the critical path</span>
            </button>
            <button
              type="button"
              className={toolButton}
              title={anyCollapsed ? "Expand all" : "Collapse all"}
              disabled={!collapsibleIds.length}
              onClick={() =>
                setCollapsed(anyCollapsed ? new Set() : new Set(collapsibleIds))
              }
            >
              {anyCollapsed ? (
                <FoldDown className="size-4" aria-hidden="true" />
              ) : (
                <FoldUp className="size-4" aria-hidden="true" />
              )}
              <span className="sr-only">
                {anyCollapsed ? "Expand all" : "Collapse all"}
              </span>
            </button>
            <button
              type="button"
              className={toolButton}
              title="Reset zoom"
              disabled={!zoomed}
              onClick={() => setView(null)}
            >
              <ZoomReset className="size-4" aria-hidden="true" />
              <span className="sr-only">Reset zoom</span>
            </button>
          </div>
        </div>
      </div>

      {showOverview && !isEmpty && (
        <TraceOverview
          nodes={flat}
          start={t0}
          total={total}
          zoomed={zoomed}
          colorOf={colorOf}
          highlight={highlight}
          cursorRef={overviewCursorRef}
          onRange={setView}
          viewStart={target[0]}
          viewEnd={target[1]}
        />
      )}

      <div
        ref={scrollRef}
        data-slot="trace-scroll"
        className="relative mt-3 touch-pan-y overflow-y-auto overscroll-contain border-t select-none"
        style={{ height: viewportHeight }}
        onScroll={onScroll}
        onPointerDown={onPointerDown}
        onPointerMove={onPointerMove}
        onPointerUp={(event) => endDrag(event, true)}
        onPointerCancel={(event) => endDrag(event, false)}
        onPointerLeave={() => {
          if (!drag.current?.active) showCursor(null);
        }}
        onDoubleClick={onDoubleClick}
      >
        <div
          data-slot="trace-axis"
          className="sticky top-0 z-20 grid h-7 grid-cols-(--trace-cols) border-b bg-card"
        >
          <div className="flex min-w-0 items-center justify-between gap-2 border-r pr-2.5 pl-3 font-mono text-[10.5px] text-muted-foreground">
            <span className="truncate">Span</span>
            <span className="@max-sm/trace:hidden">Duration</span>
          </div>
          <div
            ref={axisRef}
            className={cn(
              "relative min-w-0 overflow-hidden",
              zoomed ? "cursor-zoom-out" : "cursor-crosshair",
            )}
            title={
              zoomed
                ? "Drag to zoom further, double-click to reset"
                : "Drag across the axis to zoom"
            }
          >
            {ticks.list.map((tick) => (
              <span
                key={`${ticks.step}-${tick.value}`}
                className="absolute inset-y-0 flex items-center border-l border-border pl-1 font-mono text-[10px] leading-none whitespace-nowrap text-muted-foreground tabular-nums motion-safe:animate-[trace-fade_.35s_ease-out_both]"
                style={{ left: at(tick.value) }}
              >
                {/* A label that would be clipped at the right edge keeps only its line. */}
                {(tick.value - v0) / vs <= 0.93 ? tick.label : null}
              </span>
            ))}
            <div
              ref={readoutRef}
              aria-hidden="true"
              className="pointer-events-none absolute top-1/2 left-0 z-10 -mt-2 h-4 rounded-[4px] bg-foreground px-1.5 font-mono text-[10px] leading-4 whitespace-nowrap text-background tabular-nums opacity-0 shadow-sm"
            />
          </div>
          <div
            role="separator"
            aria-orientation="vertical"
            aria-label="Resize span column"
            aria-valuemin={20}
            aria-valuemax={70}
            aria-valuenow={Math.round(treeShare * 100)}
            tabIndex={0}
            onPointerDown={onSeparatorPointerDown}
            onKeyDown={(event) => {
              const delta =
                event.key === "ArrowLeft"
                  ? -0.02
                  : event.key === "ArrowRight"
                    ? 0.02
                    : 0;
              if (!delta) return;
              event.preventDefault();
              setFrac(Math.min(0.7, Math.max(0.2, treeShare + delta)));
            }}
            className="group/sep absolute inset-y-0 z-10 w-2 -translate-x-1/2 cursor-col-resize outline-none"
            style={{ left: "var(--trace-tree)" }}
          >
            <span className="absolute inset-y-1 left-1/2 w-0.5 -translate-x-1/2 rounded-full bg-transparent transition-colors group-hover/sep:bg-primary/60 group-focus-visible/sep:bg-ring" />
          </div>
        </div>

        {rows.length === 0 ? (
          <p className="py-10 text-center text-xs text-muted-foreground">
            {spans.length
              ? "Every service is filtered out."
              : "No spans in this trace."}
          </p>
        ) : (
          <div
            ref={treeRef}
            role="tree"
            aria-label={label}
            aria-describedby={
              description != null ? `${id}-description` : undefined
            }
            onKeyDown={onTreeKeyDown}
            onBlur={(event) => {
              if (!event.currentTarget.contains(event.relatedTarget as Node))
                setFocusId(null);
            }}
            className="relative"
            style={{ height: contentHeight }}
          >
            <div
              aria-hidden="true"
              className="pointer-events-none absolute inset-0 grid grid-cols-(--trace-cols)"
            >
              <div />
              <div className="relative overflow-hidden">
                {ticks.list.map((tick) => (
                  <span
                    key={`${ticks.step}-${tick.value}`}
                    className="absolute inset-y-0 w-px bg-border/55 motion-safe:animate-[trace-fade_.35s_ease-out_both]"
                    style={{ left: at(tick.value) }}
                  />
                ))}
              </div>
            </div>

            {renderIndices.map((i) => {
              const row = rows[i];
              const node = row.node;
              return (
                <TraceRow
                  key={node.span.id}
                  row={row}
                  index={i}
                  rowHeight={rowHeight}
                  color={colorOf(node.span.service)}
                  colorOf={colorOf}
                  selected={node.span.id === selectedId}
                  tabStop={node.span.id === stopId}
                  emphasis={emphasisOf(node)}
                  labelSide={labelSideOf(node)}
                  outside={
                    zoomed && (node.end < v0 || node.span.start > v0 + vs)
                  }
                  format={format}
                  onToggle={toggle}
                  onActivate={activate}
                  onFocusRow={setFocusId}
                />
              );
            })}

            <div
              aria-hidden="true"
              className="pointer-events-none absolute inset-0 z-10 grid grid-cols-(--trace-cols)"
            >
              <div />
              <div className="relative overflow-hidden">
                <div
                  ref={cursorRef}
                  className="absolute inset-y-0 left-0 w-px bg-foreground/45 opacity-0 transition-opacity duration-100"
                />
                <div
                  ref={brushRef}
                  className="absolute inset-y-0 hidden border-x border-primary/70 bg-primary/10"
                />
              </div>
            </div>
          </div>
        )}
      </div>

      <TraceDetail
        node={shownNode}
        open={selectedNode != null}
        info={shownNode ? info(shownNode) : null}
        format={format}
        renderDetail={renderDetail}
        onClose={() => select(null)}
        onSelect={select}
      />

      {showLegend && services.length > 0 && (
        <div
          data-slot="trace-legend"
          className="flex flex-wrap items-center gap-1 border-t px-3 py-2"
          role="group"
          aria-label="Show or hide services"
        >
          {services.map((service) => {
            const visible = !hidden.has(service.name);
            const color = colorOf(service.name);
            return (
              <button
                key={service.name}
                type="button"
                aria-pressed={visible}
                title={
                  visible ? `Hide ${service.name}` : `Show ${service.name}`
                }
                onClick={() =>
                  setHidden((current) => {
                    const next = new Set(current);
                    if (next.has(service.name)) next.delete(service.name);
                    else next.add(service.name);
                    return next;
                  })
                }
                className={cn(
                  "inline-flex h-6 items-center gap-1.5 rounded-md border px-1.5 text-xs transition-colors motion-reduce:transition-none",
                  visible
                    ? "border-transparent text-foreground hover:bg-muted"
                    : "border-dashed border-border text-muted-foreground line-through decoration-muted-foreground/50 hover:text-foreground",
                  focusRing,
                )}
              >
                <span
                  aria-hidden="true"
                  className="size-2 rounded-[2px]"
                  style={
                    visible
                      ? { background: color }
                      : { boxShadow: `inset 0 0 0 1px ${color}` }
                  }
                />
                <span className="font-medium">{service.name}</span>
                <span className="font-mono text-[10.5px] text-muted-foreground tabular-nums">
                  {service.count}
                </span>
                {service.errors > 0 && (
                  <span
                    className="inline-flex items-center gap-0.5 font-mono text-[10.5px] text-destructive tabular-nums"
                    title={`${service.errors} ${service.errors === 1 ? "error" : "errors"}`}
                  >
                    <AlertTriangle aria-hidden="true" className="size-2.5" />
                    {service.errors}
                    <span className="sr-only">
                      {" "}
                      {service.errors === 1 ? "error" : "errors"}
                    </span>
                  </span>
                )}
              </button>
            );
          })}
          {hidden.size > 0 && (
            <button
              type="button"
              onClick={() => setHidden(new Set())}
              className={cn(
                "ml-auto h-6 rounded-md px-2 text-xs font-medium text-primary hover:bg-muted",
                focusRing,
              )}
            >
              Show all
            </button>
          )}
        </div>
      )}

      <style href="overtrue-trace-waterfall" precedence="default">
        {`@keyframes trace-fade{from{opacity:0}to{opacity:1}}`}
      </style>
    </div>
  );
}

/* ------------------------------------------------------------------------ */
/* Overview                                                                  */
/* ------------------------------------------------------------------------ */

interface TraceOverviewProps {
  nodes: TraceNode[];
  start: number;
  total: number;
  viewStart: number;
  viewEnd: number;
  zoomed: boolean;
  colorOf: (service: string) => string;
  highlight: boolean;
  cursorRef: React.RefObject<HTMLDivElement | null>;
  onRange: (range: TraceTimeRange | null) => void;
}

const TraceOverview = React.memo(function TraceOverview({
  nodes,
  start,
  total,
  viewStart,
  viewEnd,
  zoomed,
  colorOf,
  highlight,
  cursorRef,
  onRange,
}: TraceOverviewProps) {
  const ref = React.useRef<HTMLDivElement>(null);
  const brushRef = React.useRef<HTMLDivElement>(null);
  const drag = React.useRef<{ x: number; active: boolean } | null>(null);
  // A mini icicle: one band per depth, split into lanes only where siblings overlap.
  const lanes = React.useMemo(() => {
    const byDepth = new Map<number, TraceNode[]>();
    for (const node of nodes) {
      const list = byDepth.get(node.depth) ?? [];
      list.push(node);
      byDepth.set(node.depth, list);
    }
    const placed: { node: TraceNode; lane: number }[] = [];
    let offset = 0;
    for (const depth of [...byDepth.keys()].sort((a, b) => a - b)) {
      const ends: number[] = [];
      const list = byDepth
        .get(depth)!
        .sort((a, b) => a.span.start - b.span.start);
      for (const node of list) {
        let lane = ends.findIndex((end) => end <= node.span.start + 1e-9);
        if (lane < 0) lane = ends.push(0) - 1;
        ends[lane] = node.end;
        placed.push({ node, lane: offset + lane });
      }
      offset += ends.length;
    }
    return { placed, count: offset };
  }, [nodes]);
  const laneHeight = Math.min(7, 30 / Math.max(1, lanes.count));
  const lens = (a: number) =>
    `calc((var(--trace-v0) - ${tidy(start)}) / ${tidy(total)} * 100% + ${a}px)`;

  const timeAt = (clientX: number) => {
    const rect = ref.current!.getBoundingClientRect();
    return (
      start +
      Math.min(1, Math.max(0, (clientX - rect.left) / rect.width)) * total
    );
  };

  return (
    <div className="px-4">
      <div
        ref={ref}
        data-slot="trace-overview"
        aria-hidden="true"
        className="relative h-10 cursor-crosshair touch-pan-y overflow-hidden rounded-md border bg-muted/25 select-none"
        onPointerDown={(event) => {
          if (event.button !== 0) return;
          drag.current = { x: event.clientX, active: false };
          event.currentTarget.setPointerCapture(event.pointerId);
        }}
        onPointerMove={(event) => {
          const rect = event.currentTarget.getBoundingClientRect();
          const cursor = cursorRef.current;
          if (cursor) {
            cursor.style.opacity = "1";
            cursor.style.left = `${((event.clientX - rect.left) / rect.width) * 100}%`;
          }
          const d = drag.current;
          if (!d) return;
          if (!d.active && Math.abs(event.clientX - d.x) > 3) d.active = true;
          if (d.active && brushRef.current) {
            const a =
              Math.min(Math.max(d.x, rect.left), rect.right) - rect.left;
            const b =
              Math.min(Math.max(event.clientX, rect.left), rect.right) -
              rect.left;
            brushRef.current.style.display = "block";
            brushRef.current.style.left = `${Math.min(a, b)}px`;
            brushRef.current.style.width = `${Math.abs(b - a)}px`;
          }
        }}
        onPointerUp={(event) => {
          const d = drag.current;
          drag.current = null;
          if (brushRef.current) brushRef.current.style.display = "none";
          if (!d) return;
          if (d.active) {
            const a = timeAt(d.x);
            const b = timeAt(event.clientX);
            if (Math.abs(b - a) > total / 5000)
              onRange([Math.min(a, b), Math.max(a, b)]);
          } else if (zoomed) {
            // A click recenters the zoom window on that moment.
            const width = viewEnd - viewStart;
            const center = timeAt(event.clientX);
            const lo = Math.min(
              Math.max(start, center - width / 2),
              start + total - width,
            );
            onRange([lo, lo + width]);
          }
        }}
        onPointerLeave={() => {
          if (cursorRef.current) cursorRef.current.style.opacity = "0";
        }}
        onDoubleClick={() => onRange(null)}
      >
        <div className="absolute inset-x-1 inset-y-1">
          {lanes.placed.map(({ node, lane }) => {
            const isError = node.span.status === "error";
            return (
              <span
                key={node.span.id}
                className={cn(
                  "absolute rounded-[1.5px]",
                  highlight && !node.critical && !isError && "opacity-35",
                )}
                style={{
                  left: `${(((node.span.start - start) / total) * 100).toFixed(3)}%`,
                  width: `max(2px, ${(((node.end - node.span.start) / total) * 100).toFixed(3)}%)`,
                  top: lane * laneHeight,
                  height: Math.max(
                    1,
                    laneHeight - (laneHeight > 3 ? 1.5 : 0.5),
                  ),
                  background: isError ? errorFill : colorOf(node.span.service),
                }}
              />
            );
          })}
        </div>
        {zoomed && (
          <>
            <div
              className="absolute inset-y-0 left-0 bg-card/70"
              style={{ width: lens(0) }}
            />
            <div
              className="absolute inset-y-0 right-0 bg-card/70"
              style={{
                left: `calc((var(--trace-v0) + var(--trace-vs) - ${tidy(start)}) / ${tidy(total)} * 100%)`,
              }}
            />
            <div
              className="absolute inset-y-0 rounded-[3px] border-x-2 border-primary shadow-[0_0_0_1px_color-mix(in_oklab,var(--color-primary)_25%,transparent)]"
              style={{
                left: lens(0),
                width: `max(4px, calc(var(--trace-vs) / ${tidy(total)} * 100%))`,
              }}
            />
          </>
        )}
        <div
          ref={cursorRef}
          className="pointer-events-none absolute inset-y-0 w-px bg-foreground/50 opacity-0 transition-opacity duration-100"
        />
        <div
          ref={brushRef}
          className="pointer-events-none absolute inset-y-0 hidden border-x border-primary bg-primary/15"
        />
      </div>
    </div>
  );
});

/* ------------------------------------------------------------------------ */
/* Detail                                                                    */
/* ------------------------------------------------------------------------ */

interface TraceDetailProps {
  node: TraceNode | null;
  info: TraceSpanInfo | null;
  open: boolean;
  format: (ms: number) => string;
  renderDetail?: (span: TraceSpan, info: TraceSpanInfo) => React.ReactNode;
  onClose: () => void;
  onSelect: (id: string | null) => void;
}

function TraceDetail({
  node,
  info,
  open,
  format,
  renderDetail,
  onClose,
  onSelect,
}: TraceDetailProps) {
  const s = node?.span;
  const isError = s?.status === "error";
  return (
    <div
      data-slot="trace-detail"
      data-open={open || undefined}
      className="grid grid-rows-[0fr] transition-[grid-template-rows] duration-300 ease-out data-[open]:grid-rows-[1fr] motion-reduce:transition-none"
      inert={!open}
    >
      <div className="min-h-0 overflow-hidden">
        {s && info && (
          <section
            aria-label={`Span detail: ${s.name}`}
            className="border-t bg-muted/20"
          >
            <div className="flex items-start gap-2.5 px-4 pt-3">
              <span
                aria-hidden="true"
                className="mt-1.5 size-2 shrink-0 rounded-full"
                style={{ background: info.color }}
              />
              <div className="min-w-0 flex-1">
                <div className="flex flex-wrap items-center gap-x-2 gap-y-1">
                  <h4 className="min-w-0 truncate text-sm font-semibold tracking-tight">
                    {s.name}
                  </h4>
                  {isError ? (
                    <span className="inline-flex items-center gap-1 rounded-full bg-destructive/10 px-1.5 py-px text-[11px] font-medium text-destructive">
                      <AlertTriangle aria-hidden="true" className="size-3" />
                      Error
                    </span>
                  ) : (
                    <span className="inline-flex items-center gap-1 rounded-full bg-emerald-500/10 px-1.5 py-px text-[11px] font-medium text-emerald-700 dark:text-emerald-400">
                      <span
                        aria-hidden="true"
                        className="size-1.5 rounded-full bg-emerald-500"
                      />
                      OK
                    </span>
                  )}
                  {info.critical && (
                    <span className="inline-flex items-center gap-1 rounded-full bg-primary/10 px-1.5 py-px text-[11px] font-medium text-primary">
                      <Route aria-hidden="true" className="size-3" />
                      Critical path
                    </span>
                  )}
                </div>
                <p className="mt-0.5 flex min-w-0 flex-wrap gap-x-2 font-mono text-[11px] text-muted-foreground">
                  <span>{s.service}</span>
                  <span aria-hidden="true" className="text-border">
                    /
                  </span>
                  <span className="truncate">{s.id}</span>
                  {info.parent && (
                    <>
                      <span aria-hidden="true" className="text-border">
                        /
                      </span>
                      <button
                        type="button"
                        onClick={() => onSelect(info.parent!.id)}
                        className={cn(
                          "truncate rounded-sm text-primary hover:underline",
                          focusRing,
                        )}
                      >
                        ↑ {info.parent.name}
                      </button>
                    </>
                  )}
                </p>
              </div>
              <button
                type="button"
                onClick={onClose}
                className={cn(toolButton, "-mt-0.5 -mr-1.5")}
                title="Close"
              >
                <X className="size-4" aria-hidden="true" />
                <span className="sr-only">Close span detail</span>
              </button>
            </div>

            <dl
              data-slot="trace-detail-timing"
              className="mx-4 mt-3 grid grid-cols-2 gap-px overflow-hidden rounded-lg border bg-border @lg/trace:grid-cols-4"
            >
              {(
                [
                  ["Start", `+${format(s.start - info.trace.start)}`],
                  ["Duration", format(s.duration)],
                  ["Self time", format(info.selfTime)],
                  ["Share of trace", formatPercent(info.share)],
                ] as const
              ).map(([term, value]) => (
                <div key={term} className="bg-card px-3 py-2">
                  <dt className="text-[11px] text-muted-foreground">{term}</dt>
                  <dd className="font-mono text-sm font-medium tabular-nums">
                    {value}
                  </dd>
                </div>
              ))}
            </dl>
            <div
              aria-hidden="true"
              className="relative mx-4 mt-2.5 h-1.5 rounded-full bg-muted"
            >
              <span
                className="absolute inset-y-0 rounded-full"
                style={{
                  left: `${((s.start - info.trace.start) / info.trace.duration) * 100}%`,
                  width: `max(3px, ${(info.share * 100).toFixed(3)}%)`,
                  background: isError ? DESTRUCTIVE : info.color,
                }}
              />
            </div>

            <div data-slot="trace-detail-body" className="px-4 pt-3 pb-4">
              {renderDetail ? (
                renderDetail(s, info)
              ) : (
                <>
                  <p className="mb-1.5 flex items-baseline gap-1.5 text-xs font-medium">
                    Attributes
                    <span className="font-mono text-[10.5px] font-normal text-muted-foreground tabular-nums">
                      {Object.keys(s.attributes ?? {}).length}
                    </span>
                  </p>
                  <TraceSpanAttributes attributes={s.attributes} />
                </>
              )}
            </div>
          </section>
        )}
      </div>
    </div>
  );
}
```

### `src/registry/overtrue/deploy-pipeline.tsx`

Left out to keep this page a readable size (45,534 characters). It is in the registry item above.

### `src/registry/overtrue/log-stream.tsx`

```tsx
"use client";

import * as React from "react";
import {
  IconArrowDown as ArrowDown,
  IconPlayerPause as Pause,
  IconPlayerPlay as Play,
  IconSearch as Search,
  IconTextWrap as TextWrap,
  IconTrash as Trash,
  IconX as X,
} from "@tabler/icons-react";

import { cn } from "@/lib/utils";

export type LogLevel = "debug" | "info" | "warn" | "error";

export interface LogEntry {
  id: string;
  time: Date | number | string;
  level: LogLevel;
  /** Service, job or component that emitted the line. */
  source?: string;
  message: string;
}

export interface LogStreamProps extends Omit<
  React.ComponentProps<"div">,
  "children" | "title"
> {
  /** Events, oldest first. Append new entries to the end. */
  entries: LogEntry[];
  title?: React.ReactNode;
  description?: React.ReactNode;
  /** Height of the scrolling log in pixels. */
  height?: number;
  /** Render at most this many of the newest matching rows. */
  maxEntries?: number;
  /** Follow the tail. Pass with `onFollowChange` to control it. */
  follow?: boolean;
  defaultFollow?: boolean;
  onFollowChange?: (follow: boolean) => void;
  /** Called by the clear action. Without it, clearing hides the current entries locally. */
  onClear?: () => void;
  /** A live source shows a Live/Paused badge, a follow control, and a cursor. Set false for archived logs. */
  live?: boolean;
  /** Levels shown initially. */
  defaultLevels?: LogLevel[];
  /** Initial text filter, matched against messages and sources. */
  defaultQuery?: string;
  /** Wrap long messages instead of truncating them. Rows can still be expanded one at a time. */
  defaultWrap?: boolean;
  /** Format timestamps in local time or UTC. */
  timeZone?: "local" | "utc";
}

const LEVELS: LogLevel[] = ["debug", "info", "warn", "error"];

const levelStyle: Record<LogLevel, { label: string; pill: string; dot: string }> = {
  debug: {
    label: "Debug",
    pill: "bg-muted text-muted-foreground",
    dot: "bg-muted-foreground/50",
  },
  info: {
    label: "Info",
    pill: "bg-sky-500/10 text-sky-700 dark:text-sky-300",
    dot: "bg-sky-500",
  },
  warn: {
    label: "Warn",
    pill: "bg-amber-500/12 text-amber-700 dark:text-amber-400",
    dot: "bg-amber-500",
  },
  error: {
    label: "Error",
    pill: "bg-destructive/12 text-rose-700 dark:text-rose-400",
    dot: "bg-destructive",
  },
};

const focusRing =
  "outline-none focus-visible:ring-2 focus-visible:ring-ring/50 focus-visible:ring-offset-1 focus-visible:ring-offset-card";

function lastIndexOfId(entries: LogEntry[], id: string) {
  for (let i = entries.length - 1; i >= 0; i--) if (entries[i].id === id) return i;
  return -1;
}

const pad = (value: number, size = 2) => String(value).padStart(size, "0");

function formatTime(time: LogEntry["time"], zone: "local" | "utc") {
  const date = time instanceof Date ? time : new Date(time);
  if (Number.isNaN(date.getTime())) return ["--:--:--", ".---", undefined] as const;
  const utc = zone === "utc";
  const hms = `${pad(utc ? date.getUTCHours() : date.getHours())}:${pad(utc ? date.getUTCMinutes() : date.getMinutes())}:${pad(utc ? date.getUTCSeconds() : date.getSeconds())}`;
  return [hms, `.${pad(utc ? date.getUTCMilliseconds() : date.getMilliseconds(), 3)}`, date.toISOString()] as const;
}

function highlight(text: string, query: string) {
  if (!query) return text;
  const lower = text.toLowerCase();
  const parts: React.ReactNode[] = [];
  let from = 0;
  let at = lower.indexOf(query, from);
  while (at !== -1) {
    if (at > from) parts.push(text.slice(from, at));
    parts.push(
      <mark key={at} className="rounded-[2px] bg-amber-300/50 text-inherit dark:bg-amber-400/30">
        {text.slice(at, at + query.length)}
      </mark>,
    );
    from = at + query.length;
    at = lower.indexOf(query, from);
  }
  if (from < text.length) parts.push(text.slice(from));
  return parts;
}

interface RowProps {
  entry: LogEntry;
  query: string;
  wrap: boolean;
  expanded: boolean;
  enter: boolean;
  zone: "local" | "utc";
  onToggle: (id: string) => void;
}

const LogRow = React.memo(function LogRow({
  entry,
  query,
  wrap,
  expanded,
  enter,
  zone,
  onToggle,
}: RowProps) {
  const [hms, ms, iso] = formatTime(entry.time, zone);
  const open = wrap || expanded;
  const level = levelStyle[entry.level] ?? levelStyle.info;
  return (
    <div
      data-level={entry.level}
      data-expanded={expanded || undefined}
      onClick={wrap ? undefined : () => onToggle(entry.id)}
      className={cn(
        "relative flex items-start gap-3 px-4 py-[5px] leading-[18px]",
        entry.level === "error"
          ? "bg-destructive/[0.06] hover:bg-destructive/10 dark:bg-destructive/10 dark:hover:bg-destructive/15"
          : "hover:bg-muted/60",
        enter &&
          "transition-[opacity,translate] duration-300 ease-out starting:translate-y-1 starting:opacity-0 motion-reduce:transition-none",
      )}
    >
      {entry.level === "error" && (
        <span aria-hidden="true" className="absolute inset-y-0 left-0 w-0.5 bg-destructive" />
      )}
      <time
        dateTime={iso}
        className="w-[84px] shrink-0 text-muted-foreground tabular-nums"
      >
        {hms}
        <span className="opacity-55">{ms}</span>
      </time>
      <span
        className={cn(
          "mt-px inline-flex h-4 w-12 shrink-0 items-center justify-center rounded-[4px] text-[10.5px] leading-none font-semibold tracking-wide uppercase",
          level.pill,
        )}
      >
        {entry.level}
      </span>
      {entry.source !== undefined && (
        <span className="hidden w-16 shrink-0 truncate text-muted-foreground @md/log:block" title={entry.source}>
          {entry.source}
        </span>
      )}
      <span
        className={cn(
          "min-w-0 flex-1 text-foreground",
          open ? "break-words whitespace-pre-wrap" : "truncate",
          entry.level === "debug" && "text-muted-foreground",
        )}
        title={open ? undefined : entry.message}
      >
        {entry.source !== undefined && (
          <span className="text-muted-foreground @md/log:hidden">{entry.source} · </span>
        )}
        {highlight(entry.message, query)}
      </span>
    </div>
  );
});

/** A live, terminal-style event stream that follows the tail until someone scrolls up to read. */
export function LogStream({
  entries,
  title = "Events",
  description,
  height = 320,
  maxEntries = 500,
  follow: followProp,
  defaultFollow = true,
  onFollowChange,
  onClear,
  live = true,
  defaultLevels = LEVELS,
  defaultQuery = "",
  defaultWrap = false,
  timeZone = "local",
  className,
  onKeyDown,
  ...props
}: LogStreamProps) {
  const id = React.useId();
  const scrollRef = React.useRef<HTMLDivElement>(null);
  const searchRef = React.useRef<HTMLInputElement>(null);
  const pausedBy = React.useRef<"scroll" | "user" | null>(null);

  const [followState, setFollowState] = React.useState(defaultFollow);
  const following = followProp ?? followState;
  const [frozen, setFrozen] = React.useState<LogEntry[] | null>(null);
  const [levels, setLevels] = React.useState<ReadonlySet<LogLevel>>(() => new Set(defaultLevels));
  const [search, setSearch] = React.useState(defaultQuery);
  const [wrap, setWrap] = React.useState(defaultWrap);
  const [expanded, setExpanded] = React.useState<ReadonlySet<string>>(() => new Set());
  const [clearedAfter, setClearedAfter] = React.useState<string | null>(null);
  const [mounted, setMounted] = React.useState(false);
  React.useEffect(() => setMounted(true), []);

  const setFollowing = React.useCallback(
    (next: boolean, reason: "scroll" | "user" = "user") => {
      pausedBy.current = next ? null : reason;
      // Freeze what is on screen so reading is never interrupted by the stream.
      setFrozen(next ? null : entries);
      if (followProp === undefined) setFollowState(next);
      onFollowChange?.(next);
    },
    [entries, followProp, onFollowChange],
  );

  // Keep a controlled `follow={false}` frozen too.
  React.useLayoutEffect(() => {
    if (!following && !frozen) setFrozen(entries);
    if (following && frozen) setFrozen(null);
  }, [following, frozen, entries]);

  const visibleSource = React.useMemo(() => {
    const source = frozen ?? entries;
    if (clearedAfter === null) return source;
    const index = lastIndexOfId(source, clearedAfter);
    return index === -1 ? source : source.slice(index + 1);
  }, [frozen, entries, clearedAfter]);

  const query = search.trim().toLowerCase();
  const { rows, counts, matching } = React.useMemo(() => {
    const counts: Record<LogLevel, number> = { debug: 0, info: 0, warn: 0, error: 0 };
    const rows: LogEntry[] = [];
    for (const entry of visibleSource) {
      if (
        query &&
        !entry.message.toLowerCase().includes(query) &&
        !entry.source?.toLowerCase().includes(query)
      )
        continue;
      counts[entry.level] = (counts[entry.level] ?? 0) + 1;
      if (levels.has(entry.level)) rows.push(entry);
    }
    const matching = rows.length;
    return { rows: rows.length > maxEntries ? rows.slice(-maxEntries) : rows, counts, matching };
  }, [visibleSource, query, levels, maxEntries]);

  const pending = React.useMemo(() => {
    if (following || !frozen) return 0;
    const last = frozen[frozen.length - 1];
    const index = last ? lastIndexOfId(entries, last.id) : -1;
    let count = 0;
    for (let i = index + 1; i < entries.length; i++) if (levels.has(entries[i].level)) count++;
    return count;
  }, [following, frozen, entries, levels]);

  // Stay pinned to the newest row while following.
  React.useLayoutEffect(() => {
    const element = scrollRef.current;
    if (following && element) element.scrollTop = element.scrollHeight;
  }, [following, rows]);

  const handleScroll = () => {
    const element = scrollRef.current;
    if (!element) return;
    const distance = element.scrollHeight - element.scrollTop - element.clientHeight;
    if (following && distance > 24) setFollowing(false, "scroll");
    else if (!following && pausedBy.current === "scroll" && distance < 2) setFollowing(true);
  };

  const toggleRow = React.useCallback((rowId: string) => {
    if (window.getSelection()?.toString()) return;
    setExpanded((current) => {
      const next = new Set(current);
      if (!next.delete(rowId)) next.add(rowId);
      return next;
    });
  }, []);

  const toggleLevel = (level: LogLevel) =>
    setLevels((current) => {
      const next = new Set(current);
      if (!next.delete(level)) next.add(level);
      return next;
    });

  const clear = () => {
    setExpanded(new Set());
    if (onClear) onClear();
    else setClearedAfter(entries[entries.length - 1]?.id ?? null);
    if (!following) setFollowing(true);
  };

  const resetFilters = () => {
    setSearch("");
    setLevels(new Set(LEVELS));
  };

  const total = visibleSource.length;
  const filtered = query !== "" || levels.size < LEVELS.length;

  return (
    <div
      data-slot="log-stream"
      data-following={following || undefined}
      className={cn(
        "@container/log flex min-w-0 flex-col overflow-hidden rounded-xl border bg-card text-card-foreground shadow-xs",
        className,
      )}
      onKeyDown={(event) => {
        onKeyDown?.(event);
        const target = event.target as HTMLElement;
        if (
          event.key === "/" &&
          !event.defaultPrevented &&
          !(target instanceof HTMLInputElement || target instanceof HTMLTextAreaElement)
        ) {
          event.preventDefault();
          searchRef.current?.focus();
        }
      }}
      {...props}
    >
      <div className="flex items-start gap-3 px-4 pt-3.5 pb-3">
        <div className="min-w-0 flex-1">
          <div className="flex min-w-0 flex-wrap items-center gap-x-2 gap-y-1">
            <p id={`${id}-title`} className="min-w-0 text-sm leading-6 font-semibold tracking-tight break-words">
              {title}
            </p>
            {live && (
              <span
                className={cn(
                  "inline-flex shrink-0 items-center gap-1.5 rounded-full border px-2 py-px text-[11px] leading-4 font-medium",
                  following ? "text-emerald-700 dark:text-emerald-400" : "text-amber-700 dark:text-amber-400",
                )}
              >
                <span className="relative flex size-1.5" aria-hidden="true">
                  {following && (
                    <span className="absolute inline-flex size-full animate-ping rounded-full bg-emerald-500 opacity-70 motion-reduce:hidden" />
                  )}
                  <span
                    className={cn(
                      "relative inline-flex size-1.5 rounded-full",
                      following ? "bg-emerald-500" : "bg-amber-500",
                    )}
                  />
                </span>
                {following ? "Live" : "Paused"}
              </span>
            )}
          </div>
          {description && <p className="truncate text-xs text-muted-foreground">{description}</p>}
        </div>
        <div className="flex shrink-0 items-center gap-1">
          <button
            type="button"
            aria-pressed={wrap}
            title="Wrap long lines"
            onClick={() => setWrap((value) => !value)}
            className={cn(
              "inline-flex size-7 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-muted hover:text-foreground aria-pressed:bg-muted aria-pressed:text-foreground motion-reduce:transition-none",
              focusRing,
            )}
          >
            <TextWrap className="size-4" aria-hidden="true" />
            <span className="sr-only">Wrap long lines</span>
          </button>
          <button
            type="button"
            title="Clear"
            onClick={clear}
            className={cn(
              "inline-flex size-7 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-muted hover:text-foreground motion-reduce:transition-none",
              focusRing,
            )}
          >
            <Trash className="size-4" aria-hidden="true" />
            <span className="sr-only">Clear events</span>
          </button>
          {live && (
            <button
              type="button"
              title={following ? "Pause the tail" : "Resume following"}
              aria-label={following ? "Pause following" : "Resume following"}
              onClick={() => setFollowing(!following)}
              className={cn(
                "ml-1 inline-flex h-7 items-center gap-1.5 rounded-md border bg-card px-2 text-xs font-medium shadow-xs transition-colors hover:bg-muted motion-reduce:transition-none @md/log:px-2.5",
                focusRing,
              )}
            >
              {following ? (
                <Pause className="size-3.5" aria-hidden="true" />
              ) : (
                <Play className="size-3.5" aria-hidden="true" />
              )}
              <span className="sr-only @md/log:not-sr-only">{following ? "Pause" : "Resume"}</span>
            </button>
          )}
        </div>
      </div>

      <div className="flex flex-wrap items-center gap-2 border-y bg-muted/30 px-4 py-2">
        <div role="group" aria-label="Levels" className="flex flex-wrap items-center gap-1">
          {LEVELS.map((level) => {
            const active = levels.has(level);
            return (
              <button
                key={level}
                type="button"
                aria-pressed={active}
                onClick={() => toggleLevel(level)}
                className={cn(
                  "inline-flex h-6 items-center gap-1 rounded-md border px-1.5 text-xs transition-colors motion-reduce:transition-none @md/log:gap-1.5 @md/log:px-2",
                  active
                    ? "border-border bg-card text-foreground shadow-xs"
                    : "border-transparent text-muted-foreground hover:text-foreground",
                  focusRing,
                )}
              >
                <span
                  aria-hidden="true"
                  className={cn(
                    "size-1.5 rounded-full",
                    active ? levelStyle[level].dot : "bg-transparent ring-1 ring-muted-foreground/50 ring-inset",
                  )}
                />
                {levelStyle[level].label}
                <span className="font-mono text-[11px] text-muted-foreground tabular-nums">{counts[level]}</span>
              </button>
            );
          })}
        </div>
        <div className="relative ml-auto min-w-36 flex-1 @lg/log:max-w-60">
          <Search
            aria-hidden="true"
            className="pointer-events-none absolute top-1/2 left-2 size-3.5 -translate-y-1/2 text-muted-foreground"
          />
          <input
            ref={searchRef}
            type="text"
            value={search}
            onChange={(event) => setSearch(event.target.value)}
            onKeyDown={(event) => {
              if (event.key === "Escape" && search) {
                event.stopPropagation();
                setSearch("");
              }
            }}
            placeholder="Filter…"
            aria-label="Filter messages"
            spellCheck={false}
            className="h-7 w-full rounded-md border border-input bg-card pr-7 pl-7 text-xs text-foreground shadow-xs transition-[border-color,box-shadow] outline-none placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-2 focus-visible:ring-ring/30 motion-reduce:transition-none"
          />
          {search ? (
            <button
              type="button"
              onClick={() => {
                setSearch("");
                searchRef.current?.focus();
              }}
              className={cn(
                "absolute top-1/2 right-1 inline-flex size-5 -translate-y-1/2 items-center justify-center rounded text-muted-foreground hover:text-foreground",
                focusRing,
              )}
            >
              <X className="size-3" aria-hidden="true" />
              <span className="sr-only">Clear filter</span>
            </button>
          ) : (
            <kbd className="pointer-events-none absolute top-1/2 right-1.5 hidden -translate-y-1/2 rounded border bg-muted px-1 font-mono text-[10px] leading-4 text-muted-foreground @md/log:block">
              /
            </kbd>
          )}
        </div>
      </div>

      <div className="relative">
        <div
          ref={scrollRef}
          role="log"
          aria-live="polite"
          aria-relevant="additions"
          aria-labelledby={`${id}-title`}
          tabIndex={0}
          onScroll={handleScroll}
          className="overflow-y-auto overscroll-contain py-1.5 font-mono text-xs outline-none focus-visible:ring-2 focus-visible:ring-ring/50 focus-visible:ring-inset"
          style={{ height }}
        >
          {rows.map((entry) => (
            <LogRow
              key={entry.id}
              entry={entry}
              query={query}
              wrap={wrap}
              expanded={expanded.has(entry.id)}
              enter={mounted}
              zone={timeZone}
              onToggle={toggleRow}
            />
          ))}
          {rows.length === 0 && (
            <div className="flex h-full flex-col items-center justify-center gap-2 px-4 text-center font-sans">
              {total === 0 ? (
                <p className="text-xs text-muted-foreground">
                  {live ? "Waiting for events…" : "No events yet."}
                </p>
              ) : (
                <>
                  <p className="text-xs text-muted-foreground">No events match these filters.</p>
                  <button
                    type="button"
                    onClick={resetFilters}
                    className={cn("rounded-md px-2 py-1 text-xs font-medium text-primary hover:bg-muted", focusRing)}
                  >
                    Show all events
                  </button>
                </>
              )}
            </div>
          )}
          {rows.length > 0 && live && following && (
            <div aria-hidden="true" className="px-4 py-[5px] leading-[18px]">
              <span className="inline-block h-3.5 w-[7px] translate-y-[3px] animate-pulse bg-foreground/35 motion-reduce:animate-none" />
            </div>
          )}
        </div>
        <div
          aria-hidden="true"
          className="pointer-events-none absolute inset-x-0 top-0 h-4 bg-linear-to-b from-card to-transparent"
        />
        {!following && (
          <button
            type="button"
            onClick={() => setFollowing(true)}
            className={cn(
              "absolute bottom-3 left-1/2 inline-flex h-7 -translate-x-1/2 items-center gap-1.5 rounded-full bg-foreground px-3 text-xs font-medium text-background shadow-lg transition-[opacity,translate] duration-200 starting:translate-y-1 starting:opacity-0 motion-reduce:transition-none",
              focusRing,
            )}
          >
            <ArrowDown className="size-3.5" aria-hidden="true" />
            Jump to latest
            {pending > 0 && (
              <span className="rounded-full bg-background/20 px-1.5 font-mono text-[11px] tabular-nums">
                {pending > 999 ? "999+" : pending} new
              </span>
            )}
          </button>
        )}
      </div>

      <div className="flex items-center justify-between gap-3 border-t px-4 py-1.5 font-mono text-[11px] text-muted-foreground tabular-nums">
        <span>
          {filtered ? `${matching.toLocaleString("en-US")} of ${total.toLocaleString("en-US")}` : total.toLocaleString("en-US")}{" "}
          {total === 1 ? "event" : "events"}
          {rows.length < matching && ` · showing last ${rows.length.toLocaleString("en-US")}`}
        </span>
        <span>{timeZone === "utc" ? "UTC" : "Local time"}</span>
      </div>
    </div>
  );
}
```
