// Shared Bloom site components: brand mark, nav, footer, hero illustrations.
// Components are pushed to window for cross-file use.

const BLOOM_MARK = `<svg viewBox="0 0 64 64" fill="none" width="26" height="26" aria-hidden="true">
  <g stroke="currentColor" stroke-width="2.5" stroke-linecap="round">
    <circle cx="32" cy="32" r="3.5" fill="currentColor"/>
    <circle cx="32" cy="10" r="2.5"/><circle cx="51" cy="21" r="2.5"/>
    <circle cx="51" cy="43" r="2.5"/><circle cx="32" cy="54" r="2.5"/>
    <circle cx="13" cy="43" r="2.5"/><circle cx="13" cy="21" r="2.5"/>
    <line x1="32" y1="32" x2="32" y2="12.5"/><line x1="32" y1="32" x2="49" y2="22"/>
    <line x1="32" y1="32" x2="49" y2="42"/><line x1="32" y1="32" x2="32" y2="51.5"/>
    <line x1="32" y1="32" x2="15" y2="42"/><line x1="32" y1="32" x2="15" y2="22"/>
  </g></svg>`;

const Icon = ({ name, size = 16, stroke = 1.5, ...rest }) => (
  <i data-lucide={name} style={{ width: size, height: size, strokeWidth: stroke, display: 'inline-block' }} {...rest} />
);

const Mark = ({ size = 26 }) => (
  <span dangerouslySetInnerHTML={{ __html: BLOOM_MARK.replace('width="26" height="26"', `width="${size}" height="${size}"`) }} style={{ color: 'var(--ink)', display: 'inline-flex' }} />
);

/* ───────────── Announce ───────────── */
const Announce = () => (
  <div className="announce">
    <span className="dot" />
    <span style={{ color: 'var(--graphite-2)' }}>DESIGN PARTNER PROGRAM </span>
    · Q2 cohort · 4 of 6 spots remaining. <a href="pilot.html">Apply →</a>
  </div>
);

/* ───────────── Nav ───────────── */
const Nav = ({ active = 'home' }) => (
  <div className="container">
    <nav className="nav">
      <a className="brand" href="index.html">
        <Mark />
        <span className="brand-name" style={{ color: '#01BBF4' }}>bloom</span>
      </a>
      <div className="links">
        <div className="dropdown-wrap">
          <a href="product.html" className={active === 'product' ? 'active dropdown-trigger' : 'dropdown-trigger'}>
            Product <span className="caret" aria-hidden="true">▾</span>
          </a>
          <div className="dropdown-menu" role="menu">
            <div className="dd-eyebrow">The four pillars</div>
            <a href="product.html#visibility" role="menuitem">
              <span className="dd-num">01</span>
              <span className="dd-body">
                <span className="dd-title">Visibility</span>
                <span className="dd-sub">Per-customer cost attribution</span>
              </span>
            </a>
            <a href="product.html#routing" role="menuitem">
              <span className="dd-num">02</span>
              <span className="dd-body">
                <span className="dd-title">Smart routing</span>
                <span className="dd-sub">Optimal model · every request</span>
              </span>
            </a>
            <a href="product.html#guardrails" role="menuitem">
              <span className="dd-num">03</span>
              <span className="dd-body">
                <span className="dd-title">Guardrails</span>
                <span className="dd-sub">Policy at the inference layer</span>
              </span>
            </a>
            <a href="product.html#evals" role="menuitem">
              <span className="dd-num">04</span>
              <span className="dd-body">
                <span className="dd-title">Closed-loop evals</span>
                <span className="dd-sub">Quality intelligence that feeds routing</span>
              </span>
            </a>
          </div>
        </div>
        <a href="pricing.html" className={active === 'pricing' ? 'active' : ''}>Pricing</a>
        <a href="pilot.html" className={active === 'pilot' ? 'active' : ''}>Design Partner Program</a>
      </div>
      <div className="right">
        <a href="sign-in.html" className="btn btn-ghost btn-sm">Sign in</a>
        <a href="pilot.html" className="btn btn-primary btn-sm">Apply to pilot →</a>
      </div>
    </nav>
  </div>
);

