// mv-brand.jsx — ModVedi brand layer
// Tokens, typography, shared primitives (Nav, Eyebrow, Button, KeyFigure),
// and the thin-line "measurement field" graphic family.
// These values MIRROR the ModVedi Design System tokens (_ds/.../tokens/colors.css),
// which every page now links as the bound source of truth. Kept as hex (not var())
// because the field graphics pass them as SVG presentation attributes, where
// CSS custom properties don't apply. If a token changes in the DS, update here too.

const MV = {
  navy: '#081E34',        // --color-navy / navy-700
  navyDeep: '#040F1A',    // --color-navy-900
  cream: '#F4F3EF',       // --color-cream
  gold: '#C8A45D',        // --color-gold
  goldHover: '#B89249',
  slate: '#2D2D2D',       // --color-charcoal (DS body text — never pure black)
  serif: "'Cormorant Garamond', Georgia, 'Times New Roman', serif",
  sans: "'Inter', system-ui, -apple-system, sans-serif",
  // text-on-navy helpers
  creamDim: 'rgba(244,243,239,0.66)',
  creamFaint: 'rgba(244,243,239,0.40)',
  hair: 'rgba(244,243,239,0.14)',
  hairNavy: 'rgba(8,30,52,0.12)',
};

// One shared render size for every hero/section field, so the graphic reads
// the same size on every page. Smaller than the old homepage figure, larger
// than the old interior figures. Same 1000:900 aspect as every field's viewBox.
const MV_FIELD_W = 1180;
const MV_FIELD_H = 1062;

// Positioning wrapper for every thin-line field. Flat (no 3D) — just absolute
// placement; any caller transform (centering, the homepage X rotation) passes through.
function field3d(style) {
  const { transform, ...rest } = style || {};
  return {
    position: 'absolute', pointerEvents: 'none', transformOrigin: 'center',
    ...rest,
    ...(transform ? { transform } : {}),
  };
}

if (typeof document !== 'undefined' && !document.getElementById('mv-styles')) {
  const s = document.createElement('style');
  s.id = 'mv-styles';
  s.textContent = `
    .mv-root{font-family:${MV.sans};font-size:14px;line-height:1.6;color:${MV.slate};
      -webkit-font-smoothing:antialiased;height:100%;position:relative;overflow:hidden}
    .mv-root *{box-sizing:border-box}
    .mv-serif{font-family:${MV.serif}}
    .mv-eyebrow{font-family:${MV.sans};font-size:11px;font-weight:600;letter-spacing:.22em;
      text-transform:uppercase;color:${MV.gold};display:inline-flex;align-items:center;gap:12px}
    .mv-eyebrow::before{content:"";width:26px;height:1px;background:${MV.gold};display:inline-block}
    .mv-link{color:inherit;text-decoration:none;position:relative;transition:color .2s}
    .mv-navlink{font-size:12px;font-weight:500;letter-spacing:.04em;color:inherit;
      text-decoration:none;padding-bottom:3px;transition:color .2s,border-color .2s;
      border-bottom:1px solid transparent}
    .mv-navlink:hover{color:${MV.gold};border-color:${MV.gold}}
    .mv-btn{display:inline-flex;align-items:center;gap:10px;font-family:${MV.sans};white-space:nowrap;
      font-size:12px;font-weight:600;letter-spacing:.04em;padding:13px 22px;border-radius:2px;
      cursor:pointer;text-decoration:none;transition:border-color .2s,color .2s,background .2s;
      background:transparent}
    .mv-btn-navy{border:1px solid ${MV.hair};color:${MV.cream}}
    .mv-btn-navy:hover{border-color:${MV.gold};color:${MV.gold}}
    .mv-btn-cream{border:1px solid ${MV.hairNavy};color:${MV.navy}}
    .mv-btn-cream:hover{border-color:${MV.gold};color:${MV.goldHover}}
    .mv-textlink{display:inline-flex;align-items:center;gap:8px;font-size:12px;font-weight:600;white-space:nowrap;
      letter-spacing:.04em;color:${MV.gold};text-decoration:none;transition:gap .2s,color .2s}
    .mv-textlink:hover{gap:13px;color:${MV.goldHover}}
    /* placeholder figure marker */
    .mv-ph{border-bottom:1.5px dashed rgba(200,164,93,0.6);padding-bottom:1px;cursor:help}
    .mv-arc{transform-origin:center;animation:mv-spin 48s linear infinite}
    @keyframes mv-spin{to{transform:rotate(360deg)}}
    .mv-trace{animation:mv-trace 14s linear infinite}
    @keyframes mv-trace{to{stroke-dashoffset:-100}}
    .mv-pulse{transform-box:fill-box;transform-origin:center;animation:mv-pulse 4.6s ease-out infinite}
    .mv-pulse-2{animation-delay:2.3s}
    @keyframes mv-pulse{0%{transform:scale(.5);opacity:.5}70%{opacity:0}100%{transform:scale(1.55);opacity:0}}
    .mv-spin-slow{transform-box:fill-box;transform-origin:center;animation:mv-spin 120s linear infinite}
    .mv-revolve{animation:mv-revolve 44s ease-in-out infinite}
    @keyframes mv-revolve{0%,50%,100%{rx:248px}25%,75%{rx:6px}}
    @media (prefers-reduced-motion: reduce){.mv-arc,.mv-trace,.mv-pulse,.mv-spin-slow,.mv-revolve{animation:none}}
  `;
  document.head.appendChild(s);
}

