import React, { useRef } from 'react';
import { num } from '../../api/useXplane.js';
import { useEased, useEasedAngle } from '../../api/ease.js';

// ============================================================================
// Cessna Citation X — Primary Flight Display (Honeywell Primus 2000).
// Built line-for-line against the X-Plane Citation X manual (pages 30-31):
//   1 Attitude · 2 Airspeed scale · 3 Airspeed trend · 4 Heading bug
//   5 Desired course (CRS) · 6 Secondary NAV (bearing pointers) · 7 Desired hdg
//   8 Minimums · 9 RA/BARO · 10 HSI · 11 STD · 12 BARO SET · 13/14 VSI
//   15 CDI · 16 DME · 17 Altimeter setting · 18 Radar altimeter
//   19 FD lateral bar · 20 Altitude trend · 21 Altimeter scale · 22 FD vertical bar
// All values are live X-Plane datarefs streamed by the bridge (no Lua needed).
// ============================================================================

const PXDEG = 7;        // pitch ladder px per degree
const clamp = (v, a, b) => Math.max(a, Math.min(b, v));
const mod360 = (d) => ((d % 360) + 360) % 360;
const hz2mhz = (hz) => (num(hz) / 100).toFixed(2);

// ── airspeed tape ───────────────────────────────────────────────────────────
// Citation X operating speeds (manual p80): Vso 115 · Vs1 136 · Vfe 180 ·
// Vmo 270 (SL-8000') / 350 (above) · Mmo 0.935.
const VSO = 115, VS1 = 136, VFE = 180;
function SpeedTape({ ias, mach, bug, alt, trendKt }) {
  const H = 560, mid = H / 2, pxkt = 3.4;     // 3.4 px per knot
  const y = (s) => mid + (ias - s) * pxkt;
  const vmo = alt > 8000 ? 350 : 270;
  const top = ias + mid / pxkt, marks = [];
  for (let s = Math.ceil((ias - mid / pxkt) / 10) * 10; s <= top; s += 10) {
    if (s < 0) continue;
    marks.push(
      <g key={s}>
        <line x1={70} y1={y(s)} x2={s % 20 === 0 ? 58 : 64} y2={y(s)} stroke="#cfd6dc" strokeWidth="1.4" />
        {s % 20 === 0 && <text x={54} y={y(s) + 4} fontSize="17" fill="#e8edf1" textAnchor="end">{s}</text>}
      </g>,
    );
  }
  return (
    <g>
      <rect x={0} y={0} width={74} height={H} fill="#0c1116" opacity="0.82" />
      <clipPath id="spdclip"><rect x={0} y={0} width={74} height={H} /></clipPath>
      <g clipPath="url(#spdclip)">
        {/* low-speed awareness: red below Vso, amber Vso→Vs1 */}
        <rect x={0} y={y(VSO)} width={8} height={Math.max(0, H - y(VSO))} fill="#c0392b" />
        <rect x={0} y={y(VS1)} width={8} height={Math.max(0, y(VSO) - y(VS1))} fill="#ffb000" />
        {/* Vmo/Mmo barber pole: overspeed band from the top down to the Vmo line */}
        <rect x={0} y={0} width={8} height={clamp(y(vmo), 0, H)} fill="url(#barber)" />
        {/* Vfe flap-limit marker */}
        <line x1={0} y1={y(VFE)} x2={12} y2={y(VFE)} stroke="#fff" strokeWidth="3" />
        {marks}
        {/* airspeed trend vector (#3): magenta line from the index up/down */}
        {Math.abs(trendKt) > 1 && (
          <g>
            <line x1={71} y1={mid} x2={71} y2={mid - trendKt * pxkt} stroke="#d24bd2" strokeWidth="3" />
            <polygon points={`71,${mid - trendKt * pxkt} 67,${mid - trendKt * pxkt + (trendKt > 0 ? 8 : -8)} 75,${mid - trendKt * pxkt + (trendKt > 0 ? 8 : -8)}`} fill="#d24bd2" />
          </g>
        )}
      </g>
      <defs>
        <pattern id="barber" width="8" height="8" patternUnits="userSpaceOnUse" patternTransform="rotate(45)">
          <rect width="8" height="8" fill="#fff" /><rect width="4" height="8" fill="#c0392b" />
        </pattern>
      </defs>
      {/* selected-speed bug (magenta) */}
      {bug > 20 && <polygon points={`74,${clamp(y(bug), 6, H - 6)} 64,${clamp(y(bug), 6, H - 6) - 7} 64,${clamp(y(bug), 6, H - 6) + 7}`} fill="#d24bd2" />}
      {/* current readout box */}
      <polygon points={`0,${mid - 20} 60,${mid - 20} 74,${mid} 60,${mid + 20} 0,${mid + 20}`} fill="#000" stroke="#cfd6dc" strokeWidth="1.4" />
      <text x={50} y={mid + 8} fontSize="26" fill="#fff" textAnchor="end" fontWeight="700">{Math.round(ias)}</text>
      {mach >= 0.4 && <text x={40} y={H - 6} fontSize="16" fill="#13e000" textAnchor="middle">M{mach.toFixed(2).slice(1)}</text>}
    </g>
  );
}