/* ───────────── Footer ───────────── */
const Footer = () => (
  <div className="footer">
    <div className="container">
      <div className="footer-top">
        <div className="footer-brand">
          <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 18 }}>
            <Mark />
            <span style={{ fontSize: 22, fontWeight: 500, letterSpacing: '-0.02em' }}>bloom</span>
          </div>
          <p className="footer-tag">
            The AI inference economics control plane.
          </p>
          <p className="footer-tag-sub">
            Visibility, routing, guardrails, and closed-loop evals — governed at the inference layer.
          </p>
          <div className="footer-tags">
            <span className="tag">SOC 2 TYPE II</span>
            <span className="tag">HIPAA READY</span>
            <span className="tag">VPC OR SAAS</span>
          </div>
        </div>

        <div className="footer-pillars">
          <div className="footer-eyebrow">The four pillars</div>
          <a href="product.html#visibility"><span className="pn">01</span><span className="pl">Visibility</span></a>
          <a href="product.html#routing"><span className="pn">02</span><span className="pl">Smart routing</span></a>
          <a href="product.html#guardrails"><span className="pn">03</span><span className="pl">Guardrails</span></a>
          <a href="product.html#evals"><span className="pn">04</span><span className="pl">Closed-loop evals</span></a>
        </div>
      </div>

      <div className="footer-base">
        <span>© 2026 Bloom Inc.</span>
        <span>·</span>
        <span>Backed by LG Nova</span>
        <span>·</span>
        <span className="ok" />
        <span>All systems operational</span>
        <span className="right">v2.4.1 · build 8a3f9c2</span>
      </div>
    </div>
  </div>
);

/* ───────────── Live counter hook ───────────── */
function useTicker(initial, step = 1, intervalMs = 1100, fmt = (n) => n.toLocaleString()) {
  const [n, setN] = React.useState(initial);
  React.useEffect(() => {
    const id = setInterval(() => {
      setN(prev => prev + (typeof step === 'function' ? step() : step));
    }, intervalMs);
    return () => clearInterval(id);
  }, [intervalMs]);
  return fmt(n);
}