// ── Top navigation ───────────────────────────────────────────
function MVNav({ theme = 'navy', style = {} }) {
  const onNavy = theme === 'navy';
  const wordColor = onNavy ? MV.cream : MV.navy;
  const linkColor = onNavy ? MV.creamDim : MV.slate;
  const rule = onNavy ? MV.hair : MV.hairNavy;
  const items = ['Strategies', 'Advisory', 'Sectors', 'Notes'];
  return (
    <nav style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between',
      padding: '34px 80px', borderBottom: `1px solid ${rule}`, ...style }}>
      <div className="mv-serif" style={{ fontSize: 27, fontWeight: 600, letterSpacing: '.01em',
        color: wordColor }}>ModVedi</div>
      <div style={{ display: 'flex', alignItems: 'center', gap: 38 }}>
        {items.map((t) => (
          <a key={t} className="mv-navlink" href="#" style={{ color: linkColor }}>{t}</a>
        ))}
        <a className="mv-navlink" href="#" style={{ color: onNavy ? MV.cream : MV.navy, fontWeight: 600 }}>Contact</a>
      </div>
    </nav>
  );
}

function MVEyebrow({ children, style = {} }) {
  return <div className="mv-eyebrow" style={style}>{children}</div>;
}

function MVArrow({ color = MV.gold }) {
  return (
    <svg width="16" height="10" viewBox="0 0 16 10" fill="none" stroke={color} strokeWidth="1.4" strokeLinecap="round" strokeLinejoin="round">
      <path d="M1 5h13M10 1l4 4-4 4" />
    </svg>
  );
}

// A clearly-marked placeholder figure. Shows a dashed underline + tooltip.
function PH({ children }) {
  return <span className="mv-ph" title="Placeholder figure — replace before publishing">{children}</span>;
}