// ── AOA index (manual p22): normalised 0 (zero-lift) … 1.0 (stall); the
// pilot keeps AOA below 0.6 (30% margin). alpha≈14° ≈ stall.
function AoaIndex({ alpha }) {
  const n = clamp(alpha / 14, 0, 1.05);
  const H = 120, y = (v) => H - v / 1.05 * H;
  return (
    <g>
      <text x={0} y={-6} fontSize="11" fill="#9aa6ad" textAnchor="middle">AOA</text>
      <rect x={-7} y={0} width={14} height={H} fill="#0c1116" stroke="#2a3138" />
      <rect x={-7} y={0} width={14} height={y(0.85)} fill="#c0392b" opacity="0.55" />
      <rect x={-7} y={y(0.85)} width={14} height={y(0.6) - y(0.85)} fill="#ffb000" opacity="0.5" />
      <rect x={-7} y={y(0.6)} width={14} height={H - y(0.6)} fill="#13a800" opacity="0.4" />
      <polygon points={`8,${y(n)} 18,${y(n) - 6} 18,${y(n) + 6}`} fill="#fff" />
    </g>
  );
}

// ── altitude tape + VSI ───────────────────────────────────────────────────────
function AltTape({ alt, bug, vs, baro, std, baroHpa, minOn, minFt, raBaro }) {
  const H = 560, mid = H / 2, pxft = 0.32;     // px per foot
  const top = alt + mid / pxft, marks = [];
  for (let s = Math.ceil((alt - mid / pxft) / 100) * 100; s <= top; s += 100) {
    const y = mid + (alt - s) * pxft;
    marks.push(
      <g key={s}>
        <line x1={6} y1={y} x2={s % 500 === 0 ? 22 : 16} y2={y} stroke="#cfd6dc" strokeWidth="1.4" />
        {s % 200 === 0 && <text x={26} y={y + 4} fontSize="16" fill="#e8edf1">{s}</text>}
      </g>,
    );
  }
  const baroTxt = std ? 'STD' : baroHpa ? `${Math.round(num(baro) * 33.8639)}` : num(baro).toFixed(2);
  const minY = clamp(mid + (alt - minFt) * pxft, 6, H - 6);
  return (
    <g>
      <rect x={0} y={0} width={120} height={H} fill="#0c1116" opacity="0.82" />
      <clipPath id="altclip"><rect x={0} y={0} width={120} height={H} /></clipPath>
      <g clipPath="url(#altclip)">
        {marks}
        {/* altitude trend (green, 6 s projection of VSI) */}
        <rect x={2} y={Math.min(mid, mid - vs / 10 * pxft)} width={4} height={Math.abs(vs / 10 * pxft)} fill="#13e000" />
        {/* minimums bug (cyan) */}
        {minOn && <polygon points={`6,${minY} 22,${minY - 7} 22,${minY + 7}`} fill="#19c3e0" />}
      </g>
      {/* selected-altitude bug (magenta) */}
      <polygon points={`0,${clamp(mid + (alt - bug) * pxft, 6, H - 6) - 8} 14,${clamp(mid + (alt - bug) * pxft, 6, H - 6) - 8} 14,${clamp(mid + (alt - bug) * pxft, 6, H - 6) + 8} 0,${clamp(mid + (alt - bug) * pxft, 6, H - 6) + 8}`} fill="#d24bd2" />
      {/* current readout box */}
      <polygon points={`120,${mid - 20} 30,${mid - 20} 16,${mid} 30,${mid + 20} 120,${mid + 20}`} fill="#000" stroke="#cfd6dc" strokeWidth="1.4" />
      <text x={112} y={mid + 8} fontSize="25" fill="#fff" textAnchor="end" fontWeight="700">{Math.round(alt)}</text>
      {/* baro setting */}
      <text x={60} y={H + 26} fontSize="17" fill={std ? '#13e000' : '#19c3e0'} textAnchor="middle">{std ? 'STD' : `${baroTxt}${baroHpa ? '' : ''}`}</text>
      {minOn && <text x={60} y={H + 46} fontSize="13" fill="#19c3e0" textAnchor="middle">{raBaro ? 'RA' : 'BARO'} {Math.round(minFt)}</text>}
    </g>
  );
}