/* ───────────── Route diagram — clean three-column layout ───────────── */
const RouteDiagram = () => {
  const [tick, setTick] = React.useState(0);
  React.useEffect(() => {
    const id = setInterval(() => setTick(t => (t + 1) % 3), 1800);
    return () => clearInterval(id);
  }, []);
  const providers = [
    { y:  80, label: 'openai',    region: 'us-east-1', p99: 62 },
    { y: 200, label: 'anthropic', region: 'eu-west-1', p99: 87 },
    { y: 320, label: 'together',  region: 'us-west-2', p99: 94 },
  ];
  const COL_C = 70;     // client x
  const COL_G = 280;    // gateway x (center of box)
  const COL_P = 470;    // provider box left x
  return (
    <svg viewBox="0 0 660 440" width="100%" style={{ display: 'block' }}>
      <defs>
        <pattern id="rdDots" width="18" height="18" patternUnits="userSpaceOnUse">
          <circle cx="1" cy="1" r="1" fill="var(--rule-2)" />
        </pattern>
      </defs>
      <rect width="660" height="440" fill="url(#rdDots)" opacity="0.35"/>

      {/* Column headers */}
      <g fontFamily="Geist Mono" fontSize="10" fill="var(--fg-3)" letterSpacing="0.10em">
        <text x={COL_C} y="32" textAnchor="middle">CLIENT</text>
        <text x={COL_G} y="32" textAnchor="middle">▸ BLOOM GATEWAY</text>
        <text x={COL_P + 80} y="32" textAnchor="middle">PROVIDERS</text>
      </g>

      {/* faint connection lines client → gateway, gateway → providers */}
      <g stroke="var(--rule-2)" strokeWidth="1" fill="none">
        <path d={`M${COL_C + 14},210 L${COL_G - 70},210`} />
        {providers.map((p, i) => (
          <path key={i} d={`M${COL_G + 70},210 C${COL_G + 130},210 ${COL_P - 50},${p.y + 24} ${COL_P},${p.y + 24}`} />
        ))}
      </g>

      {/* Active highlighted route */}
      {(() => {
        const p = providers[tick];
        return (
          <g key={tick} stroke="var(--signal)" strokeWidth="2" fill="none" strokeLinecap="round">
            <path d={`M${COL_C + 14},210 L${COL_G - 70},210`}
                  strokeDasharray="220" strokeDashoffset="220">
              <animate attributeName="stroke-dashoffset" from="220" to="0" dur="0.45s" fill="freeze"/>
            </path>
            <path d={`M${COL_G + 70},210 C${COL_G + 130},210 ${COL_P - 50},${p.y + 24} ${COL_P},${p.y + 24}`}
                  strokeDasharray="260" strokeDashoffset="260">
              <animate attributeName="stroke-dashoffset" from="260" to="0" dur="0.55s" begin="0.45s" fill="freeze"/>
            </path>
          </g>
        );
      })()}

      {/* Client node */}
      <g>
        <circle cx={COL_C} cy="210" r="14" fill="var(--signal)" stroke="var(--ink)" strokeWidth="1.5"/>
        <text x={COL_C} y="245" textAnchor="middle" fontFamily="Geist Mono" fontSize="10" fill="var(--fg-3)" letterSpacing="0.06em">your.app</text>
      </g>

      {/* Gateway: tall card, no overlap */}
      <g>
        <rect x={COL_G - 70} y="128" width="140" height="164" rx="6" fill="var(--ink)" stroke="var(--ink)"/>
        <text x={COL_G} y="154" textAnchor="middle" fontFamily="Geist Mono" fontSize="9" fill="var(--graphite-2)" letterSpacing="0.10em">BLOOM</text>
        <text x={COL_G} y="178" textAnchor="middle" fontFamily="Geist" fontSize="18" fontWeight="500" fill="var(--paper)" letterSpacing="-0.01em">gateway</text>
        <line x1={COL_G - 50} y1="194" x2={COL_G + 50} y2="194" stroke="rgba(255,255,255,0.12)"/>
        {/* mini pillar list */}
        <g fontFamily="Geist Mono" fontSize="10" fill="var(--graphite-2)" letterSpacing="0.04em">
          <text x={COL_G - 50} y="214">01 · observe</text>
          <text x={COL_G - 50} y="232">02 · route</text>
          <text x={COL_G - 50} y="250">03 · enforce</text>
          <text x={COL_G - 50} y="268">04 · score</text>
        </g>
        <circle cx={COL_G + 54} cy="284" r="2.5" fill="var(--signal)">
          <animate attributeName="opacity" values="1;0.3;1" dur="1.6s" repeatCount="indefinite"/>
        </circle>
        <text x={COL_G + 48} y="287" textAnchor="end" fontFamily="Geist Mono" fontSize="9" fill="var(--signal)" letterSpacing="0.10em">LIVE</text>
      </g>

      {/* Provider rows */}
      {providers.map((p, i) => {
        const active = i === tick;
        return (
          <g key={i}>
            <rect x={COL_P} y={p.y} width="170" height="48" rx="5"
                  fill={active ? 'var(--ink)' : 'var(--paper)'}
                  stroke="var(--ink)" strokeWidth="1.2"/>
            <text x={COL_P + 14} y={p.y + 18} fontFamily="Geist Mono" fontSize="9"
                  fill={active ? 'var(--graphite-2)' : 'var(--fg-3)'} letterSpacing="0.10em">
              {p.region.toUpperCase()}
            </text>
            <text x={COL_P + 14} y={p.y + 36} fontFamily="Geist" fontSize="14" fontWeight="500"
                  fill={active ? 'var(--paper)' : 'var(--ink)'} letterSpacing="-0.01em">
              {p.label} · <tspan fontFamily="Geist Mono" fontSize="12">{p.p99}ms</tspan>
            </text>
            {active && <circle cx={COL_P + 156} cy={p.y + 12} r="3" fill="var(--signal)"/>}
          </g>
        );
      })}

      {/* SLO badge bottom-left under client */}
      <g>
        <rect x="30" y="396" width="190" height="32" rx="4" fill="var(--paper)" stroke="var(--ink)" strokeWidth="1"/>
        <text x="42" y="416" fontFamily="Geist Mono" fontSize="10" fill="var(--fg-3)" letterSpacing="0.08em">SLO · p99 ≤100ms</text>
        <text x="180" y="416" fontFamily="Geist" fontSize="12" fontWeight="500" fill="var(--ink)" textAnchor="end">met</text>
        <circle cx="208" cy="412" r="3.5" fill="var(--ok)"/>
      </g>
    </svg>
  );
};