// ── Measurement field: thin-line geometric backdrop ──────────
// variant: 'rings' | 'crosshair' | 'arc'. on: 'navy' | 'cream'.
// Returns an absolutely-positioned SVG meant to bleed off the right edge.
function MeasurementField({ variant = 'rings', on = 'navy', style = {}, innerRef }) {
  const line = on === 'navy' ? 'rgba(244,243,239,0.13)' : 'rgba(8,30,52,0.10)';
  const lineSoft = on === 'navy' ? 'rgba(244,243,239,0.07)' : 'rgba(8,30,52,0.06)';
  const gold = MV.gold;
  const C = 500, Cy = 420;

  const rings = (
    <g stroke={line} strokeWidth="1" fill="none">
      {[90, 170, 250, 330, 410, 490].map((r) => <circle key={r} cx={C} cy={Cy} r={r} />)}
    </g>
  );
  const crosshair = (
    <g stroke={lineSoft} strokeWidth="1">
      <line x1={C} y1={Cy - 520} x2={C} y2={Cy + 520} />
      <line x1={C - 560} y1={Cy} x2={C + 560} y2={Cy} />
      {/* tick marks along the horizontal axis */}
      <g stroke={line}>
        {[-410, -330, -250, -170, -90, 90, 170, 250, 330, 410].map((d) => (
          <line key={d} x1={C + d} y1={Cy - 7} x2={C + d} y2={Cy + 7} />
        ))}
      </g>
    </g>
  );
  const nodes = (
    <g fill={gold}>
      <circle cx={C} cy={Cy - 250} r="3.5" />
      <circle cx={C + 330} cy={Cy} r="3.5" />
      <circle cx={C} cy={Cy + 170} r="3.5" />
      <circle cx={C - 170} cy={Cy} r="2.5" />
    </g>
  );
  const goldArc = (
    <g className="mv-arc" style={{ transformBox: 'fill-box' }}>
      <circle cx={C} cy={Cy} r="290" fill="none" stroke={gold} strokeWidth="1.4"
        strokeDasharray="2 13" opacity="0.55" />
    </g>
  );
  const centerDot = <circle cx={C} cy={Cy} r="2.5" fill={on === 'navy' ? MV.creamFaint : MV.hairNavy} />;

  return (
    <svg ref={innerRef} viewBox="0 0 1000 900" width="1000" height="900"
      style={field3d(style)} aria-hidden="true">
      {(variant === 'rings' || variant === 'arc') && rings}
      {(variant === 'crosshair') && (
        <g stroke={line} strokeWidth="1" fill="none">
          {[150, 300, 450].map((r) => <circle key={r} cx={C} cy={Cy} r={r} />)}
        </g>
      )}
      {crosshair}
      {goldArc}
      {variant === 'arc' && (
        <g className="mv-arc" style={{ transformBox: 'fill-box', animationDuration: '72s', animationDirection: 'reverse' }}>
          <circle cx={C} cy={Cy} r="180" fill="none" stroke={gold} strokeWidth="1" strokeDasharray="1 18" opacity="0.5" />
        </g>
      )}
      {nodes}
      {centerDot}
    </svg>
  );
}