function VSI({ vs }) {
  const H = 480, mid = H / 2;
  // non-linear-ish: ±2000 fpm across the scale
  const y = (fpm) => mid - clamp(fpm, -2500, 2500) / 2500 * (H / 2 - 10);
  const ticks = [0, 500, 1000, 2000];
  return (
    <g>
      <rect x={0} y={0} width={48} height={H} fill="#0c1116" opacity="0.7" rx="6" />
      {ticks.map((t) => (
        <g key={t}>
          <line x1={0} y1={y(t)} x2={t % 1000 === 0 ? 16 : 10} y2={y(t)} stroke="#9aa6ad" strokeWidth="1.2" />
          <line x1={0} y1={y(-t)} x2={t % 1000 === 0 ? 16 : 10} y2={y(-t)} stroke="#9aa6ad" strokeWidth="1.2" />
          {t > 0 && <text x={20} y={y(t) + 4} fontSize="11" fill="#9aa6ad">{t / 1000}</text>}
          {t > 0 && <text x={20} y={y(-t) + 4} fontSize="11" fill="#9aa6ad">{t / 1000}</text>}
        </g>
      ))}
      <line x1={0} y1={mid} x2={48} y2={y(vs)} stroke="#13e000" strokeWidth="3" />
      {Math.abs(vs) > 100 && <text x={24} y={vs > 0 ? 14 : H - 4} fontSize="14" fill="#13e000" textAnchor="middle" fontWeight="700">{Math.round(vs / 50) * 50}</text>}
    </g>
  );
}