/* ───────────── Topology · sphere of providers ───────────── */
const TopologyViz = () => {
  const [tick, setTick] = React.useState(0);
  React.useEffect(() => {
    const id = setInterval(() => setTick(t => (t + 1) % 6), 1100);
    return () => clearInterval(id);
  }, []);
  const nodes = [
    { x: 280, y:  60, label: 'openai',    p: 62 },
    { x: 460, y: 130, label: 'anthropic', p: 87 },
    { x: 470, y: 290, label: 'gemini',    p: 78 },
    { x: 280, y: 360, label: 'together',  p: 94 },
    { x: 100, y: 290, label: 'fireworks', p: 71 },
    { x:  90, y: 130, label: 'groq',      p: 41 },
  ];
  return (
    <svg viewBox="0 0 560 420" width="100%" style={{ display: 'block' }}>
      <defs>
        <pattern id="topDots" width="18" height="18" patternUnits="userSpaceOnUse">
          <circle cx="1" cy="1" r="1" fill="var(--rule-2)"/>
        </pattern>
      </defs>
      <rect width="560" height="420" fill="url(#topDots)" opacity="0.35"/>

      {/* spokes */}
      <g stroke="var(--rule-2)" strokeWidth="1">
        {nodes.map((n, i) => <line key={i} x1="280" y1="210" x2={n.x} y2={n.y}/>)}
      </g>

      {/* concentric rings */}
      <g stroke="var(--rule-2)" strokeWidth="1" fill="none" opacity="0.6">
        <circle cx="280" cy="210" r="90"/>
        <circle cx="280" cy="210" r="140"/>
      </g>

      {/* highlighted spoke */}
      {(() => {
        const n = nodes[tick];
        return (
          <line x1="280" y1="210" x2={n.x} y2={n.y} stroke="var(--signal)" strokeWidth="2" strokeLinecap="round"
                strokeDasharray="220" strokeDashoffset="220" key={tick}>
            <animate attributeName="stroke-dashoffset" from="220" to="0" dur="0.5s" fill="freeze"/>
          </line>
        );
      })()}

      {/* hub */}
      <g>
        <rect x="220" y="180" width="120" height="60" rx="6" fill="var(--ink)" stroke="var(--ink)"/>
        <text x="280" y="202" textAnchor="middle" fontFamily="Geist Mono" fontSize="9" fill="var(--graphite-2)" letterSpacing="0.10em">▸ BLOOM</text>
        <text x="280" y="222" textAnchor="middle" fontFamily="Geist" fontSize="16" fontWeight="500" fill="var(--paper)" letterSpacing="-0.01em">gateway</text>
        <circle cx="320" cy="234" r="2" fill="var(--signal)">
          <animate attributeName="opacity" values="1;0.3;1" dur="1.6s" repeatCount="indefinite"/>
        </circle>
      </g>

      {/* provider nodes */}
      {nodes.map((n, i) => {
        const active = i === tick;
        return (
          <g key={i}>
            <circle cx={n.x} cy={n.y} r={active ? 18 : 14}
                    fill={active ? 'var(--ink)' : 'var(--paper)'}
                    stroke="var(--ink)" strokeWidth="1.2"/>
            <text x={n.x} y={n.y + 4} textAnchor="middle" fontFamily="Geist Mono" fontSize="9"
                  fill={active ? 'var(--paper)' : 'var(--ink)'} letterSpacing="0.04em">{n.p}</text>
            <text x={n.x} y={n.y + (n.y > 210 ? 38 : -22)} textAnchor="middle" fontFamily="Geist" fontSize="13" fontWeight="500" fill="var(--ink)">{n.label}</text>
          </g>
        );
      })}

      {/* counter chip top-right */}
      <g>
        <rect x="404" y="22" width="138" height="32" rx="4" fill="var(--paper)" stroke="var(--ink)" strokeWidth="1"/>
        <text x="416" y="42" fontFamily="Geist Mono" fontSize="10" fill="var(--fg-3)" letterSpacing="0.08em">2.14M req/min</text>
        <circle cx="528" cy="38" r="3.5" fill="var(--signal)">
          <animate attributeName="opacity" values="1;0.4;1" dur="1.4s" repeatCount="indefinite"/>
        </circle>
      </g>
    </svg>
  );
};