// ── Held-orbit field: a thin-line system of holdings (About) ──
// The firm sits at the center as a gold anchor. A few companies are held
// in stable concentric orbits, each tethered back to the center by a
// hairline. Nothing drifts away. Reads as permanence, concentration, and
// stewardship: we buy, improve, and hold.
function OrbitField({ on = 'navy', style = {}, innerRef }) {
  const line = on === 'navy' ? 'rgba(244,243,239,0.15)' : 'rgba(8,30,52,0.12)';
  const lineSoft = on === 'navy' ? 'rgba(244,243,239,0.06)' : 'rgba(8,30,52,0.05)';
  const gold = MV.gold;
  const Cx = 500, Cy = 430;
  const rings = [150, 252, 354];
  // companies held on the orbits: [ringIndex, angleDeg]
  const held = [
    [0, -58], [0, 150],
    [1, -18], [1, 108], [1, -150],
    [2, 32], [2, -110],
  ];
  const pos = (ri, deg) => {
    const r = rings[ri], a = (deg * Math.PI) / 180;
    return [Cx + r * Math.cos(a), Cy + r * Math.sin(a)];
  };
  return (
    <svg ref={innerRef} viewBox="0 0 1000 900" width="1000" height="900"
      style={field3d(style)} aria-hidden="true">
      {/* faint crosshair datum through the center */}
      <g stroke={lineSoft} strokeWidth="1">
        <line x1={Cx} y1={Cy - 430} x2={Cx} y2={Cy + 430} />
        <line x1={Cx - 470} y1={Cy} x2={Cx + 470} y2={Cy} />
      </g>
      {/* orbit rings */}
      <g fill="none" stroke={line} strokeWidth="1">
        {rings.map((r) => <circle key={r} cx={Cx} cy={Cy} r={r} />)}
      </g>
      {/* the long-horizon ring, dashed, slowly rotating */}
      <g className="mv-arc" style={{ transformBox: 'fill-box', animationDuration: '88s' }}>
        <circle cx={Cx} cy={Cy} r="440" fill="none" stroke={gold} strokeWidth="1"
          strokeDasharray="1 20" opacity="0.42" />
      </g>
      {/* tethers from center to each held company */}
      <g stroke={line} strokeWidth="1" opacity="0.6">
        {held.map(([ri, deg], i) => {
          const [x, y] = pos(ri, deg);
          return <line key={i} x1={Cx} y1={Cy} x2={x} y2={y} />;
        })}
      </g>
      {/* one company mid-transit: a short gold arc trace on ring 1 */}
      <path className="mv-trace" d={describeArc(Cx, Cy, rings[1], -18, 78)} fill="none"
        stroke={gold} strokeWidth="1.6" opacity="0.8" pathLength="100" strokeDasharray="22 78" />
      {/* held companies */}
      {held.map(([ri, deg], i) => {
        const [x, y] = pos(ri, deg);
        return (
          <g key={i}>
            <circle cx={x} cy={y} r="9" fill="none" stroke={gold} strokeWidth="1" opacity="0.35" />
            <circle cx={x} cy={y} r="3.6" fill={gold} />
          </g>
        );
      })}
      {/* the firm: a gold anchor at the center */}
      <circle cx={Cx} cy={Cy} r="16" fill="none" stroke={gold} strokeWidth="1" opacity="0.45" />
      <circle cx={Cx} cy={Cy} r="6.5" fill={gold} />
    </svg>
  );
}

// small helper: an SVG arc path from startDeg to endDeg on a circle
function describeArc(cx, cy, r, startDeg, endDeg) {
  const p = (deg) => {
    const a = (deg * Math.PI) / 180;
    return [cx + r * Math.cos(a), cy + r * Math.sin(a)];
  };
  const [x1, y1] = p(startDeg);
  const [x2, y2] = p(endDeg);
  const large = Math.abs(endDeg - startDeg) > 180 ? 1 : 0;
  const sweep = endDeg > startDeg ? 1 : 0;
  return `M ${x1} ${y1} A ${r} ${r} 0 ${large} ${sweep} ${x2} ${y2}`;
}

