/* Shared MCP animation for full-size cards and next-case previews. */
  /* MCP topology */
  .viz-mcp { width: 100%; max-width: 420px; padding: 0 12px; }
  .viz-mcp svg { width: 100%; height: auto; overflow: visible; }
  .viz-mcp .ln { stroke: var(--line-strong); stroke-width: 1; fill: none; }
  /* Packets: hidden until mcp-flow.js activates their hop, then exactly one pass.
     dashoffset runs 18 → -100, so the dash enters before the path start and exits
     past its end. The old version looped 14 → -100 against a pattern that repeats
     every 100 units, which is what made it flicker at every restart. */
  .viz-mcp .pulse {
    stroke: var(--accent); stroke-width: 1.7; fill: none;
    stroke-dasharray: 18 82; stroke-dashoffset: 18; stroke-linecap: round;
    opacity: 0;
  }
  .viz-mcp .pulse.is-active { opacity: 1; animation: mcpfFlow 0.72s cubic-bezier(0.4, 0, 0.6, 1) forwards; }
  /* The return trip uses the second accent so request and response read apart. */
  /* Request travels in accent, the response comes back in the success hue. */
  .viz-mcp .pulse.is-back { opacity: 1; stroke: var(--mcpf-ok); animation: mcpfFlowBack 0.72s cubic-bezier(0.4, 0, 0.6, 1) forwards; }
  @keyframes mcpfFlow { from { stroke-dashoffset: 18; } to { stroke-dashoffset: -100; } }
  @keyframes mcpfFlowBack { from { stroke-dashoffset: -100; } to { stroke-dashoffset: 18; } }

  .viz-mcp .node { fill: oklch(from var(--bg) calc(l + 0.05) c h); stroke: var(--line-strong); transition: stroke 0.3s, fill 0.3s; }
  .viz-mcp .node.hot { stroke: oklch(from var(--accent) l c h / 0.7); fill: oklch(from var(--accent) l c h / 0.10); }
  .viz-mcp text { font-family: var(--mono); font-size: 9px; fill: var(--muted); transition: fill 0.3s; }
  .viz-mcp text.hot { fill: var(--accent); }
  /* The node currently taking part in the request. */
  .viz-mcp .node-g.is-lit .node { stroke: var(--accent); fill: oklch(from var(--accent) l c h / 0.2); }
  .viz-mcp .node-g.is-lit text { fill: var(--accent); }

  /* The question, typed into what reads as an input field. */
  .viz-mcp .mcpf-input rect:first-of-type {
    fill: var(--surface-sunken); stroke: var(--line-input); stroke-width: 0.8;
  }
  .viz-mcp .mcpf-input-text { font-size: 10px; fill: var(--text); }
  .viz-mcp .mcpf-caret { fill: var(--accent); opacity: 0; }
  .viz-mcp .mcpf-input.is-typing .mcpf-caret { opacity: 1; animation: mcpfCaret 1s steps(1) infinite; }
  @keyframes mcpfCaret { 50% { opacity: 0; } }
  /* Return key hint, lights up at the moment the request is sent. */
  .viz-mcp .mcpf-enter { font-size: 11px; fill: var(--faint); opacity: 0; transition: opacity 0.25s, fill 0.25s; }
  .viz-mcp .mcpf-input.is-ready .mcpf-enter { opacity: 1; }
  .viz-mcp .mcpf-input.is-sent .mcpf-enter { opacity: 1; fill: var(--accent); }

  /* Request view and result view share the frame. The graph carries the journey,
     the report carries what came back — a number alone undersold it. */
  .viz-mcp .mcpf-graph { transition: opacity 0.45s var(--ease-out-soft); }
  .viz-mcp[data-view="report"] .mcpf-graph { opacity: 0; pointer-events: none; }

  .viz-mcp .mcpf-report {
    opacity: 0; transform: translateY(10px);
    transition: opacity 0.45s var(--ease-out-soft), transform 0.5s var(--ease-out-soft);
    pointer-events: none;
  }
  .viz-mcp[data-view="report"] .mcpf-report { opacity: 1; transform: translateY(0); }
  /* The result reads as a success, not just as more accent. Derived from --accent
     with the hue rotated toward green, so it stays in the palette and follows the
     light/dark switch on its own. */
  .viz-mcp { --mcpf-ok: oklch(from var(--accent) l c 158); }
  .viz-mcp .mcpf-report-card {
    /* srgb, not oklch: --surface-2 is achromatic in light mode, and mixing a hueless
       colour in oklch let the hue drift (measured: 158 turned into 11, a red tint). */
    fill: color-mix(in srgb, var(--mcpf-ok) 7%, var(--surface-2));
    stroke: oklch(from var(--mcpf-ok) l c h / 0.5); stroke-width: 0.8;
  }
  .viz-mcp .mcpf-report-kind { font-size: 6px; fill: var(--faint); letter-spacing: 0.16em; }
  .viz-mcp .mcpf-report-head { font-size: 13px; font-weight: 600; fill: var(--mcpf-ok); }
  .viz-mcp .mcpf-report-rule { stroke: var(--line); stroke-width: 0.8; fill: none; }
  .viz-mcp .mcpf-row-label { font-size: 8px; fill: var(--text); }
  .viz-mcp .mcpf-row-value { font-size: 8px; fill: var(--muted); font-variant-numeric: tabular-nums; }
  .viz-mcp .mcpf-row-track { fill: var(--wash); }
  .viz-mcp .mcpf-row-bar { fill: var(--mcpf-ok); transition: width 0.7s var(--ease-out-soft); }
  .viz-mcp .mcpf-report-foot { font-size: 6.5px; fill: var(--faint); letter-spacing: 0.06em; }

  /* Check badge: pops slightly after the panel, so the eye reads panel, then verdict. */
  .viz-mcp .mcpf-badge circle { fill: var(--mcpf-ok); }
  .viz-mcp .mcpf-badge path { fill: none; stroke: var(--on-accent); stroke-width: 2.4; stroke-linecap: round; stroke-linejoin: round; }
  .viz-mcp .mcpf-badge {
    opacity: 0; transform: scale(0.5); transform-box: fill-box; transform-origin: center;
    transition: opacity 0.3s var(--ease-out-soft), transform 0.4s var(--ease-spring);
  }
  .viz-mcp[data-view="report"] .mcpf-badge { opacity: 1; transform: scale(1); transition-delay: 0.3s; }

  /* The input rises slightly as the report takes over, so the question reads as
     history and the result as the current thing. */
  .viz-mcp .mcpf-input { transition: transform 0.45s var(--ease-out-soft); }
  .viz-mcp[data-view="report"] .mcpf-input { transform: translateY(-3px); }

  /* On a phone the card is ~320px wide, which scaled the report rows down to 7px
     and the kind label to 5.5px. Reclaim the side padding and size the type up in
     viewBox units so it lands around 9px on screen. */
  @media (max-width: 820px) {
    .viz-mcp { padding: 0 5px; }
    .viz-mcp .mcpf-report-kind { font-size: 7px; }
    .viz-mcp .mcpf-report-head { font-size: 14px; }
    .viz-mcp .mcpf-row-label, .viz-mcp .mcpf-row-value { font-size: 9px; }
    .viz-mcp .mcpf-report-foot { font-size: 7px; }
    .viz-mcp .mcpf-input-text { font-size: 11px; }
    .viz-mcp text { font-size: 10px; }
    .viz-mcp .mcpf-tool-name { font-size: 8px; }
    .viz-mcp .mcpf-tool-label { font-size: 6px; }
  }

  /* Tool call, tied to MCP by its own short connector and a label. */
  .viz-mcp .mcpf-tool { opacity: 0; transition: opacity 0.3s var(--ease-out-soft); }
  .viz-mcp .mcpf-tool.is-shown { opacity: 1; }
  .viz-mcp .mcpf-tool rect { fill: var(--surface-sunken); stroke: oklch(from var(--accent) l c h / 0.5); stroke-width: 0.8; }
  .viz-mcp .mcpf-tool-label { font-size: 5.5px; fill: var(--faint); letter-spacing: 0.16em; }
  .viz-mcp .mcpf-tool-name { font-size: 7.5px; fill: var(--accent); letter-spacing: 0.02em; }
  .viz-mcp .mcpf-tool-link { opacity: 0; transition: opacity 0.3s; }
  .viz-mcp .mcpf-tool-link.is-shown { opacity: 1; }


@media (prefers-reduced-motion: reduce) {
  .viz-mcp .pulse, .viz-mcp .pulse.is-active, .viz-mcp .pulse.is-back { animation: none; opacity: 0; }
}