/* ───────────── Latency histogram + savings bars ───────────── */
const LatencyViz = () => {
  // simulate a histogram + a savings bar chart
  const buckets = [4, 9, 18, 32, 56, 78, 92, 86, 64, 38, 22, 12, 7, 4, 2];
  const [pulse, setPulse] = React.useState(0);
  React.useEffect(() => {
    const id = setInterval(() => setPulse(p => (p + 1) % 15), 280);
    return () => clearInterval(id);
  }, []);
  const max = Math.max(...buckets);
  const W = 560, H = 420;
  return (
    <svg viewBox={`0 0 ${W} ${H}`} width="100%" style={{ display: 'block' }}>
      <defs>
        <pattern id="latDots" width="18" height="18" patternUnits="userSpaceOnUse">
          <circle cx="1" cy="1" r="1" fill="var(--rule-2)"/>
        </pattern>
      </defs>
      <rect width={W} height={H} fill="url(#latDots)" opacity="0.3"/>

      {/* card */}
      <g>
        <rect x="32" y="32" width={W - 64} height={H - 64} rx="6" fill="var(--paper)" stroke="var(--ink)" strokeWidth="1.2"/>
      </g>

      {/* header */}
      <g fontFamily="Geist Mono" fontSize="10" letterSpacing="0.10em" fill="var(--fg-3)">
        <text x="52" y="64">LATENCY DISTRIBUTION · LAST 1H</text>
        <text x={W - 52} y="64" textAnchor="end" fill="var(--signal-ink)">▸ p99 87ms</text>
      </g>
      <line x1="52" y1="76" x2={W - 52} y2="76" stroke="var(--border-1)"/>

      {/* y-axis ticks */}
      <g fontFamily="Geist Mono" fontSize="9" fill="var(--fg-3)">
        <text x="48" y="100" textAnchor="end">100</text>
        <text x="48" y="160" textAnchor="end">75</text>
        <text x="48" y="220" textAnchor="end">50</text>
        <text x="48" y="280" textAnchor="end">25</text>
      </g>

      {/* bars */}
      {buckets.map((b, i) => {
        const bw = (W - 100 - 32) / buckets.length;
        const x = 56 + i * bw + 2;
        const h = (b / max) * 200;
        const y = 300 - h;
        const isP99 = i === 11;
        return (
          <g key={i}>
            <rect x={x} y={y} width={bw - 4} height={h}
                  fill={isP99 ? 'var(--signal)' : (i === pulse ? 'var(--ink)' : 'var(--ink)')}
                  opacity={isP99 ? 1 : (i === pulse ? 1 : 0.85)}/>
          </g>
        );
      })}

      {/* x-axis line + p99 marker */}
      <line x1="52" y1="300" x2={W - 52} y2="300" stroke="var(--ink)" strokeWidth="1"/>
      {(() => {
        const bw = (W - 100 - 32) / buckets.length;
        const px = 56 + 11 * bw + (bw - 4) / 2 + 2;
        return (
          <g>
            <line x1={px} y1="80" x2={px} y2="306" stroke="var(--signal)" strokeDasharray="3 3" strokeWidth="1"/>
            <rect x={px - 30} y="82" width="60" height="20" rx="3" fill="var(--signal)"/>
            <text x={px} y="96" textAnchor="middle" fontFamily="Geist Mono" fontSize="10" fill="var(--ink)">p99</text>
          </g>
        );
      })()}

      {/* x labels */}
      <g fontFamily="Geist Mono" fontSize="9" fill="var(--fg-3)">
        <text x="58" y="318">0ms</text>
        <text x={W / 2} y="318" textAnchor="middle">100ms</text>
        <text x={W - 58} y="318" textAnchor="end">300ms</text>
      </g>

      {/* footer chips */}
      <g>
        <rect x="52" y="338" width="148" height="46" rx="4" fill="var(--paper-2)" stroke="var(--border-1)"/>
        <text x="64" y="356" fontFamily="Geist Mono" fontSize="9" fill="var(--fg-3)" letterSpacing="0.08em">CACHE HIT RATE</text>
        <text x="64" y="376" fontFamily="Geist" fontSize="18" fontWeight="500" fill="var(--ink)">41<tspan fontFamily="Geist Mono" fontSize="12" fill="var(--fg-3)">%</tspan></text>

        <rect x="208" y="338" width="148" height="46" rx="4" fill="var(--paper-2)" stroke="var(--border-1)"/>
        <text x="220" y="356" fontFamily="Geist Mono" fontSize="9" fill="var(--fg-3)" letterSpacing="0.08em">COST · LAST 1H</text>
        <text x="220" y="376" fontFamily="Geist" fontSize="18" fontWeight="500" fill="var(--ink)">$184<tspan fontFamily="Geist Mono" fontSize="12" fill="var(--fg-3)"> ↓41%</tspan></text>

        <rect x="364" y="338" width="148" height="46" rx="4" fill="var(--ink)" stroke="var(--ink)"/>
        <text x="376" y="356" fontFamily="Geist Mono" fontSize="9" fill="var(--graphite-2)" letterSpacing="0.08em">REQ ROUTED</text>
        <text x="376" y="376" fontFamily="Geist" fontSize="18" fontWeight="500" fill="var(--paper)">2.14<tspan fontFamily="Geist Mono" fontSize="12" fill="var(--graphite-2)">M/min</tspan></text>
      </g>
    </svg>
  );
};