// ── Span field: a thin-line suspension bridge ────────────────
// Same measurement-drawing family as MeasurementField (hairline strokes,
// gold nodes), but the subject is a bridge: five piers for five sectors,
// a parabolic main cable, vertical hangers, a faint datum below.
function BridgeField({ on = 'navy', style = {}, innerRef }) {
  const line = on === 'navy' ? 'rgba(244,243,239,0.13)' : 'rgba(8,30,52,0.10)';
  const lineSoft = on === 'navy' ? 'rgba(244,243,239,0.07)' : 'rgba(8,30,52,0.06)';
  const gold = MV.gold;

  const deckY = 470, anchorY = 452, topY = 206, baseY = 560;
  const xL = 70, xR = 970;            // anchorages
  const t1 = 360, t2 = 700;           // tower x
  const midX = (t1 + t2) / 2, midY = 372;
  const a = (topY - midY) / Math.pow(t1 - midX, 2); // parabola through tower tops + mid
  const cableY = (x) => {
    if (x <= t1) return anchorY + (topY - anchorY) * (x - xL) / (t1 - xL); // straight side span
    if (x >= t2) return topY + (anchorY - topY) * (x - t2) / (xR - t2);
    return a * Math.pow(x - midX, 2) + midY;        // main-span parabola
  };
  // hangers across the whole run
  const hangers = [];
  for (let x = xL + 40; x < xR; x += 46) hangers.push(x);
  // five gold pier markers along the deck = five sectors
  const piers = [xL + 150, t1, midX, t2, xR - 150];

  return (
    <svg ref={innerRef} viewBox="0 0 1000 900" width="1000" height="900"
      style={field3d(style)} aria-hidden="true">
      {/* faint measurement grid + datum line, keeps the family resemblance */}
      <g stroke={lineSoft} strokeWidth="1">
        {[xL, t1, midX, t2, xR].map((x) => <line key={'v' + x} x1={x} y1={topY - 40} x2={x} y2={baseY + 70} />)}
        <line x1={xL - 30} y1={600} x2={xR + 30} y2={600} />
      </g>
      <g stroke={line} strokeWidth="1">
        {/* datum ticks */}
        {hangers.map((x) => <line key={'t' + x} x1={x} y1={596} x2={x} y2={604} />)}
      </g>

      {/* hangers */}
      <g stroke={line} strokeWidth="1">
        {hangers.map((x) => <line key={'h' + x} x1={x} y1={cableY(x)} x2={x} y2={deckY} />)}
      </g>

      {/* main cable */}
      <path d={`M ${xL} ${anchorY} L ${t1} ${topY} Q ${midX} ${2 * midY - topY} ${t2} ${topY} L ${xR} ${anchorY}`}
        fill="none" stroke={line} strokeWidth="1.4" />
      {/* slow gold survey trace drawing along the cable */}
      <path className="mv-trace" d={`M ${xL} ${anchorY} L ${t1} ${topY} Q ${midX} ${2 * midY - topY} ${t2} ${topY} L ${xR} ${anchorY}`}
        fill="none" stroke={gold} strokeWidth="1.4" opacity="0.6"
        pathLength="100" strokeDasharray="14 86" />

      {/* deck */}
      <g stroke={line}>
        <line x1={xL} y1={deckY} x2={xR} y2={deckY} strokeWidth="1.4" />
        <line x1={xL} y1={deckY + 6} x2={xR} y2={deckY + 6} strokeWidth="1" stroke={lineSoft} />
      </g>

      {/* towers */}
      <g stroke={line} strokeWidth="1.4">
        <line x1={t1} y1={topY} x2={t1} y2={baseY} />
        <line x1={t2} y1={topY} x2={t2} y2={baseY} />
        {/* tower cross-braces */}
        <line x1={t1 - 11} y1={300} x2={t1 + 11} y2={300} strokeWidth="1" />
        <line x1={t2 - 11} y1={300} x2={t2 + 11} y2={300} strokeWidth="1" />
      </g>

      {/* gold nodes: tower tops, midspan, anchorages, five piers */}
      <g fill={gold}>
        <circle cx={t1} cy={topY} r="3.5" />
        <circle cx={t2} cy={topY} r="3.5" />
        <circle cx={midX} cy={midY} r="3" />
        {piers.map((x) => <circle key={'p' + x} cx={x} cy={deckY} r="3" />)}
      </g>
      <g fill={on === 'navy' ? MV.creamFaint : MV.hairNavy}>
        <circle cx={xL} cy={anchorY} r="2.5" />
        <circle cx={xR} cy={anchorY} r="2.5" />
      </g>
    </svg>
  );
}