// ── attitude ball ─────────────────────────────────────────────────────────────
function Attitude({ pitch, roll, slip, fdP, fdR, fdOn }) {
  const R = 196, cx = 0, cy = 0;
  const ladder = [];
  for (let p = -90; p <= 90; p += 10) {
    if (p === 0) continue;
    const y = p * PXDEG;
    const w = p % 20 === 0 ? 70 : 36;
    ladder.push(
      <g key={p}>
        <line x1={-w / 2} y1={-y} x2={w / 2} y2={-y} stroke="#fff" strokeWidth="2" />
        {p % 20 === 0 && <>
          <text x={-w / 2 - 8} y={-y + 5} fontSize="14" fill="#fff" textAnchor="end">{Math.abs(p)}</text>
          <text x={w / 2 + 8} y={-y + 5} fontSize="14" fill="#fff">{Math.abs(p)}</text>
        </>}
      </g>,
    );
  }
  // bank scale arc marks (top)
  const bankMarks = [-60, -45, -30, -20, -10, 0, 10, 20, 30, 45, 60].map((b) => {
    const a = (b - 90) * Math.PI / 180, r1 = R, r2 = b % 30 === 0 || b === 0 ? R - 16 : R - 10;
    return <line key={b} x1={Math.cos(a) * r1} y1={Math.sin(a) * r1} x2={Math.cos(a) * r2} y2={Math.sin(a) * r2} stroke="#fff" strokeWidth={b === 0 ? 0 : 1.6} />;
  });
  return (
    <g>
      <clipPath id="attclip"><circle cx={cx} cy={cy} r={R} /></clipPath>
      <g clipPath="url(#attclip)">
        {/* sky / ground, rotated by roll then pitched */}
        <g transform={`rotate(${-roll})`}>
          <g transform={`translate(0 ${pitch * PXDEG})`}>
            <rect x={-600} y={-1200} width={1200} height={1200} fill="#3a86c8" />
            <rect x={-600} y={0} width={1200} height={1200} fill="#6b4a2b" />
            <line x1={-600} y1={0} x2={600} y2={0} stroke="#fff" strokeWidth="2.5" />
            {ladder}
          </g>
        </g>
      </g>
      {/* fixed bank pointer + arc */}
      <g transform={`rotate(${-roll})`}>
        <polygon points={`0,${-R + 2} -10,${-R + 20} 10,${-R + 20}`} fill="#ffd400" />
      </g>
      {bankMarks}
      <polygon points={`0,${-R - 2} -9,${-R - 18} 9,${-R - 18}`} fill="#fff" />
      {/* slip/skid trapezoid below the bank pointer */}
      <g transform={`rotate(${-roll})`}>
        <rect x={-14 + clamp(slip, -1, 1) * 26} y={-R + 22} width={28} height={7} fill="#ffd400" stroke="#000" strokeWidth="0.6" />
      </g>
      {/* fixed aircraft reference (yellow) */}
      <g>
        <rect x={-2.5} y={-2.5} width={5} height={5} fill="#ffd400" />
        <line x1={-90} y1={0} x2={-30} y2={0} stroke="#ffd400" strokeWidth="4" />
        <line x1={30} y1={0} x2={90} y2={0} stroke="#ffd400" strokeWidth="4" />
        <line x1={-30} y1={0} x2={-30} y2={12} stroke="#ffd400" strokeWidth="4" />
        <line x1={30} y1={0} x2={30} y2={12} stroke="#ffd400" strokeWidth="4" />
      </g>
      {/* flight-director command bars (magenta V-bars) — #19 lateral / #22 vertical */}
      {fdOn && (
        <g transform={`translate(0 ${clamp(-fdP * PXDEG, -70, 70)}) rotate(${clamp(fdR, -30, 30)})`}>
          <polyline points="-70,16 0,2 70,16" fill="none" stroke="#d24bd2" strokeWidth="4" />
        </g>
      )}
    </g>
  );
}