/* ───────────── Stack · architecture sandwich (typographic) ───────────── */
const StackViz = () => {
  const layers = [
    { l: 'YOUR APP',           sub: 'one URL change · one HTTP header',    tone: 'paper' },
    { l: '▸ BLOOM GATEWAY',    sub: '01 observe · 02 route · 03 enforce · 04 score', tone: 'ink' },
    { l: '1,000+ MODELS',      sub: 'openai · anthropic · gemini · oss · vpc',    tone: 'paper' },
  ];
  return (
    <svg viewBox="0 0 560 420" width="100%" style={{ display: 'block' }}>
      <defs>
        <pattern id="stkDots" width="18" height="18" patternUnits="userSpaceOnUse">
          <circle cx="1" cy="1" r="1" fill="var(--rule-2)"/>
        </pattern>
      </defs>
      <rect width="560" height="420" fill="url(#stkDots)" opacity="0.3"/>

      {layers.map((ly, i) => {
        const y = 40 + i * 116;
        const ink = ly.tone === 'ink';
        return (
          <g key={i}>
            <rect x="40" y={y} width="480" height="96" rx="6"
                  fill={ink ? 'var(--ink)' : 'var(--paper)'}
                  stroke="var(--ink)" strokeWidth="1.2"/>
            <text x="60" y={y + 30} fontFamily="Geist Mono" fontSize="10"
                  fill={ink ? 'var(--graphite-2)' : 'var(--fg-3)'} letterSpacing="0.10em">LAYER {String(i+1).padStart(2,'0')}</text>
            <text x="60" y={y + 62} fontFamily="Geist" fontSize="28" fontWeight="500"
                  fill={ink ? 'var(--paper)' : 'var(--ink)'} letterSpacing="-0.02em">{ly.l}</text>
            <text x="60" y={y + 84} fontFamily="Geist Mono" fontSize="11"
                  fill={ink ? 'var(--graphite-2)' : 'var(--fg-3)'}>{ly.sub}</text>
            {ink && (
              <g>
                <circle cx="496" cy={y + 28} r="3" fill="var(--signal)">
                  <animate attributeName="opacity" values="1;0.3;1" dur="1.6s" repeatCount="indefinite"/>
                </circle>
                <text x="490" y={y + 31} textAnchor="end" fontFamily="Geist Mono" fontSize="9"
                      fill="var(--signal)" letterSpacing="0.10em">LIVE</text>
              </g>
            )}
          </g>
        );
      })}

      {/* connector arrows between layers */}
      <g stroke="var(--ink)" strokeWidth="1.2" fill="none" markerEnd="url(#stkArr)">
        <line x1="280" y1="138" x2="280" y2="154"/>
        <line x1="280" y1="254" x2="280" y2="270"/>
      </g>
      <defs>
        <marker id="stkArr" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
          <path d="M0,0 L10,5 L0,10 z" fill="var(--ink)"/>
        </marker>
      </defs>
    </svg>
  );
};