// ── Summit field: a thin-line mountain (About / vision) ──────
// A surveyed peak that reads clearly as a mountain: one strong ridgeline,
// a back range for depth, an ascending route to the summit, and a single
// clean sightline from the summit out to a distant target on the horizon —
// the firm looking ahead. Vision, plainly drawn.
function MountainField({ on = 'navy', style = {}, innerRef }) {
  const line = on === 'navy' ? 'rgba(244,243,239,0.16)' : 'rgba(8,30,52,0.12)';
  const lineSoft = on === 'navy' ? 'rgba(244,243,239,0.07)' : 'rgba(8,30,52,0.06)';
  const gold = MV.gold;
  const horizon = 560;
  const summit = [520, 196];
  // one clear, legible mountain silhouette
  const ridge = '50,560 200,470 300,506 410,388 520,196 626,360 712,322 836,452 980,560';
  const back = '50,560 210,514 360,478 500,432 620,360 760,420 880,482 980,524';
  const route = 'M 250 560 L 332 502 L 404 472 L 462 372 L 500 300 L ' + summit.join(' ');
  const target = [772, 256];
  return (
    <svg ref={innerRef} viewBox="0 0 1000 900" width="1000" height="900"
      style={field3d(style)} aria-hidden="true">
      {/* horizon datum */}
      <line x1="10" y1={horizon} x2="990" y2={horizon} stroke={lineSoft} strokeWidth="1" />
      {/* depth: a back range */}
      <polyline points={back} fill="none" stroke={lineSoft} strokeWidth="1" />
      {/* primary mountain */}
      <polyline points={ridge} fill="none" stroke={line} strokeWidth="1.5" />
      {/* sightline from summit to a distant target — the firm's view ahead */}
      <line x1={summit[0]} y1={summit[1]} x2={target[0]} y2={target[1]} stroke={line} strokeWidth="1" opacity="0.7" />
      <g fill="none" stroke={gold} strokeWidth="1.2">
        <circle cx={target[0]} cy={target[1]} r="15" opacity="0.55" />
        <circle cx={target[0]} cy={target[1]} r="7" opacity="0.8" />
      </g>
      <circle cx={target[0]} cy={target[1]} r="2.6" fill={gold} />
      {/* ascending route to the summit */}
      <path className="mv-trace" d={route} fill="none" stroke={gold} strokeWidth="1.6"
        opacity="0.78" pathLength="100" strokeDasharray="16 84" />
      {/* summit marker — clearly the peak */}
      <g fill="none" stroke={gold} strokeWidth="1">
        <circle cx={summit[0]} cy={summit[1]} r="11" opacity="0.4" />
      </g>
      <circle cx={summit[0]} cy={summit[1]} r="4.2" fill={gold} />
      <circle cx="250" cy="560" r="2.6" fill={on === 'navy' ? MV.creamFaint : MV.hairNavy} />
    </svg>
  );
}

// ── World field: a thin-line wireframe globe (Strategies) ─────
function GlobeField({ on = 'navy', style = {}, innerRef }) {
  const line = on === 'navy' ? 'rgba(244,243,239,0.13)' : 'rgba(8,30,52,0.10)';
  const lineSoft = on === 'navy' ? 'rgba(244,243,239,0.07)' : 'rgba(8,30,52,0.06)';
  const gold = MV.gold;
  const Cx = 552, Cy = 380, R = 304;
  const lat = [-180, -90, 0, 90, 180];
  const lon = [44, 124, 196, 248];
  return (
    <svg ref={innerRef} viewBox="0 0 1000 900" width="1000" height="900"
      style={field3d(style)} aria-hidden="true">
      <circle cx={Cx} cy={Cy} r={R} fill="none" stroke={line} strokeWidth="1.4" />
      <g transform={`rotate(-15 ${Cx} ${Cy})`}>
        {/* latitudes (the sphere stays put) */}
        {lat.map((d) => {
          const rx = Math.sqrt(Math.max(R * R - d * d, 1));
          return <ellipse key={'la' + d} cx={Cx} cy={Cy + d} rx={rx} ry={rx * 0.16}
            fill="none" stroke={d === 0 ? line : lineSoft} strokeWidth="1" />;
        })}
        {/* meridians revolve around the polar axis (sweep, do not tumble) */}
        {[248, 168, 88, 168, 248].map((rx0, i) => (
          <ellipse key={'lo' + i} className="mv-revolve" cx={Cx} cy={Cy} rx={rx0} ry={R}
            fill="none" stroke={lineSoft} strokeWidth="1" style={{ animationDelay: `-${i * 4}s` }} />
        ))}
        {/* polar axis */}
        <line x1={Cx} y1={Cy - R} x2={Cx} y2={Cy + R} stroke={lineSoft} strokeWidth="1" />
        <line x1={Cx} y1={Cy - R - 26} x2={Cx} y2={Cy + R + 26} stroke={line} strokeWidth="1" opacity="0.5" />
      </g>
      {/* routes between locations */}
      <g fill="none" stroke={gold} strokeWidth="1.3" opacity="0.62">
        <path d="M 452 296 Q 560 232 664 332" />
        <path className="mv-trace" d="M 664 332 Q 660 452 556 506" pathLength="100" strokeDasharray="14 86" />
      </g>
      <g fill={gold}>
        <circle cx="452" cy="296" r="3.6" />
        <circle cx="664" cy="332" r="3.6" />
        <circle cx="556" cy="506" r="3.2" />
      </g>
    </svg>
  );
}