// ── HSI (rotating compass with CDI + bearing pointers) ─────────────────────────
function HSI({ hdg, trk, crs, hdgBug, cdi, toFrom, brg1, brg2, srcLabel, srcColor }) {
  const R = 150;
  const card = [];
  for (let d = 0; d < 360; d += 5) {
    const a = (d - hdg - 90) * Math.PI / 180, r2 = d % 10 === 0 ? R - 14 : R - 8;
    card.push(<line key={d} x1={Math.cos(a) * R} y1={Math.sin(a) * R} x2={Math.cos(a) * r2} y2={Math.sin(a) * r2} stroke="#cfd6dc" strokeWidth={d % 30 === 0 ? 1.8 : 1} />);
    if (d % 30 === 0) {
      const rt = R - 30, lbl = d === 0 ? 'N' : d === 90 ? 'E' : d === 180 ? 'S' : d === 270 ? 'W' : d / 10;
      card.push(<text key={`t${d}`} x={Math.cos(a) * rt} y={Math.sin(a) * rt + 5} fontSize="14" fill="#e8edf1" textAnchor="middle">{lbl}</text>);
    }
  }
  const ptr = (deg, color, dbl) => {
    const a = (deg - hdg) * Math.PI / 180; // 0 = up
    const x = Math.sin(a), y = -Math.cos(a);
    return (
      <g stroke={color} strokeWidth="2.5" fill="none">
        <line x1={x * (R - 16)} y1={y * (R - 16)} x2={x * 40} y2={y * 40} />
        {/* arrow head */}
        <polygon points={`${x * (R - 16)},${y * (R - 16)} ${x * (R - 34) - y * 8},${y * (R - 34) + x * 8} ${x * (R - 34) + y * 8},${y * (R - 34) - x * 8}`} fill={color} />
        {dbl && <line x1={x * -40} y1={y * -40} x2={x * -(R - 16)} y2={y * -(R - 16)} />}
      </g>
    );
  };
  return (
    <g>
      <circle cx={0} cy={0} r={R} fill="#0a0e12" stroke="#2a3138" strokeWidth="1.5" />
      <g>{card}</g>
      {/* heading bug (magenta) */}
      <g transform={`rotate(${mod360(hdgBug - hdg)})`}><polygon points={`0,${-R} -9,${-R + 14} 9,${-R + 14}`} fill="#d24bd2" /></g>
      {/* course pointer + CDI deviation (#5 + #15) — FMS magenta / VOR green */}
      <g transform={`rotate(${mod360(crs - hdg)})`}>
        <line x1={0} y1={-R + 18} x2={0} y2={-50} stroke={srcColor} strokeWidth="3" />
        <polygon points={`0,${-R + 6} -8,${-R + 22} 8,${-R + 22}`} fill={srcColor} />
        <line x1={0} y1={50} x2={0} y2={R - 18} stroke={srcColor} strokeWidth="3" />
        {/* CDI bar */}
        <line x1={clamp(cdi, -2, 2) * 30} y1={-46} x2={clamp(cdi, -2, 2) * 30} y2={46} stroke={srcColor} strokeWidth="3.5" />
        {[-2, -1, 1, 2].map((d) => <circle key={d} cx={d * 30} cy={0} r="3" fill="none" stroke="#9aa6ad" strokeWidth="1.2" />)}
        {toFrom !== 0 && <polygon points={toFrom > 0 ? '0,-14 -8,2 8,2' : '0,14 -8,-2 8,-2'} fill={srcColor} />}
      </g>
      {/* bearing pointers — #6 secondary NAV (cyan circle = BRG1, white diamond = BRG2) */}
      {brg1 != null && ptr(brg1, '#19c3e0', false)}
      {brg2 != null && ptr(brg2, '#cfd6dc', true)}
      {/* fixed lubber line + aircraft */}
      <polygon points={`0,${-R - 2} -8,${-R - 16} 8,${-R - 16}`} fill="#fff" />
      <text x={0} y={-R - 22} fontSize="13" fill="#fff" textAnchor="middle" fontWeight="700">{String(Math.round(mod360(hdg))).padStart(3, '0')}</text>
      <text x={0} y={6} fontSize="12" fill={srcColor} textAnchor="middle">{srcLabel}</text>
    </g>
  );
}