/* ───────────── Dashboard preview illustration ───────────── */
const DashboardViz = ({ compact = false } = {}) => {
  const PAD = compact ? 14 : 18;
  const ROW_PAD = compact ? '10px 4px' : '14px 4px';
  const HSIZE = compact ? 22 : 30;
  const NAME_COL = compact ? '140px' : '170px';
  const COST_COL = compact ? '88px' : '100px';
  const TRAIL_COL = compact ? '60px' : '70px';
  const ROW_FONT = compact ? 12 : 13;
  const BAR_H = compact ? 8 : 10;
  const customers = [
    { name: 'Acme Robotics',     cost: 28442, delta: -12, agents: [
      { a: 'support-bot',  c: 12428 },
      { a: 'docs-search',  c:  7964 },
      { a: 'onboarding',   c:  4551 },
      { a: 'reports',      c:  3499 },
    ]},
    { name: 'Northwind Health',  cost: 19711, delta:  -8, agents: [
      { a: 'triage-agent', c: 11432 },
      { a: 'intake-bot',   c:  5322 },
      { a: 'rx-lookup',    c:  2957 },
    ]},
    { name: 'Globex Finance',    cost: 14209, delta:   3, agents: [
      { a: 'docs-search',  c:  5826 },
      { a: 'risk-copilot', c:  4831 },
      { a: 'kyc-classify', c:  3552 },
    ]},
    { name: 'Stark Industries',  cost:  9803, delta: -14, agents: [
      { a: 'copilot',      c:  6078 },
      { a: 'spec-writer',  c:  3725 },
    ]},
    { name: 'Initech',           cost:  7124, delta:   2, agents: [
      { a: 'chat-v2',      c:  5058 },
      { a: 'summarizer',   c:  2066 },
    ]},
  ];

  // Flatten across all customers, group by agent name, sort desc — for "by agent" view
  const agentMap = {};
  customers.forEach(cust => {
    cust.agents.forEach(ag => {
      if (!agentMap[ag.a]) agentMap[ag.a] = { name: ag.a, cost: 0, customers: [] };
      agentMap[ag.a].cost += ag.c;
      agentMap[ag.a].customers.push({ name: cust.name, c: ag.c });
    });
  });
  const agents = Object.values(agentMap).sort((a, b) => b.cost - a.cost).slice(0, 6);

  const [view, setView] = React.useState('customer'); // 'customer' | 'agent'
  const total = useTicker(82371, () => Math.floor(Math.random() * 9) + 1, 1500, n => '$' + n.toLocaleString());

  const custMax = customers[0].cost;
  const agentMax = agents[0].cost;

  return (
    <div style={{ background: 'var(--paper)', border: '1px solid var(--border-1)', borderRadius: 6, padding: PAD, boxShadow: 'var(--shadow-1)' }}>
      <style>{`
        .dash-tabs { display: inline-flex; padding: 3px; background: var(--paper-2); border-radius: 999px; border: 1px solid var(--border-1); gap: 0; }
        .dash-tabs button {
          font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.10em; text-transform: uppercase;
          padding: 6px 14px; border: 0; background: transparent; cursor: pointer; color: var(--fg-3);
          border-radius: 999px; transition: background 200ms, color 200ms;
        }
        .dash-tabs button.active { background: var(--ink); color: var(--paper); }
        .dash-row { transition: opacity 280ms ease, transform 320ms cubic-bezier(.2,.7,.2,1); }
        .dash-row.entering { opacity: 0; transform: translateY(6px); }
        .dash-row.leaving  { opacity: 0; transform: translateY(-6px); }
        .dash-bar-fill { transition: width 480ms cubic-bezier(.2,.7,.2,1), background 280ms; }
        .dash-bar-track { position: relative; height: 10px; background: var(--paper-2); border-radius: 999px; overflow: hidden; }
      `}</style>

      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', padding: '0 4px 14px', borderBottom: '1px solid var(--border-1)', marginBottom: 14, gap: 12, flexWrap: 'wrap' }}>
        <div>
          <div style={{ fontFamily: 'var(--font-mono)', fontSize: 10, letterSpacing: '0.10em', color: 'var(--fg-3)', textTransform: 'uppercase' }}>
            Spend · {view === 'customer' ? 'by customer' : 'by agent'} · last 24h
          </div>
          <div className="tabular" style={{ fontFamily: 'var(--font-display)', fontSize: HSIZE, fontWeight: 500, letterSpacing: '-0.02em', marginTop: 2 }}>{total}</div>
        </div>
        <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
          <div className="dash-tabs" role="tablist">
            <button role="tab" aria-selected={view === 'customer'} className={view === 'customer' ? 'active' : ''} onClick={() => setView('customer')}>By customer</button>
            <button role="tab" aria-selected={view === 'agent'}    className={view === 'agent'    ? 'active' : ''} onClick={() => setView('agent')}>By agent</button>
          </div>
          <span style={{ display: 'inline-flex', alignItems: 'center', gap: 6, fontFamily: 'var(--font-mono)', fontSize: 10, color: 'var(--signal-ink)', letterSpacing: '0.08em', textTransform: 'uppercase' }}>
            <span style={{ width: 6, height: 6, borderRadius: 999, background: 'var(--signal)', boxShadow: '0 0 0 3px rgba(1,187,244,0.18)' }}/>LIVE
          </span>
        </div>
      </div>

      {/* column headers */}
      <div style={{ display: 'grid', gridTemplateColumns: `${NAME_COL} 1fr ${COST_COL} ${TRAIL_COL}`, gap: 14, alignItems: 'center', padding: '0 4px 10px', fontFamily: 'var(--font-mono)', fontSize: 10, textTransform: 'uppercase', letterSpacing: '0.08em', color: 'var(--fg-3)' }}>
        <div>{view === 'customer' ? 'Customer' : 'Agent'}</div>
        <div>Share of spend</div>
        <div style={{ textAlign: 'right' }}>Cost</div>
        <div style={{ textAlign: 'right' }}>{view === 'customer' ? 'Δ vs avg' : 'Customers'}</div>
      </div>

      {/* rows — keyed on view so React mounts a fresh set; CSS handles enter animation */}
      <div key={view} style={{ display: 'flex', flexDirection: 'column' }}>
        {(view === 'customer' ? customers : agents).map((r, i) => {
          const cost = r.cost;
          const max = view === 'customer' ? custMax : agentMax;
          const widthPct = (cost / max) * 100;
          const trail = view === 'customer' ? (
            <div className={'tabular ' + (r.delta < 0 ? 'delta-down' : 'delta-up')}
                 style={{ fontFamily: 'var(--font-mono)', fontSize: ROW_FONT, textAlign: 'right' }}>
              {r.delta < 0 ? '↓' : '↑'} {Math.abs(r.delta)}%
            </div>
          ) : (
            <div style={{ fontFamily: 'var(--font-mono)', fontSize: ROW_FONT, textAlign: 'right', color: 'var(--fg-2)' }}>
              {r.customers.length}
            </div>
          );
          return (
            <div key={r.name}
                 className="dash-row"
                 style={{
                   display: 'grid',
                   gridTemplateColumns: `${NAME_COL} 1fr ${COST_COL} ${TRAIL_COL}`,
                   gap: 14,
                   alignItems: 'center',
                   padding: ROW_PAD,
                   borderTop: '1px solid var(--border-1)',
                   animation: 'dashIn 360ms ' + (i * 35) + 'ms cubic-bezier(.2,.7,.2,1) backwards',
                 }}>
              <div style={{ fontSize: ROW_FONT, fontWeight: 500, color: 'var(--ink)' }}>{r.name}</div>
              <div className="dash-bar-track" style={{ height: BAR_H }}>
                <div className="dash-bar-fill"
                     style={{
                       position: 'absolute', inset: 0, right: 'auto',
                       width: widthPct + '%',
                       background: view === 'customer' ? 'var(--signal)' : 'var(--ink)',
                       borderRadius: 999,
                     }}/>
              </div>
              <div className="tabular" style={{ fontFamily: 'var(--font-mono)', fontSize: ROW_FONT, textAlign: 'right' }}>${cost.toLocaleString()}</div>
              {trail}
            </div>
          );
        })}
      </div>
      <style>{`@keyframes dashIn { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: translateY(0); } }`}</style>

      <div style={{ marginTop: 14, paddingTop: 12, borderTop: '1px solid var(--border-1)', display: 'flex', justifyContent: 'space-between', fontFamily: 'var(--font-mono)', fontSize: 10, color: 'var(--fg-3)', letterSpacing: '0.04em' }}>
        <span>{view === 'customer' ? '5 of 247 customers' : '6 of 14 agents'} · attributed via x-customer-id</span>
        <span>updated just now</span>
      </div>
    </div>
  );
};