// ── Data field: axes, a plotted series, a small network (Insights) ──
function DataField({ on = 'navy', style = {}, innerRef }) {
  const line = on === 'navy' ? 'rgba(244,243,239,0.13)' : 'rgba(8,30,52,0.10)';
  const lineSoft = on === 'navy' ? 'rgba(244,243,239,0.07)' : 'rgba(8,30,52,0.06)';
  const gold = MV.gold;
  const ax = 150, ay = 624;
  const pts = [[150, 542], [262, 470], [374, 506], [486, 372], [598, 410], [710, 292], [822, 244], [930, 300]];
  const dStr = 'M ' + pts.map((p) => p.join(' ')).join(' L ');
  const net = [[660, 178], [758, 150], [712, 246]];
  // extremely subtle binary texture behind the chart (Insights: notes + research)
  const bits = [];
  for (let gy = 150; gy <= 612; gy += 32) {
    for (let gx = 70; gx <= 936; gx += 38) {
      if ((gx * 7 + gy * 5) % 3 !== 0) continue;
      bits.push({ x: gx, y: gy, c: ((gx * 13 + gy * 11) % 7) % 2 ? '1' : '0' });
    }
  }
  const bitFill = on === 'navy' ? 'rgba(244,243,239,1)' : 'rgba(8,30,52,1)';
  return (
    <svg ref={innerRef} viewBox="0 0 1000 900" width="1000" height="900"
      style={field3d(style)} aria-hidden="true">
      {/* subtle 0/1 matrix texture */}
      <g fill={bitFill} fillOpacity="0.05" style={{ font: '13px ui-monospace, SFMono-Regular, Menlo, monospace' }}>
        {bits.map((b, i) => <text key={i} x={b.x} y={b.y}>{b.c}</text>)}
      </g>
      {/* gridlines */}
      <g stroke={lineSoft} strokeWidth="1">
        {[260, 340, 420, 500, 580].map((y) => <line key={'g' + y} x1={ax} y1={y} x2={950} y2={y} />)}
        {[262, 374, 486, 598, 710, 822, 930].map((x) => <line key={'v' + x} x1={x} y1={176} x2={x} y2={ay} />)}
      </g>
      {/* axes */}
      <g stroke={line} strokeWidth="1.3">
        <line x1={ax} y1={170} x2={ax} y2={ay} />
        <line x1={ax} y1={ay} x2={958} y2={ay} />
      </g>
      {/* series */}
      <path d={dStr} fill="none" stroke={line} strokeWidth="1.4" />
      <path className="mv-trace" d={dStr} fill="none" stroke={gold} strokeWidth="1.6" opacity="0.7"
        pathLength="100" strokeDasharray="12 88" />
      <g fill={gold}>{pts.map((p, i) => <circle key={i} cx={p[0]} cy={p[1]} r={i % 2 ? 2.6 : 3.4} />)}</g>
      {/* small network */}
      <g stroke={gold} strokeWidth="1" opacity="0.5">
        <line x1={net[0][0]} y1={net[0][1]} x2={net[1][0]} y2={net[1][1]} />
        <line x1={net[1][0]} y1={net[1][1]} x2={net[2][0]} y2={net[2][1]} />
        <line x1={net[0][0]} y1={net[0][1]} x2={net[2][0]} y2={net[2][1]} />
      </g>
      <g fill={on === 'navy' ? MV.creamFaint : MV.hairNavy}>{net.map((p, i) => <circle key={i} cx={p[0]} cy={p[1]} r="2.6" />)}</g>
    </svg>
  );
}