export default function CitPFD({ xp, navSrc }) {
  const V = xp.values || {};
  const bsrc = navSrc || { brg1: 'VOR1', brg2: 'VOR2' };
  const [std, setStd] = React.useState(false);
  const [raBaro, setRaBaro] = React.useState(false);   // #9 RA/BARO minimums source
  const [min, setMin] = React.useState({ on: false, ft: 200 });
  const trend = useRef({ ias: 0, t: 0 });

  // Smooth the moving symbology toward the live datarefs (frame-rate-independent
  // easing) — the same rAF glide the G1000 uses, so a 10-20 Hz stream renders as
  // fluid 60 fps motion instead of stepping.
  const ias = useEased(num(V.airspeed), 0.10);
  const alt = useEased(num(V.altitude), 0.12);
  const vs = useEased(num(V.vspeed), 0.18);
  const pitch = useEased(num(V.pitch), 0.07);
  const roll = useEased(num(V.roll), 0.07);
  const slip = useEased(num(V.slip), 0.12);
  const hdg = useEasedAngle(num(V.heading), 0.08);
  const crs = useEasedAngle(num(V.obsCrs), 0.10);
  const hdgBug = useEasedAngle(num(V.apHdgBug), 0.10);
  const cdi = useEased(num(V.hsiDef), 0.12);
  const mach = useEased(num(V.mach), 0.2);
  const aoa = useEased(num(V.aoa), 0.12);
  const hdgRaw = num(V.heading);
  const vor1e = useEasedAngle(num(V.nav1Brg), 0.12);
  const vor2e = useEasedAngle(num(V.nav2Brg), 0.12);
  const adf1e = useEasedAngle(mod360(hdgRaw + num(V.adf1Brg)), 0.12); // ADF relative → mag bearing
  const adf2e = useEasedAngle(mod360(hdgRaw + num(V.adf2Brg)), 0.12);
  const gpsBrgE = useEasedAngle(num(V.gpsBearing), 0.12);
  const trk = num(V.track), toFrom = num(V.hsiToFrom);
  const baro = num(V.baro, 29.92);
  const radAlt = num(V.radioAlt, 99999);
  const fdOn = num(V.apMode) >= 1 || num(V.apEngaged) > 0;
  // bearing pointer source (Nav Source Selector): resolve each pointer to a
  // magnetic bearing or null (no station / OFF). Pointer 1 = cyan ◯, 2 = white ◇.
  const pickBrg = (sel) => {
    if (sel === 'VOR1') return (num(V.nav1Dme) > 0 || num(V.nav1Brg) > 0) ? vor1e : null;
    if (sel === 'VOR2') return (num(V.nav2Dme) > 0 || num(V.nav2Brg) > 0) ? vor2e : null;
    if (sel === 'ADF1') return num(V.adf1Brg) ? adf1e : null;
    if (sel === 'ADF2') return num(V.adf2Brg) ? adf2e : null;
    if (sel === 'FMS1' || sel === 'FMS') return num(V.gpsBearing) ? gpsBrgE : null;
    return null;
  };
  const brg1 = pickBrg(bsrc.brg1);
  const brg2 = pickBrg(bsrc.brg2);
  // FMA / AFCS mode annunciation (active = green, armed = white)
  const st = (k) => num(V[k]);
  const latM = st('aprStatus') ? ['LOC', st('aprStatus')] : (st('navStatus') || st('gpssStatus')) ? ['NAV', Math.max(st('navStatus'), st('gpssStatus'))]
    : st('bcStatus') ? ['BC', st('bcStatus')] : st('hdgStatus') ? ['HDG', st('hdgStatus')] : ['ROLL', 2];
  const vertM = st('gsStatus') ? ['GS', st('gsStatus')] : st('vnavStatus') ? ['VNAV', st('vnavStatus')]
    : st('flcStatus') ? ['FLC', st('flcStatus')] : st('vsStatus') ? ['VS', st('vsStatus')]
    : st('altStatus') ? ['ALT', st('altStatus')] : ['PITCH', 2];
  const apTxt = num(V.apEngaged) > 0 || num(V.apMode) >= 2 ? 'AP' : fdOn ? 'FD' : '';
  const fmaColor = (s) => (s >= 2 ? '#16e000' : '#fff');
  // Nav source (Nav Source Selector, manual p24): 0 VOR1 · 1 VOR2 · 2 FMS.
  // FMS course is magenta, VOR course is green (Honeywell convention).
  const cdiSrc = num(V.cdiSrc);
  const srcLabel = cdiSrc === 2 ? 'FMS1' : cdiSrc === 1 ? 'VOR2' : 'VOR1';
  const srcColor = cdiSrc === 2 ? '#d24bd2' : '#13e000';
  const cycleNav = () => xp.setDataref('cdiSrc', cdiSrc === 1 ? 0 : 1);  // toggle VOR1↔VOR2
  const setFms = () => xp.setDataref('cdiSrc', 2);
  const dme = cdiSrc === 1 ? num(V.nav2Dme) : num(V.nav1Dme);
  // airspeed trend vector (#3): smoothed acceleration projected 10 s ahead
  const t = trend.current, nowS = (typeof performance !== 'undefined' ? performance.now() : Date.now()) / 1000;
  const dt = Math.min(0.5, Math.max(0.001, nowS - (t.t || nowS)));
  const rate = (ias - (t.ias != null ? t.ias : ias)) / dt;       // kt/s
  t.s = (t.s || 0) * 0.92 + rate * 0.08; t.ias = ias; t.t = nowS;
  const trendKt = clamp(t.s * 10, -45, 45);

  return (
    <div className="cit-screen">
      <svg className="cit-pfd" viewBox="0 0 800 940" preserveAspectRatio="xMidYMid meet">
        <rect x={0} y={0} width={800} height={940} fill="#05080b" />
        {/* FMA / AFCS mode annunciation bar (active green · armed white) */}
        <g transform="translate(204 8)">
          <rect x={0} y={0} width={392} height={26} fill="#0a0e12" stroke="#2a3138" />
          <line x1={130} y1={2} x2={130} y2={24} stroke="#2a3138" /><line x1={262} y1={2} x2={262} y2={24} stroke="#2a3138" />
          <text x={65} y={18} fontSize="14" fill={fmaColor(latM[1])} textAnchor="middle" fontWeight="700">{latM[0]}</text>
          <text x={196} y={18} fontSize="14" fill="#16e000" textAnchor="middle" fontWeight="700">{apTxt}</text>
          <text x={328} y={18} fontSize="14" fill={fmaColor(vertM[1])} textAnchor="middle" fontWeight="700">{vertM[0]}</text>
        </g>
        {/* attitude */}
        <g transform="translate(400 270)"><Attitude pitch={pitch} roll={roll} slip={slip} fdP={num(V.fdPitch)} fdR={num(V.fdRoll)} fdOn={fdOn} /></g>
        {/* speed tape (#2,#3) */}
        <g transform="translate(96 90)"><SpeedTape ias={ias} mach={mach} bug={num(V.apSpdBug)} alt={alt} trendKt={trendKt} /></g>
        <text x={120} y={78} fontSize="14" fill="#9aa6ad" textAnchor="middle">KIAS</text>
        {/* AOA index (#manual p22) */}
        <g transform="translate(48 600)"><AoaIndex alpha={aoa} /></g>
        {/* altitude tape (#20,#21) + baro (#12,#17) */}
        <g transform="translate(584 90)"><AltTape alt={alt} bug={num(V.apAltBug)} vs={vs} baro={baro} std={std} baroHpa={false} minOn={min.on} minFt={min.ft} raBaro={raBaro} /></g>
        {/* VSI (#13,#14) */}
        <g transform="translate(716 130)"><VSI vs={vs} /></g>
        {/* HSI (#10) */}
        <g transform="translate(400 690)"><HSI hdg={hdg} trk={trk} crs={crs} hdgBug={hdgBug} cdi={cdi} toFrom={toFrom} brg1={brg1} brg2={brg2} srcLabel={srcLabel} srcColor={srcColor} /></g>

        {/* CRS / HDG digital (#5,#7) */}
        <g fontSize="15" fontWeight="700">
          <text x={20} y={560} fill="#19c3e0">CRS</text>
          <text x={20} y={580} fill="#19c3e0" fontSize="20">{String(Math.round(mod360(crs))).padStart(3, '0')}</text>
          <text x={20} y={642} fill="#d24bd2">HDG</text>
          <text x={20} y={662} fill="#d24bd2" fontSize="20">{String(Math.round(mod360(hdgBug))).padStart(3, '0')}</text>
        </g>
        {/* secondary NAV legend (#6) — reflects the Nav Source Selector */}
        <g fontSize="13">
          {bsrc.brg1 !== 'OFF' && <><circle cx={28} cy={726} r="6" fill="none" stroke="#19c3e0" strokeWidth="2" />
            <text x={42} y={731} fill="#19c3e0">{bsrc.brg1}</text></>}
          {bsrc.brg2 !== 'OFF' && <><rect x={22} y={744} width={12} height={12} fill="none" stroke="#cfd6dc" strokeWidth="2" transform="rotate(45 28 750)" />
            <text x={42} y={755} fill="#cfd6dc">{bsrc.brg2}</text></>}
        </g>
        {/* DME (#16) */}
        {dme > 0 && <text x={760} y={620} fontSize="16" fill="#13e000" textAnchor="end">{dme.toFixed(1)}NM</text>}
        {/* radar altimeter (#18) — only within 2500 ft AGL */}
        {radAlt < 2500 && <text x={400} y={420} fontSize="22" fill="#13e000" textAnchor="middle" fontWeight="700">{Math.round(radAlt)}</text>}
        {radAlt < 2500 && <text x={400} y={436} fontSize="11" fill="#9aa6ad" textAnchor="middle">RA</text>}
        {/* TCAS label */}
        <text x={690} y={840} fontSize="13" fill="#9aa6ad">TCAS</text>
        <text x={760} y={84} fontSize="13" fill="#9aa6ad" textAnchor="end">FT</text>
      </svg>

      {/* bezel buttons — Nav Source Selector (p24, sits under the PFD), MINIMUMS
          rotary (#8), RA/BARO (#9), STD (#11), BARO SET (#12), CRS, HDG */}
      <div className="cit-bezel">
        <div className="cit-bz-group">
          <span className="cit-bz-lbl">NAV SRC</span>
          <button className={`cit-bz-btn ${cdiSrc !== 2 ? 'on' : ''}`} onClick={cycleNav}>{cdiSrc === 1 ? 'VOR2' : 'VOR1'}</button>
          <button className={`cit-bz-btn ${cdiSrc === 2 ? 'on' : ''}`} onClick={setFms}>FMS</button>
        </div>
        <div className="cit-bz-group">
          <span className="cit-bz-lbl">MINIMUMS</span>
          <button className="cit-bz-knob" onClick={() => setMin((m) => ({ ...m, on: true, ft: m.ft - 50 }))}>‹</button>
          <span className="cit-bz-val">{min.on ? min.ft : '– – –'}</span>
          <button className="cit-bz-knob" onClick={() => setMin((m) => ({ ...m, on: true, ft: m.ft + 50 }))}>›</button>
          <button className={`cit-bz-btn ${min.on ? 'on' : ''}`} onClick={() => setMin((m) => ({ ...m, on: !m.on }))}>MIN</button>
        </div>
        <button className={`cit-bz-btn ${raBaro ? 'on' : ''}`} onClick={() => setRaBaro((v) => !v)}>RA/BARO</button>
        <button className={`cit-bz-btn ${std ? 'on' : ''}`} onClick={() => setStd((v) => !v)}>STD</button>
        <div className="cit-bz-group">
          <span className="cit-bz-lbl">BARO SET</span>
          <button className="cit-bz-knob" onClick={() => xp.command('pfd_baro_down')}>‹</button>
          <span className="cit-bz-val">{std ? 'STD' : baro.toFixed(2)}</span>
          <button className="cit-bz-knob" onClick={() => xp.command('pfd_baro_up')}>›</button>
        </div>
        <div className="cit-bz-group">
          <span className="cit-bz-lbl">CRS</span>
          <button className="cit-bz-knob" onClick={() => xp.command('pfd_crs_down')}>‹</button>
          <button className="cit-bz-knob" onClick={() => xp.command('pfd_crs_up')}>›</button>
        </div>
        <div className="cit-bz-group">
          <span className="cit-bz-lbl">HDG</span>
          <button className="cit-bz-knob" onClick={() => xp.command('pfd_hdg_down')}>‹</button>
          <button className="cit-bz-knob" onClick={() => xp.command('pfd_hdg_sync')}>SYNC</button>
          <button className="cit-bz-knob" onClick={() => xp.command('pfd_hdg_up')}>›</button>
        </div>
      </div>
    </div>
  );
}