/* ───────────── Flow viz (request → gateway → response) ───────────── */
const FlowViz = () => {
  const reqId = useTicker(8412091, 1, 900, n => 'req_' + n.toString(16));
  const lat = useTicker(180, () => Math.floor(Math.random() * 12) - 6, 1200, n => Math.max(140, Math.min(220, n)) + 'ms');
  const lines = [
    { t: '00.000', e: 'POST /v1/chat/completions',   c: 'k' },
    { t: '00.002', e: 'auth · x-customer-id=acme_42', c: 'g' },
    { t: '00.004', e: 'cache lookup · semantic miss',  c: 'g' },
    { t: '00.008', e: 'route → us-east-1 · openai',    c: 'k' },
    { t: '00.142', e: 'guardrails · pii redacted (1)', c: 'g' },
    { t: '00.183', e: 'eval · score 0.94 · ok',        c: 'g' },
    { t: '00.187', e: 'response 200 · 412 tok · $0.0021', c: 'k' },
  ];
  return (
    <div style={{ background: 'var(--ink)', color: 'var(--paper)', borderRadius: 6, padding: 22, boxShadow: 'var(--shadow-pop)' }}>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', marginBottom: 14 }}>
        <div style={{ fontFamily: 'var(--font-mono)', fontSize: 10, color: 'var(--graphite-2)', letterSpacing: '0.10em', textTransform: 'uppercase' }}>TRACE · {reqId}</div>
        <div className="tabular" style={{ fontFamily: 'var(--font-mono)', fontSize: 11, color: 'var(--signal)' }}>{lat}</div>
      </div>
      <div style={{ fontFamily: 'var(--font-mono)', fontSize: 12, lineHeight: 1.85, color: 'var(--graphite-2)' }}>
        {lines.map((l, i) => (
          <div key={i} style={{ display: 'flex', gap: 14 }}>
            <span style={{ color: 'var(--graphite-2)', opacity: 0.7, minWidth: 64 }}>{l.t}</span>
            <span style={{ color: l.c === 'k' ? 'var(--paper)' : 'var(--graphite-2)' }}>{l.e}</span>
          </div>
        ))}
      </div>
      <div style={{ display: 'flex', gap: 18, marginTop: 18, paddingTop: 14, borderTop: '1px solid rgba(255,255,255,0.08)', fontFamily: 'var(--font-mono)', fontSize: 11, color: 'var(--graphite-2)' }}>
        <span>cache: <span style={{ color: 'var(--paper)' }}>miss</span></span>
        <span>·</span>
        <span>route: <span style={{ color: 'var(--paper)' }}>us-east-1</span></span>
        <span>·</span>
        <span>tokens: <span style={{ color: 'var(--signal)' }}>412</span></span>
        <span>·</span>
        <span>cost: <span style={{ color: 'var(--paper)' }}>$0.0021</span></span>
      </div>
    </div>
  );
};

window.Mark = Mark;
window.Icon = Icon;
window.Announce = Announce;
window.SiteNav = Nav;
window.SiteFooter = Footer;
window.RouteDiagram = RouteDiagram;
window.DashboardViz = DashboardViz;
window.FlowViz = FlowViz;
window.TopologyViz = TopologyViz;
window.LatencyViz = LatencyViz;
window.StackViz = StackViz;
window.useTicker = useTicker;