// ── Connection field: people linked in a quiet web (Contact) ──
function ConnectionField({ on = 'navy', style = {}, innerRef }) {
  const line = on === 'navy' ? 'rgba(244,243,239,0.13)' : 'rgba(8,30,52,0.10)';
  const lineSoft = on === 'navy' ? 'rgba(244,243,239,0.07)' : 'rgba(8,30,52,0.06)';
  const gold = MV.gold;
  const A = [430, 400], B = [650, 440];
  const sats = [[300, 250], [556, 232], [792, 318], [742, 588], [470, 600], [250, 486]];
  const linkTo = [A, B, B, B, A, A];
  return (
    <svg ref={innerRef} viewBox="0 0 1000 900" width="1000" height="900"
      style={field3d(style)} aria-hidden="true">
      {/* web hairlines */}
      <g stroke={line} strokeWidth="1">
        {sats.map((s, i) => <line key={i} x1={s[0]} y1={s[1]} x2={linkTo[i][0]} y2={linkTo[i][1]} />)}
      </g>
      {/* main human connection */}
      <line x1={A[0]} y1={A[1]} x2={B[0]} y2={B[1]} stroke={gold} strokeWidth="1.6" opacity="0.7" />
      {/* signal rings reaching out */}
      <g fill="none" stroke={gold} strokeWidth="1">
        <circle cx={A[0]} cy={A[1]} r="46" opacity="0.18" />
        <circle cx={B[0]} cy={B[1]} r="46" opacity="0.18" />
        <circle className="mv-pulse" cx={A[0]} cy={A[1]} r="46" opacity="0.4" />
        <circle className="mv-pulse mv-pulse-2" cx={B[0]} cy={B[1]} r="46" opacity="0.4" />
      </g>
      {/* nodes */}
      <g fill={on === 'navy' ? MV.creamFaint : MV.hairNavy}>
        {sats.map((s, i) => <circle key={i} cx={s[0]} cy={s[1]} r="2.8" />)}
      </g>
      <g fill={gold}>
        <circle cx={A[0]} cy={A[1]} r="5" />
        <circle cx={B[0]} cy={B[1]} r="5" />
      </g>
    </svg>
  );
}

// Compass hook: drifts `fieldRef` toward the pointer within `rootRef`.
// Subtle (max ~strength px). No-op under reduced-motion.
function useCompass(rootRef, fieldRef, strength = 16) {
  React.useEffect(() => {
    const root = rootRef.current, field = fieldRef.current;
    if (!root || !field) return;
    if (window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches) return;
    let raf = 0, tx = 0, ty = 0, cx = 0, cy = 0;
    const base = field.style.transform || '';
    const onMove = (e) => {
      const r = root.getBoundingClientRect();
      const nx = (e.clientX - r.left) / r.width - 0.5;
      const ny = (e.clientY - r.top) / r.height - 0.5;
      tx = nx * strength * 2; ty = ny * strength * 2;
      if (!raf) raf = requestAnimationFrame(tick);
    };
    const tick = () => {
      cx += (tx - cx) * 0.08; cy += (ty - cy) * 0.08;
      field.style.transform = `${base} translate(${cx.toFixed(2)}px, ${cy.toFixed(2)}px)`;
      if (Math.abs(tx - cx) > 0.1 || Math.abs(ty - cy) > 0.1) raf = requestAnimationFrame(tick);
      else raf = 0;
    };
    root.addEventListener('pointermove', onMove);
    return () => { root.removeEventListener('pointermove', onMove); if (raf) cancelAnimationFrame(raf); };
  }, [rootRef, fieldRef, strength]);
}

Object.assign(window, { MV, MV_FIELD_W, MV_FIELD_H, MVNav, MVEyebrow, MVArrow, PH, MeasurementField, BridgeField,
  MountainField, OrbitField, GlobeField, DataField, ConnectionField, useCompass });
