// pixel.jsx — Ferry, pixel-art deep-sea variant. Wired to the real API.
// Depends on window: Icon (from shared.jsx). Exports to window: FerryApp

const VERSION = 'v1.8';

const PXJB = "'JetBrains Mono', ui-monospace, monospace";
const PX = "'Silkscreen', monospace";

const PD = {
  bone: '#DCEFF2',
  ash: 'rgba(220,239,242,0.56)',
  faint: 'rgba(220,239,242,0.32)',
  bio: '#3FE0D8',
  bioDim: 'rgba(63,224,216,0.16)',
  fill: 'rgba(120,200,210,0.05)',
  line: 'rgba(120,200,210,0.18)',
  edge: 'rgba(63,224,216,0.30)'
};
const PD_GREEN = '#46E0A0';
const PD_GREENDIM = 'rgba(70,224,160,0.16)';

const PX_GRAIN = "url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.4'/%3E%3C/svg%3E\")";

// ── square marine snow, choppy step drift ─────────────────────
function PixelSnow() {
  const f = []; let s = 11;
  const rnd = () => (s = (s * 9301 + 49297) % 233280) / 233280;
  for (let i = 0; i < 30; i++) {
    const big = rnd() > 0.7;
    f.push({ left: rnd() * 100, top: rnd() * 100, size: big ? 3 : 2,
      op: 0.18 + rnd() * 0.42, dur: 10 + rnd() * 14, delay: -rnd() * 18,
      dx: (rnd() * 12 - 6).toFixed(1), glow: big });
  }
  return (
    <div style={{ position: 'absolute', inset: 0, overflow: 'hidden', imageRendering: 'pixelated' }}>
      {f.map((p, i) =>
        <span key={i} style={{
          position: 'absolute', left: `${p.left}%`, top: `${p.top}%`,
          width: p.size, height: p.size, background: '#CFEFF0', opacity: p.op,
          boxShadow: p.glow ? '0 0 5px rgba(120,225,225,0.7)' : 'none',
          animation: `pxDrift ${p.dur}s steps(10) ${p.delay}s infinite`,
          ['--dx']: `${p.dx}px`
        }} />
      )}
    </div>
  );
}

// ── blocky pixel leviathan resting in the deep ────────────────
function PixelLeviathan() {
  const cell = 14, cols = 30;
  const h = [1,2,1,3,2,4,3,5,4,6,7,9,11,12,13,12,11,9,8,6,7,5,6,4,3,4,2,3,1,2];
  const W = cols * cell, H = 230;
  return (
    <div style={{ position: 'absolute', left: '50%', transform: 'translateX(-50%)', bottom: -22,
      width: W, height: H, pointerEvents: 'none' }}>
      <svg width={W} height={H} viewBox={`0 0 ${W} ${H}`} shapeRendering="crispEdges" style={{ display: 'block' }}>
        {h.map((v, i) => {
          const x = i * cell, ph = v * cell, y = H - ph;
          return (
            <g key={i}>
              <rect x={x} y={y} width={cell} height={ph} fill="rgba(4,13,19,0.62)" />
              <rect x={x} y={y} width={cell} height={2} fill="rgba(63,224,216,0.13)" />
            </g>
          );
        })}
      </svg>
      <div style={{ position: 'absolute', left: 12 * cell, top: H - 13 * cell + 34,
        width: 12, height: 12, background: PD.bio, boxShadow: `0 0 10px ${PD.bio}`,
        animation: 'pxBlink 5s steps(2) infinite' }} />
      <div style={{ position: 'absolute', left: 16 * cell, top: H - 13 * cell + 44,
        width: 10, height: 10, background: PD.bio, boxShadow: `0 0 9px ${PD.bio}`,
        animation: 'pxBlink 5s steps(2) 0.4s infinite' }} />
    </div>
  );
}

// ── tiny pixel "screen" thumbnail ─────────────────────────────
const PX_HUES = [176, 192, 160, 205, 184, 168];
function PixelThumb({ i = 0 }) {
  const hue = PX_HUES[i % PX_HUES.length];
  const head = `hsla(${hue},55%,52%,0.85)`;
  const headDeep = `hsla(${hue},55%,34%,0.85)`;
  const ln = `hsla(${hue},40%,72%,0.36)`;
  const blk = `hsla(${hue},45%,60%,0.24)`;
  const tall = i % 2 === 0;
  return (
    <div style={{
      position: 'relative', width: '100%', aspectRatio: '1 / 1.18',
      borderRadius: 2, overflow: 'hidden', imageRendering: 'pixelated',
      background: `linear-gradient(180deg, hsla(${hue},34%,13%,1), #04090C)`,
      boxShadow: `inset 0 0 0 2px ${PD.line}`
    }}>
      <div style={{ display: 'flex', justifyContent: 'space-between', padding: '5px 5px 0' }}>
        <div style={{ width: 12, height: 3, background: ln }} />
        <div style={{ width: 6, height: 3, background: ln }} />
      </div>
      <div style={{ margin: '5px 5px 0', height: tall ? 22 : 16,
        background: `linear-gradient(135deg,${head},${headDeep})` }} />
      <div style={{ padding: '6px 5px 0', display: 'flex', flexDirection: 'column', gap: 4 }}>
        <div style={{ width: '74%', height: 3, background: ln }} />
        <div style={{ width: '50%', height: 3, background: ln }} />
        <div style={{ marginTop: 2, display: 'flex', gap: 4 }}>
          <div style={{ width: 14, height: 14, background: blk }} />
          <div style={{ flex: 1, display: 'flex', flexDirection: 'column', gap: 3, paddingTop: 2 }}>
            <div style={{ width: '66%', height: 3, background: ln }} />
            <div style={{ width: '42%', height: 3, background: ln }} />
          </div>
        </div>
      </div>
      <div style={{ position: 'absolute', inset: 0, pointerEvents: 'none',
        backgroundImage: 'repeating-linear-gradient(0deg, rgba(0,0,0,0.18) 0 1px, transparent 1px 3px)' }} />
    </div>
  );
}

// ── real file thumbnail ────────────────────────────────────────
function RealThumb({ file }) {
  const { useState, useEffect } = React;
  const [url, setUrl] = useState('');
  useEffect(() => {
    const u = URL.createObjectURL(file);
    setUrl(u);
    return () => URL.revokeObjectURL(u);
  }, [file]);
  return (
    <div style={{
      position: 'relative', width: '100%', aspectRatio: '1 / 1.18',
      borderRadius: 2, overflow: 'hidden',
      boxShadow: `inset 0 0 0 2px ${PD.line}`
    }}>
      {url && <img src={url} alt="" style={{ width: '100%', height: '100%', objectFit: 'cover' }} />}
      <div style={{ position: 'absolute', inset: 0, pointerEvents: 'none',
        backgroundImage: 'repeating-linear-gradient(0deg, rgba(0,0,0,0.12) 0 1px, transparent 1px 3px)' }} />
    </div>
  );
}

function PixelStep({ n, title, last, children, badge, right, onHeaderClick, open = true }) {
  const showBody = open && children != null;
  return (
    <div style={{ position: 'relative', paddingBottom: last ? 0 : 22 }}>
      {!last && <div style={{ position: 'absolute', left: 11, top: 30, bottom: 5, width: 2,
        backgroundImage: `repeating-linear-gradient(180deg, ${PD.edge} 0 4px, transparent 4px 8px)` }} />}
      <div onClick={onHeaderClick}
        style={{ display: 'flex', alignItems: 'center', gap: 12,
          cursor: onHeaderClick ? 'pointer' : 'default', userSelect: 'none' }}>
        {badge !== undefined ? badge :
          <div style={{ width: 24, height: 24, flexShrink: 0, background: PD.bioDim, borderRadius: 2,
            boxShadow: `inset 0 0 0 2px ${PD.edge}`,
            display: 'flex', alignItems: 'center', justifyContent: 'center',
            fontFamily: PX, fontWeight: 400, fontSize: 11, color: PD.bio, paddingTop: 1 }}>{n}</div>
        }
        <div style={{ flex: 1, minWidth: 0, fontFamily: PX, fontSize: 11, fontWeight: 400, color: PD.bone,
          letterSpacing: 0.5, textTransform: 'uppercase', lineHeight: 1.3 }}>{title}</div>
        {right}
      </div>
      {showBody && <div style={{ paddingLeft: 36, paddingTop: 13 }}>{children}</div>}
    </div>
  );
}

// fullscreen sheet of selected screenshots — real previews
function ShotsModal({ onClose, files }) {
  const count = files.length;
  return (
    <div style={{ position: 'absolute', inset: 0, zIndex: 10, background: 'linear-gradient(180deg,#06141D 0%,#03090F 70%,#02070C 100%)',
      animation: 'deepIn 0.22s ease both', display: 'flex', flexDirection: 'column' }}>
      <div style={{ position: 'absolute', inset: 0, backgroundImage: PX_GRAIN, opacity: 0.2, mixBlendMode: 'overlay', pointerEvents: 'none' }} />
      <div style={{ padding: '44px 22px 16px', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 9 }}>
          <span style={{ width: 6, height: 6, background: PD.bio, boxShadow: `0 0 8px ${PD.bio}` }} />
          <span style={{ fontFamily: PX, fontSize: 12, color: PD.bone, letterSpacing: 1 }}>{count} SELECTED</span>
        </div>
        <div onClick={onClose} style={{ width: 34, height: 34, borderRadius: 2, cursor: 'pointer',
          background: PD.fill, boxShadow: `inset 0 0 0 2px ${PD.line}`,
          display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
          <svg width="15" height="15" viewBox="0 0 24 24"><path d="M6 6l12 12M18 6L6 18" fill="none" stroke={PD.ash} strokeWidth="2.4" strokeLinecap="round" /></svg>
        </div>
      </div>
      <div style={{ flex: 1, minHeight: 0, overflowY: 'auto', padding: '4px 22px 26px',
        display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 14, alignContent: 'start' }}>
        {files.map((file, i) =>
          <div key={i} style={{ position: 'relative' }}>
            <RealThumb file={file} />
            <div style={{ position: 'absolute', right: 6, bottom: 6, width: 18, height: 18,
              background: PD.bio, display: 'flex', alignItems: 'center', justifyContent: 'center',
              boxShadow: `0 0 8px ${PD.bio}` }}>
              <Icon name="check" size={11} color="#03161A" stroke={3} />
            </div>
            <div style={{ position: 'absolute', left: 6, bottom: 6, fontFamily: PX, fontSize: 7,
              letterSpacing: 0.3, color: PD.ash }}>{file.name.slice(0, 12)}</div>
          </div>
        )}
      </div>
    </div>
  );
}

// pixel Figma mark
const FIG = { o: '#F24E1E', r: '#FF7262', p: '#A259FF', b: '#1ABCFE', g: '#0ACF83' };
const FIG_ROWS = [
  '.ooooo.rrrr.',
  'oooooorrrrrr',
  'oooooorrrrrr',
  'oooooorrrrrr',
  'oooooorrrrrr',
  '.ooooo.rrrr.',
  '.ppppp.bbbb.',
  'ppppppbbbbbb',
  'ppppppbbbbbb',
  'ppppppbbbbbb',
  'ppppppbbbbbb',
  '.ppppp.bbbb.',
  '.gggg.......',
  'gggggg......',
  'gggggg......',
  'gggggg......',
  'gggggg......',
  '.gggg.......'
];
function FigmaPixelMark({ cell = 7 }) {
  const px = cell / 6;
  return (
    <div style={{ display: 'grid', gridTemplateColumns: `repeat(12, ${px}px)`,
      gridAutoRows: `${px}px`, imageRendering: 'pixelated' }}>
      {FIG_ROWS.flatMap((row, y) => row.split('').map((ch, x) =>
        <div key={x + '-' + y} style={{ width: px, height: px, background: FIG[ch] || 'transparent' }} />
      ))}
    </div>
  );
}

// pixel Miro mark
const MIRO_YELLOW = '#FFD02F';
const MIRO_INK = '#0B0B0F';
const MIRO_STROKES = [
  { type: 'bar', x0: 1, x1: 2, topY: 4 },
  { type: 'wedge', bx: 9, base: 4, topY: 2, slope: 0.45 },
  { type: 'wedge', bx: 16, base: 11, topY: 2, slope: 0.45 },
];
function MiroPixelMark({ size = 32, px }) {
  const W = 18, H = 14;
  const p = px || size / 26;
  const filled = (x, y) => {
    for (const s of MIRO_STROKES) {
      if (s.type === 'bar') {
        if (x >= s.x0 && x <= s.x1 && y >= s.topY && y < H) return true;
      } else if (y >= s.topY) {
        const left = Math.max(s.base, Math.round(s.bx - (y - s.topY) * s.slope));
        if (x >= left && x <= s.bx) return true;
      }
    }
    return false;
  };
  const cells = [];
  for (let y = 0; y < H; y++) for (let x = 0; x < W; x++)
    cells.push(<div key={x + '-' + y} style={{ width: p, height: p, background: filled(x, y) ? MIRO_INK : 'transparent' }} />);
  return (
    <div style={{ width: size, height: size, borderRadius: size * 0.28, background: MIRO_YELLOW,
      display: 'flex', alignItems: 'center', justifyContent: 'center', imageRendering: 'pixelated' }}>
      <div style={{ display: 'grid', gridTemplateColumns: `repeat(${W}, ${p}px)`, gridAutoRows: `${p}px` }}>{cells}</div>
    </div>
  );
}

// coming-soon marks
const NOTION_N = ['k.....k','kk....k','k.k...k','k.k...k','k..k..k','k...k.k','k...k.k','k....kk','k.....k'];
function NotionPixelMark({ size = 30, px = 2.4 }) {
  return (
    <div style={{ width: size, height: size, borderRadius: 4, background: '#FFFFFF',
      display: 'flex', alignItems: 'center', justifyContent: 'center', imageRendering: 'pixelated',
      boxShadow: 'inset 0 0 0 1.5px rgba(0,0,0,0.12)' }}>
      <div style={{ display: 'grid', gridTemplateColumns: `repeat(7, ${px}px)`, gridAutoRows: `${px}px` }}>
        {NOTION_N.flatMap((row, y) => row.split('').map((ch, x) =>
          <div key={x + '-' + y} style={{ width: px, height: px, background: ch === 'k' ? '#0F0F0F' : 'transparent' }} />
        ))}
      </div>
    </div>
  );
}

function LinearPixelMark({ size = 30, px = 3 }) {
  const N = 10;
  const cells = [];
  for (let y = 0; y < N; y++) for (let x = 0; x < N; x++) {
    const on = (x + y) % 3 === 0;
    cells.push(<div key={x + '-' + y} style={{ width: px, height: px, background: on ? 'rgba(255,255,255,0.85)' : 'transparent' }} />);
  }
  return (
    <div style={{ width: size, height: size, borderRadius: 7, background: '#5E6AD2', overflow: 'hidden',
      display: 'flex', alignItems: 'center', justifyContent: 'center', imageRendering: 'pixelated',
      boxShadow: 'inset 0 0 0 1.5px rgba(255,255,255,0.18)' }}>
      <div style={{ display: 'grid', gridTemplateColumns: `repeat(${N}, ${px}px)`, gridAutoRows: `${px}px` }}>{cells}</div>
    </div>
  );
}

const SLACK_C = { B: '#36C5F0', Y: '#ECB22E', G: '#2EB67D', R: '#E01E5A' };
function SlackPixelMark({ size = 32, px = 2 }) {
  const N = 12;
  const cells = [];
  for (let y = 0; y < N; y++) for (let x = 0; x < N; x++) {
    let c = null;
    if (x >= 6 && x <= 7 && y >= 0 && y <= 5) c = 'B';
    else if (y >= 6 && y <= 7 && x >= 6 && x <= 11) c = 'Y';
    else if (x >= 4 && x <= 5 && y >= 6 && y <= 11) c = 'G';
    else if (y >= 4 && y <= 5 && x >= 0 && x <= 5) c = 'R';
    cells.push(<div key={x + '-' + y} style={{ width: px, height: px, background: c ? SLACK_C[c] : 'transparent' }} />);
  }
  return (
    <div style={{ width: size, height: size, borderRadius: 5, background: '#FFFFFF',
      display: 'flex', alignItems: 'center', justifyContent: 'center', imageRendering: 'pixelated',
      boxShadow: 'inset 0 0 0 1.5px rgba(0,0,0,0.1)' }}>
      <div style={{ display: 'grid', gridTemplateColumns: `repeat(${N}, ${px}px)`, gridAutoRows: `${px}px` }}>{cells}</div>
    </div>
  );
}

function SeaSignpost({ onTap, mark, label }) {
  return (
    <div onClick={onTap} style={{ position: 'absolute', right: 22, bottom: 140, width: 58, cursor: 'pointer', zIndex: 1,
      opacity: 0.6, filter: 'blur(0.4px) saturate(0.92)' }}>
      <div style={{ position: 'absolute', left: '50%', bottom: 0, transform: 'translateX(-50%)', width: 6, height: 16,
        background: 'linear-gradient(180deg, rgba(21,124,140,0.45), rgba(21,124,140,0))' }} />
      <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', transform: 'scale(0.82)', transformOrigin: '50% 100%',
        animation: 'signBob 3.6s ease-in-out infinite' }}>
        <div style={{ position: 'relative', display: 'inline-flex', flexDirection: 'row', alignItems: 'center', gap: 5,
          padding: '5px 16px 5px 9px', filter: 'drop-shadow(0 0 6px rgba(63,224,216,0.35))' }}>
          <svg viewBox="0 0 100 100" preserveAspectRatio="none" style={{ position: 'absolute', inset: 0, width: '100%', height: '100%' }}>
            <polygon points="1,1 85,1 98,50 85,99 1,99" fill="#0B2A30"
              stroke="rgba(63,224,216,0.7)" strokeWidth="2" vectorEffect="non-scaling-stroke" strokeLinejoin="round" />
          </svg>
          <div style={{ position: 'relative' }}>{mark}</div>
          <span style={{ position: 'relative', fontFamily: PX, fontSize: 7, letterSpacing: 0.5, color: PD.bone }}>{label}</span>
        </div>
        <div style={{ width: 7, height: 54, marginTop: -1,
          background: 'linear-gradient(90deg,#093D45 0 38%, #1A93A4 38% 66%, #093D45 66%)',
          boxShadow: 'inset 0 0 0 1px rgba(0,0,0,0.35)' }} />
      </div>
    </div>
  );
}

function SignPostGlyph() {
  return (
    <div style={{ position: 'relative', width: 20, height: 22 }}>
      <div style={{ position: 'absolute', left: 9, top: 1, width: 2, height: 21, background: PD.ash }} />
      <div style={{ position: 'absolute', left: 4, top: 4, width: 13, height: 5, background: PD.bio,
        clipPath: 'polygon(0 0, 75% 0, 100% 50%, 75% 100%, 0 100%)' }} />
      <div style={{ position: 'absolute', left: 3, top: 12, width: 13, height: 5, background: PD.ash,
        clipPath: 'polygon(25% 0, 100% 0, 100% 100%, 25% 100%, 0 50%)' }} />
    </div>
  );
}

function ConnectionsModal({ onClose, dest, miroConnected, onConnectMiro, onSetActive }) {
  const row = (code, name, hue, connected, action, tile) =>
    <div style={{ display: 'flex', alignItems: 'center', gap: 12, padding: '13px 14px', borderRadius: 3,
      background: PD.fill, boxShadow: `inset 0 0 0 2px ${PD.line}` }}>
      <div style={{ width: 38, height: 38, borderRadius: 3, flexShrink: 0, display: 'flex', alignItems: 'center', justifyContent: 'center',
        background: tile ? 'transparent' : `hsla(${hue},60%,50%,0.18)`, imageRendering: 'pixelated',
        fontFamily: PX, fontSize: 15, color: `hsl(${hue} 75% 72%)`, paddingTop: 2 }}>{code}</div>
      <div style={{ flex: 1, minWidth: 0 }}>
        <div style={{ fontFamily: PXJB, fontSize: 14, fontWeight: 700, color: PD.bone }}>{name}</div>
        <div style={{ fontFamily: PXJB, fontSize: 11, color: connected ? PD_GREEN : PD.faint }}>{connected ? 'Connected' : 'Not connected'}</div>
      </div>
      {action}
    </div>;

  const setActiveBtn = (key) =>
    <span onClick={() => onSetActive(key)} style={{ cursor: 'pointer', height: 30, padding: '0 12px', borderRadius: 3,
      display: 'inline-flex', alignItems: 'center', boxShadow: `inset 0 0 0 1.5px ${PD.edge}`, color: PD.bio,
      fontFamily: PX, fontSize: 8.5, letterSpacing: 0.5, paddingTop: 2 }}>SET ACTIVE</span>;

  const soonRow = (mark, name) =>
    <div style={{ display: 'flex', alignItems: 'center', gap: 12, padding: '13px 14px', borderRadius: 3,
      background: PD.fill, boxShadow: `inset 0 0 0 2px ${PD.line}`, opacity: 0.62 }}>
      <div style={{ width: 38, height: 38, borderRadius: 3, flexShrink: 0, display: 'flex', alignItems: 'center', justifyContent: 'center',
        filter: 'saturate(0.85)' }}>{mark}</div>
      <div style={{ flex: 1, minWidth: 0 }}>
        <div style={{ fontFamily: PXJB, fontSize: 14, fontWeight: 700, color: PD.bone }}>{name}</div>
        <div style={{ fontFamily: PXJB, fontSize: 11, color: PD.faint }}>Coming soon</div>
      </div>
      <span style={{ fontFamily: PX, fontSize: 8, letterSpacing: 0.5, color: PD.faint, padding: '6px 9px 4px',
        borderRadius: 2, boxShadow: `inset 0 0 0 1.5px ${PD.line}` }}>SOON</span>
    </div>;

  return (
    <div style={{ position: 'absolute', inset: 0, zIndex: 12, background: 'linear-gradient(180deg,#06141D 0%,#03090F 70%,#02070C 100%)',
      animation: 'deepIn 0.22s ease both', display: 'flex', flexDirection: 'column' }}>
      <div style={{ position: 'absolute', inset: 0, backgroundImage: PX_GRAIN, opacity: 0.2, mixBlendMode: 'overlay', pointerEvents: 'none' }} />
      <div style={{ padding: '44px 22px 16px', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
          <SignPostGlyph />
          <div style={{ display: 'flex', flexDirection: 'column', gap: 3 }}>
            <span style={{ fontFamily: PX, fontSize: 12, color: PD.bone, letterSpacing: 1 }}>CONNECTIONS</span>
            <span style={{ fontFamily: PXJB, fontSize: 11, color: PD.faint }}>Choose ferry destination</span>
          </div>
        </div>
        <div onClick={onClose} style={{ width: 34, height: 34, borderRadius: 2, cursor: 'pointer',
          background: PD.fill, boxShadow: `inset 0 0 0 2px ${PD.line}`,
          display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
          <svg width="15" height="15" viewBox="0 0 24 24"><path d="M6 6l12 12M18 6L6 18" fill="none" stroke={PD.ash} strokeWidth="2.4" strokeLinecap="round" /></svg>
        </div>
      </div>
      <div style={{ flex: 1, minHeight: 0, overflowY: 'auto', padding: '4px 22px 24px', display: 'flex', flexDirection: 'column', gap: 18 }}>
        <div>
          <div style={{ fontFamily: PX, fontSize: 8.5, letterSpacing: 0.5, color: PD.faint, marginBottom: 10 }}>CONNECTED</div>
          <div style={{ display: 'flex', flexDirection: 'column', gap: 9 }}>
            {row(<FigmaPixelMark cell={8} />, 'Figma', 178, true, dest === 'figma' ? null : setActiveBtn('figma'))}
            {miroConnected && row(<MiroPixelMark size={38} />, 'Miro', 46, true, dest === 'miro' ? null : setActiveBtn('miro'), true)}
          </div>
        </div>
        {!miroConnected &&
          <div>
            <div style={{ fontFamily: PX, fontSize: 8.5, letterSpacing: 0.5, color: PD.faint, marginBottom: 10 }}>AVAILABLE</div>
            {row(<MiroPixelMark size={38} />, 'Miro', 46, false,
              <span onClick={() => onConnectMiro()} style={{ cursor: 'pointer', height: 30, padding: '0 14px', borderRadius: 3,
                display: 'inline-flex', alignItems: 'center', background: 'linear-gradient(135deg,#46E6DC,#129AAC)', color: '#03161A',
                fontFamily: PX, fontSize: 9, letterSpacing: 0.5, paddingTop: 2 }}>CONNECT ACCOUNT</span>, true)}
          </div>
        }
        <div>
          <div style={{ fontFamily: PX, fontSize: 8.5, letterSpacing: 0.5, color: PD.faint, marginBottom: 10 }}>COMING SOON</div>
          <div style={{ display: 'flex', flexDirection: 'column', gap: 9 }}>
            {soonRow(<NotionPixelMark />, 'Notion')}
            {soonRow(<LinearPixelMark />, 'Linear')}
            {soonRow(<SlackPixelMark />, 'Slack')}
          </div>
          <div style={{ fontFamily: PXJB, fontSize: 11, color: PD.faint, marginTop: 12, textAlign: 'center' }}>More integrations on the way</div>
        </div>
      </div>
    </div>
  );
}

// ── mini ferry-sub sprite ──────────────────────────────────────
const FERRY_PAL = {
  H: '#2BBFC2', h: '#178C97', N: '#34CFC8', x: '#0C515C',
  R: '#9FF6EE', t: '#2FC9C2', W: '#FFF6C8', o: '#0A4750',
  G: '#EAFEFF', S: '#1F8E9C', r: '#FF7A8A', f: '#157C8C'
};
const MINI_FERRY = [
  '.........rr...........',
  '........Rrr...........',
  '.......R..............',
  '......RRRRRRRRRRRRRR..',
  '.....RSSSSSR........R.',
  '....RRxxxxxR........RG',
  '...GGSSSSSSSGGGGGGGGGG',
  '..GGoGoGoGoGoGoGoGoGGG',
  '.HHHHHHHHHHHHHHHHHHHHH',
  'GGhHHHHHHHHHHHHHHHHHHh',
  '..hhhhhhhhhhhhhhhhhhh.',
  '....hhhhhhhhhhhhhhhh..'
];
const CABIN_LIT = { x: '#FFD25A', o: '#FFC24A' };

function FSprite({ map, palette, cell = 5, glow = '' }) {
  const cells = [];
  map.forEach((row, y) => row.split('').forEach((ch, x) => {
    const c = palette[ch];
    if (!c) return;
    cells.push(<div key={`${x}-${y}`} style={{
      position: 'absolute', left: x * cell, top: y * cell, width: cell, height: cell,
      background: c, boxShadow: glow.includes(ch) ? `0 0 ${cell}px ${c}` : 'none' }} />);
  }));
  return <div style={{ position: 'relative', width: map[0].length * cell, height: map.length * cell, imageRendering: 'pixelated' }}>{cells}</div>;
}

function Bubbles() {
  const arr = []; let s = 5; const rnd = () => (s = (s * 9301 + 49297) % 233280) / 233280;
  for (let i = 0; i < 11; i++) arr.push({ left: 18 + rnd() * 64, size: 2 + Math.round(rnd() * 3), dur: 1.5 + rnd() * 1.7, delay: -rnd() * 2.2 });
  return (
    <div style={{ position: 'absolute', inset: 0, pointerEvents: 'none' }}>
      {arr.map((b, i) =>
        <span key={i} style={{ position: 'absolute', left: `${b.left}%`, bottom: '42%',
          width: b.size, height: b.size, borderRadius: 99, background: 'rgba(180,255,250,0.7)',
          animation: `bubbleUp ${b.dur}s ease-in ${b.delay}s infinite` }} />
      )}
    </div>
  );
}

function HullBubbles() {
  const arr = []; let s = 13; const rnd = () => (s = (s * 9301 + 49297) % 233280) / 233280;
  for (let i = 0; i < 14; i++) arr.push({
    left: 34 + rnd() * 46, top: 44 + rnd() * 18, size: 2 + Math.round(rnd() * 3),
    dur: 2.4 + rnd() * 2.4, delay: -rnd() * 5, dx: (rnd() * 8 - 2).toFixed(1) });
  return (
    <div style={{ position: 'absolute', inset: 0, pointerEvents: 'none' }}>
      {arr.map((b, i) =>
        <span key={i} style={{ position: 'absolute', left: b.left, top: b.top,
          width: b.size, height: b.size, borderRadius: 99, background: 'rgba(180,255,250,0.6)',
          boxShadow: '0 0 4px rgba(150,240,235,0.5)', ['--bx']: `${b.dx}px`,
          animation: `bubbleRise ${b.dur}s ease-in ${b.delay}s infinite` }} />
      )}
    </div>
  );
}

function ExitTrail() {
  const arr = []; let s = 29; const rnd = () => (s = (s * 9301 + 49297) % 233280) / 233280;
  const N = 22;
  for (let i = 0; i < N; i++) {
    const t = i / (N - 1), e = t * t;
    arr.push({ x: 52 + (470 - 52) * e + (rnd() * 8 - 4), y: 40 + (88 - 40) * e + (rnd() * 6 - 3),
      size: 2 + Math.round(rnd() * 3), delay: +(t * 1.95).toFixed(2),
      dur: 1.3 + rnd() * 1.2, dx: (rnd() * 8 - 2).toFixed(1) });
  }
  return (
    <div style={{ position: 'absolute', inset: 0, pointerEvents: 'none' }}>
      {arr.map((b, i) =>
        <span key={i} style={{ position: 'absolute', left: b.x, top: b.y,
          width: b.size, height: b.size, borderRadius: 99, background: 'rgba(180,255,250,0.6)',
          boxShadow: '0 0 4px rgba(150,240,235,0.5)', ['--bx']: `${b.dx}px`,
          animation: `bubbleRise ${b.dur}s ease-in ${b.delay}s both` }} />
      )}
    </div>
  );
}

function FerrySmoke() {
  const puffs = [
    { d: 0.0, x: 65, y: 34, s: 3 }, { d: 0.4, x: 67, y: 33, s: 4 },
    { d: 0.8, x: 64, y: 35, s: 3 }, { d: 1.2, x: 68, y: 32, s: 5 },
    { d: 1.6, x: 66, y: 34, s: 4 }, { d: 2.0, x: 65, y: 33, s: 3 },
    { d: 2.4, x: 67, y: 35, s: 5 }, { d: 2.8, x: 64, y: 32, s: 4 }
  ];
  return (
    <div style={{ position: 'absolute', inset: 0, pointerEvents: 'none', zIndex: -1 }}>
      {puffs.map((p, i) =>
        <span key={i} style={{ position: 'absolute', left: p.x, top: p.y,
          width: p.s, height: p.s, background: '#D2EBEE',
          animation: `ferrySmoke 3.2s linear ${p.d}s infinite` }} />
      )}
    </div>
  );
}

function FerryLights() {
  const win = [18, 30, 42, 54, 66, 78];
  return (
    <div style={{ position: 'absolute', inset: 0, pointerEvents: 'none' }}>
      <span style={{ position: 'absolute', left: 12, top: 33, width: 84, height: 16,
        background: 'radial-gradient(ellipse at center, rgba(255,221,150,0.45), transparent 72%)',
        animation: 'deepIn 0.4s ease 0.08s both' }} />
      {win.map((x, i) =>
        <span key={i} style={{ position: 'absolute', left: x, top: 41, width: 4, height: 4, borderRadius: 1,
          background: '#FFE7AE',
          animation: `lightOn 0.28s ease ${0.08 + i * 0.04}s both, lightFlick 2.6s ease-in-out ${0.9 + i * 0.1}s infinite` }} />
      )}
      <span style={{ position: 'absolute', left: 72, top: 45, width: 40, height: 24, transform: 'translate(-50%,-50%)',
        background: 'radial-gradient(ellipse at center, rgba(255,196,72,0.55), rgba(255,196,72,0.12) 55%, transparent 75%)',
        animation: 'deepIn 0.35s ease 0.1s both' }} />
    </div>
  );
}

function FerryLoad({ onDone, count = 6 }) {
  const { useEffect, useMemo } = React;
  useEffect(() => { const t = setTimeout(onDone, 2860); return () => clearTimeout(t); }, []);
  const shots = useMemo(() => {
    const n = Math.max(1, count);
    const startT = 0.45, endT = 1.95, span = endT - startT;
    const dur = Math.max(0.26, Math.min(0.8, 4.8 / n));
    let s = 7; const rnd = () => (s = (s * 9301 + 49297) % 233280) / 233280;
    return Array.from({ length: n }, (_, i) => ({
      x: Math.round(rnd() * 56 - 28),
      delay: +(startT + (n === 1 ? 0 : span * i / (n - 1))).toFixed(3),
      dur: +dur.toFixed(3) }));
  }, [count]);
  return (
    <div style={{ position: 'absolute', inset: 0, pointerEvents: 'none', zIndex: 4 }}>
      <div style={{ position: 'absolute', left: 26, top: 33, width: 18, height: 9,
        background: 'radial-gradient(ellipse at center, rgba(159,246,238,0.75), transparent 70%)',
        animation: 'deepIn 0.3s ease 0.3s both, pxBlink 1.1s steps(2) 0.6s infinite' }} />
      {shots.map((sh, i) =>
        <div key={i} style={{ position: 'absolute', left: 28, top: 29, ['--sx']: sh.x + 'px',
          width: 13, height: 16,
          animation: `shotLoad ${sh.dur}s cubic-bezier(0.5,0,0.3,1) ${sh.delay}s both` }}>
          <div style={{ width: '100%', height: '100%', background: '#0C515C',
            boxShadow: 'inset 0 0 0 1.5px #9FF6EE, 0 0 6px rgba(70,230,225,0.5)',
            display: 'flex', flexDirection: 'column', gap: 1.5, padding: 2.5, justifyContent: 'flex-end' }}>
            <span style={{ height: 2, background: '#46E6DC' }} />
            <span style={{ height: 2, width: '60%', background: '#2FC9C2' }} />
          </div>
        </div>
      )}
      <div style={{ position: 'absolute', left: 23, top: 33, width: 23, height: 8,
        background: 'linear-gradient(180deg,#34CFC8,#157C8C)', boxShadow: 'inset 0 0 0 1px #0A4750',
        transformOrigin: '1px 8px', animation: 'ferryHatch 2.86s ease both', zIndex: 5 }} />
    </div>
  );
}

function ForwardWake() {
  const streaks = [
    { y: 44, d: 0.0, w: 16, o: 0.5 }, { y: 50, d: 0.35, w: 22, o: 0.65 },
    { y: 56, d: 0.7, w: 14, o: 0.45 }, { y: 47, d: 0.5, w: 20, o: 0.55 },
    { y: 53, d: 0.9, w: 18, o: 0.5 }
  ];
  const spray = [{ d: 0.0, s: 3 }, { d: 0.35, s: 2 }, { d: 0.7, s: 3 }, { d: 1.05, s: 2 }, { d: 0.5, s: 2 }];
  return (
    <div style={{ position: 'absolute', inset: 0, pointerEvents: 'none' }}>
      {streaks.map((s, i) =>
        <span key={'s' + i} style={{ position: 'absolute', left: 42, top: s.y, width: s.w, height: 2,
          background: `linear-gradient(90deg, transparent, rgba(180,255,250,${s.o}))`,
          animation: `wakeStreak 1s linear ${s.d}s infinite` }} />
      )}
      {spray.map((p, i) =>
        <span key={'p' + i} style={{ position: 'absolute', left: 92, top: 47, width: p.s, height: p.s,
          borderRadius: 99, background: 'rgba(220,255,252,0.92)',
          animation: `bowSpray 0.9s ease-out ${p.d}s infinite` }} />
      )}
    </div>
  );
}

const deepBg = 'linear-gradient(180deg, #0A2230 0%, #07151F 30%, #040C13 64%, #02070C 100%)';

function DeepDecor() {
  const ov = (extra) => ({ position: 'absolute', inset: 0, pointerEvents: 'none', ...extra });
  return (
    <React.Fragment>
      <div style={ov({ height: '46%',
        background: 'repeating-conic-gradient(rgba(90,225,225,0.13) 0% 25%, transparent 0% 50%) 0 0 / 6px 6px',
        WebkitMaskImage: 'radial-gradient(80% 100% at 50% 0%, #000 0%, transparent 70%)',
        maskImage: 'radial-gradient(80% 100% at 50% 0%, #000 0%, transparent 70%)' })} />
      <div style={ov({ backgroundImage: 'repeating-linear-gradient(0deg, rgba(120,200,210,0.035) 0 1px, transparent 1px 16px), repeating-linear-gradient(90deg, rgba(120,200,210,0.035) 0 1px, transparent 1px 16px)' })} />
      <PixelLeviathan />
      <PixelSnow />
      <div style={ov({ background: 'linear-gradient(180deg, transparent 42%, rgba(0,4,8,0.55) 100%)' })} />
      <div style={ov({ boxShadow: 'inset 0 0 120px 26px rgba(0,3,6,0.6)' })} />
      <div style={ov({ backgroundImage: PX_GRAIN, opacity: 0.26, mixBlendMode: 'overlay' })} />
    </React.Fragment>
  );
}

// ── RECENT GROUP NAMES ────────────────────────────────────────
const RECENT_KEY = 'ferry_recent_groups';
function getRecent() { try { return JSON.parse(localStorage.getItem(RECENT_KEY) || '[]'); } catch { return []; } }
function saveRecent(name) {
  const updated = [name, ...getRecent().filter(g => g !== name)].slice(0, 5);
  localStorage.setItem(RECENT_KEY, JSON.stringify(updated));
}

// ─────────────────────────────────────────────────────────────
// MAIN FERRY SCREEN
// ─────────────────────────────────────────────────────────────
function OptionFerryPixel({ user, token }) {
  const { useState, useEffect, useRef } = React;
  const [phase, setPhase] = useState('idle');
  const [pct, setPct] = useState(0);
  const [entering, setEntering] = useState(false);
  const [shipHidden, setShipHidden] = useState(false);
  const [connected, setConnected] = useState(true);
  const [step1Open, setStep1Open] = useState(false);
  const [batchName, setBatchName] = useState('');
  const [recentGroups, setRecentGroups] = useState(() => getRecent());
  const [files, setFiles] = useState([]);
  const [shotsOpen, setShotsOpen] = useState(false);
  const [connOpen, setConnOpen] = useState(false);
  const [dest, setDest] = useState('figma');
  const [miroConnected, setMiroConnected] = useState(false);
  const [everFerried, setEverFerried] = useState(false);
  const [pairingCode, setPairingCode] = useState(() => localStorage.getItem('ferry_pairing_code'));
  const [errorMsg, setErrorMsg] = useState('');
  const [keyboardOpen, setKeyboardOpen] = useState(false);
  const fileInputRef = useRef(null);

  const DEST_NAME = dest === 'miro' ? 'Miro' : 'Figma';
  const DEST_LABEL = dest === 'miro' ? 'MIRO' : 'FIGMA';
  const avatarMark = dest === 'miro' ? <MiroPixelMark size={44} /> : <FigmaPixelMark cell={9} />;
  const signMark = dest === 'miro' ? <MiroPixelMark size={14} px={0.6} /> : <FigmaPixelMark cell={5} />;

  // Display username from pairing code or user profile
  const codeHandle = pairingCode && pairingCode.includes('#') ? pairingCode.split('#')[0] : null;
  const codeDisc = pairingCode && pairingCode.includes('#') ? pairingCode.split('#')[1] : null;
  const displayHandle = codeHandle || user.handle || '—';
  const displayDisc = codeDisc;

  // Fetch pairing code on mount if not cached
  useEffect(() => {
    if (pairingCode || !token) return;
    fetch('/auth/pair', { method: 'POST', headers: { Authorization: 'Bearer ' + token } })
      .then(r => r.ok ? r.json() : null)
      .then(d => { if (d && d.code) { setPairingCode(d.code); localStorage.setItem('ferry_pairing_code', d.code); } })
      .catch(() => {});
  }, []);

  // Upload progress ticker
  useEffect(() => {
    if (phase !== 'sending') return;
    let p = 0; setPct(0);
    const id = setInterval(() => {
      p += Math.random() * 7 + 3.5;
      if (p >= 95) { setPct(95); clearInterval(id); }
      else setPct(Math.round(p));
    }, 150);
    return () => clearInterval(id);
  }, [phase]);

  function openPicker() { fileInputRef.current && fileInputRef.current.click(); }

  function handleFileInput(e) {
    const picked = Array.from(e.target.files || []);
    setFiles(prev => [...prev, ...picked]);
    e.target.value = '';
  }

  async function doUpload() {
    setErrorMsg('');
    const name = batchName.trim() || 'Untitled';
    const fd = new FormData();
    fd.append('groupName', name);
    files.forEach(f => fd.append('screenshots', f));
    try {
      const res = await fetch('/images/upload', {
        method: 'POST',
        headers: { Authorization: 'Bearer ' + token },
        body: fd
      });
      if (!res.ok) throw new Error('Upload failed (' + res.status + ')');
      saveRecent(name);
      setRecentGroups(getRecent());
      setPct(100);
      setTimeout(() => setPhase('done'), 700);
      setEverFerried(true);
    } catch (err) {
      setErrorMsg(err.message || 'Upload failed');
      setPhase('idle');
    }
  }

  function onLoadDone() { setPhase('sending'); doUpload(); }

  function startFerry() { if (phase === 'idle' && files.length > 0) setPhase('loading'); }

  function ferryAgain() {
    setShipHidden(true);
    setFiles([]);
    setBatchName('');
    setPhase('idle');
    setTimeout(() => {
      setShipHidden(false);
      setEntering(true);
      setTimeout(() => setEntering(false), 1300);
    }, 1150);
  }

  function handleLogout() {
    ['ferry_token', 'ferry_user', 'ferry_connected', 'ferry_pairing_code'].forEach(k => localStorage.removeItem(k));
    window.location.href = '/';
  }

  const sending = phase === 'sending';
  const done = phase === 'done';
  const loading = phase === 'loading';
  const atSurface = phase === 'idle' || loading;

  return (
    <div style={{ position: 'relative', height: '100%', overflow: 'hidden', background: deepBg, fontFamily: PXJB, color: PD.bone }}>
      <input ref={fileInputRef} type="file" accept="image/*" multiple style={{ display: 'none' }} onChange={handleFileInput} />

      {/* ── DEEP / PROGRESS WORLD ── */}
      {(sending || done) &&
        <div style={{ position: 'absolute', inset: 0, zIndex: 1, background: deepBg, animation: 'deepIn 0.5s ease both' }}>
          <DeepDecor />
          <div style={{ position: 'absolute', left: 0, right: 0, bottom: 70, display: 'flex', justifyContent: 'center', gap: 44, opacity: 0.5 }}>
            <span style={{ width: 10, height: 10, background: PD.bio, boxShadow: `0 0 12px ${PD.bio}`, animation: 'pxBlink 5s steps(2) infinite' }} />
            <span style={{ width: 8, height: 8, background: PD.bio, boxShadow: `0 0 10px ${PD.bio}`, animation: 'pxBlink 5s steps(2) .4s infinite' }} />
          </div>
          {sending &&
            <div style={{ position: 'absolute', left: 0, right: 0, top: '56%', display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 22, padding: '0 30px', animation: 'textRise 0.5s ease 0.5s both' }}>
              <div style={{ fontFamily: PX, fontSize: 13, color: PD.bone, letterSpacing: 1 }}>FERRYING TO {DEST_LABEL}</div>
              <div style={{ width: '100%', maxWidth: 240 }}>
                <div style={{ height: 16, background: PD.fill, boxShadow: `inset 0 0 0 2px ${PD.line}`, padding: 3, borderRadius: 2 }}>
                  <div style={{ height: '100%', width: `${pct}%`, borderRadius: 1, background: 'linear-gradient(90deg,#159FB0,#46E6DC 70%,#9FF6EE)', transition: 'width 0.15s linear', boxShadow: `0 0 10px ${PD.bio}` }} />
                </div>
                <div style={{ display: 'flex', justifyContent: 'space-between', marginTop: 10, fontFamily: PX, fontSize: 9, letterSpacing: 0.5, color: PD.ash }}>
                  <span>{files.length} SCREENSHOTS</span><span style={{ color: PD.bio }}>{pct}%</span>
                </div>
              </div>
            </div>
          }
          {done &&
            <div style={{ position: 'absolute', left: 0, right: 0, top: '52%', display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 16, padding: '0 30px', animation: 'popIn 0.4s ease-out both' }}>
              <div style={{ width: 36, height: 36, background: PD.bioDim, boxShadow: `inset 0 0 0 2px rgba(63,224,216,0.5)`, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
                <Icon name="check" size={20} color={PD.bio} stroke={3} />
              </div>
              <div style={{ fontFamily: PX, fontSize: 13, color: PD.bone, letterSpacing: 1 }}>DELIVERED</div>
              <div style={{ fontFamily: PXJB, fontSize: 12.5, color: PD.ash, textAlign: 'center' }}>{files.length} screenshots in your {DEST_NAME} inbox</div>
              <div onClick={ferryAgain} style={{ marginTop: 4, height: 42, padding: '0 20px', display: 'flex', alignItems: 'center', cursor: 'pointer', borderRadius: 3, background: PD.fill, boxShadow: `inset 0 0 0 2px rgba(63,224,216,0.5)`, fontFamily: PX, fontSize: 10, color: PD.bio, letterSpacing: 0.5, paddingTop: 2 }}>
                FERRY AGAIN
              </div>
            </div>
          }
        </div>
      }

      {/* ── IDLE WORLD ── */}
      <div style={{ position: 'absolute', inset: 0, zIndex: 2, background: deepBg, overflow: 'hidden',
        transform: atSurface ? 'translateY(0)' : 'translateY(-122%)',
        transition: 'transform 1.05s cubic-bezier(0.6,0.02,0.28,1)',
        pointerEvents: phase === 'idle' ? 'auto' : 'none' }}>
        <DeepDecor />
        <div style={{ position: 'relative', height: '100%', display: 'flex', flexDirection: 'column' }}>
          <div style={{ flex: 1, minHeight: 0, overflowY: 'auto', overflowX: 'hidden', WebkitOverflowScrolling: 'touch' }}>

            {/* brand row */}
            <div style={{ padding: '44px 22px 0', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
              <div style={{ display: 'flex', alignItems: 'center', gap: 9, minWidth: 0 }}>
                <span style={{ width: 9, height: 9, flexShrink: 0, background: PD.bio, boxShadow: `0 0 8px ${PD.bio}` }} />
                <span style={{ fontFamily: PX, fontSize: 14, color: PD.bone, letterSpacing: 1 }}>FERRY</span>
                {everFerried
                  ? <span style={{ fontFamily: PXJB, fontSize: 10.5, color: PD.ash, whiteSpace: 'nowrap' }}>· Last ferried <span style={{ color: PD.bone, fontWeight: 600 }}>just now</span></span>
                  : <span style={{ fontFamily: PXJB, fontSize: 10.5, color: PD.faint, whiteSpace: 'nowrap' }}>· No crossings yet</span>}
              </div>
              <div onClick={handleLogout} style={{ width: 36, height: 36, borderRadius: 2, background: PD.fill,
                boxShadow: `inset 0 0 0 2px ${PD.line}`, display: 'flex', alignItems: 'center', justifyContent: 'center', cursor: 'pointer' }}>
                <Icon name="logout" size={16} color={PD.ash} />
              </div>
            </div>

            {/* greeting */}
            <div style={{ padding: '14px 22px 18px', display: 'flex', alignItems: 'center', gap: 13 }}>
              <div onClick={() => setConnOpen(true)}
                style={{ width: 44, height: 44, borderRadius: dest === 'miro' ? 12 : 3, flexShrink: 0, cursor: 'pointer',
                  background: dest === 'miro' ? 'transparent' : 'linear-gradient(150deg,#0E3A44,#08272F 70%,#041519)',
                  boxShadow: '0 5px 16px -4px rgba(63,224,216,0.55)', display: 'flex', alignItems: 'center', justifyContent: 'center',
                  imageRendering: 'pixelated' }}>{avatarMark}</div>
              <div style={{ flex: 1, minWidth: 0 }}>
                <div style={{ fontFamily: PXJB, fontSize: 12, color: PD.ash, fontWeight: 500 }}>Hey,</div>
                <div style={{ fontFamily: PXJB, fontSize: 22, fontWeight: 700, lineHeight: 1.05, letterSpacing: -0.5, color: 'rgb(211,216,217)' }}>
                  {displayHandle}{displayDisc ? <span style={{ color: PD.faint }}>#{displayDisc}</span> : null}
                </div>
              </div>
            </div>

            {/* steps */}
            <div style={{ padding: '0 22px 12px' }}>
              <PixelStep n="1"
                title={connected
                  ? <span style={{ display: 'inline-flex', alignItems: 'center', gap: 7 }}>
                      Connected to {DEST_NAME}
                      <span style={{ display: 'inline-flex', transition: 'transform .25s ease', transform: step1Open ? 'rotate(-90deg)' : 'rotate(90deg)' }}>
                        <Icon name="chevR" size={15} color={PD.ash} />
                      </span>
                    </span>
                  : `Connect to ${DEST_NAME} plugin`}
                open={!connected || step1Open}
                onHeaderClick={connected ? () => setStep1Open(o => !o) : undefined}
                badge={connected
                  ? <div style={{ width: 24, height: 24, flexShrink: 0, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
                      <span style={{ width: 11, height: 11, borderRadius: 99, background: PD_GREEN, animation: 'beacon 1.9s ease-in-out infinite' }} />
                    </div>
                  : undefined}>
                <div style={{ fontFamily: PXJB, fontSize: 11.5, color: PD.faint }}>Open the plugin inside {DEST_NAME} to pair this phone.</div>
                <div onClick={() => { setConnected(c => !c); setStep1Open(false); }}
                  style={{ marginTop: 13, display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
                    height: 34, padding: '0 16px', paddingTop: 2, borderRadius: 3, cursor: 'pointer',
                    fontFamily: PX, fontSize: 8.5, letterSpacing: 0.5, userSelect: 'none',
                    ...(connected
                      ? { color: PD.ash, background: PD.fill, boxShadow: `inset 0 0 0 2px ${PD.line}` }
                      : { color: '#03161A', background: 'linear-gradient(135deg,#46E6DC,#129AAC)', boxShadow: 'inset 0 0 0 2px rgba(180,255,250,0.35)' }) }}>
                  {connected ? 'DISCONNECT' : "It's connected"}
                </div>
              </PixelStep>

              <PixelStep n="2" title="Name this batch">
                <div style={{ height: 50, borderRadius: 3, background: PD.fill, boxShadow: `inset 0 0 0 2px ${PD.line}`,
                  display: 'flex', alignItems: 'center', gap: 10, padding: '0 14px' }}>
                  <Icon name="tag" size={16} color={PD.faint} />
                  <input className="ferryBatchInput"
                    value={batchName}
                    onChange={e => setBatchName(e.target.value)}
                    placeholder="Name this batch…"
                    enterKeyHint="done"
                    onKeyDown={e => { if (e.key === 'Enter') e.currentTarget.blur(); }}
                    onFocus={() => setKeyboardOpen(true)}
                    onBlur={() => setKeyboardOpen(false)}
                    style={{ flex: 1, minWidth: 0, border: 'none', outline: 'none', background: 'transparent',
                      fontFamily: PXJB, fontSize: 15, fontWeight: 600, color: PD.bone, caretColor: PD.bio, padding: 0 }} />
                  {batchName &&
                    <div onClick={() => setBatchName('')} style={{ width: 22, height: 22, flexShrink: 0, borderRadius: 2, cursor: 'pointer',
                      display: 'flex', alignItems: 'center', justifyContent: 'center', boxShadow: `inset 0 0 0 1.5px ${PD.line}` }}>
                      <svg width="11" height="11" viewBox="0 0 24 24"><path d="M6 6l12 12M18 6L6 18" fill="none" stroke={PD.ash} strokeWidth="2.6" strokeLinecap="round" /></svg>
                    </div>
                  }
                </div>
                {recentGroups.length > 0 && everFerried &&
                  <div style={{ marginTop: 11, display: 'flex', flexWrap: 'wrap', gap: 7, alignItems: 'center' }}>
                    <span style={{ fontFamily: PX, fontSize: 8, letterSpacing: 0.5, color: PD.faint }}>RECENT</span>
                    {recentGroups.map(r => {
                      const on = batchName === r;
                      return (
                        <span key={r} onClick={() => setBatchName(r)} style={{ cursor: 'pointer', height: 26,
                          display: 'inline-flex', alignItems: 'center', padding: '0 11px', borderRadius: 2, whiteSpace: 'nowrap',
                          fontFamily: PXJB, fontSize: 11.5, fontWeight: 600,
                          color: on ? '#03161A' : PD.ash, background: on ? PD.bio : PD.fill,
                          boxShadow: on ? 'none' : `inset 0 0 0 1.5px ${PD.line}` }}>{r}</span>
                      );
                    })}
                  </div>
                }
              </PixelStep>

              <PixelStep n="3" title="Pick screenshots" last>
                {files.length === 0
                  ? <div onClick={openPicker} style={{ cursor: 'pointer', borderRadius: 4, padding: '15px 16px',
                      display: 'flex', flexDirection: 'row', alignItems: 'center', justifyContent: 'flex-start', gap: 12,
                      boxShadow: `inset 0 0 0 2px ${PD.line}`,
                      backgroundImage: 'repeating-linear-gradient(45deg, rgba(120,200,210,0.05) 0 8px, transparent 8px 16px)' }}>
                      <div style={{ width: 30, height: 30, flexShrink: 0, borderRadius: 4, display: 'flex', alignItems: 'center', justifyContent: 'center',
                        background: PD.bioDim, boxShadow: `inset 0 0 0 2px ${PD.edge}` }}>
                        <Icon name="plus" size={18} color={PD.bio} />
                      </div>
                      <div style={{ fontFamily: PX, fontSize: 9.5, letterSpacing: 0.5, color: PD.bone }}>ADD SCREENSHOTS</div>
                    </div>
                  : <React.Fragment>
                      <div style={{ marginBottom: 11, display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
                        <span onClick={() => setShotsOpen(true)} style={{ cursor: 'pointer', display: 'inline-flex', alignItems: 'center', gap: 7, height: 24, padding: '0 10px 0 8px',
                          borderRadius: 2, background: PD.bioDim, color: PD.bio, fontFamily: PX, fontSize: 8, letterSpacing: 0.5, paddingTop: 1 }}>
                          <span style={{ width: 5, height: 5, background: PD.bio }} /> {files.length} SELECTED
                        </span>
                        <span onClick={openPicker} style={{ cursor: 'pointer', display: 'inline-flex', alignItems: 'center', gap: 5,
                          height: 24, padding: '0 11px 0 9px', borderRadius: 2, background: PD.fill, boxShadow: `inset 0 0 0 1.5px ${PD.edge}`,
                          fontFamily: PX, fontSize: 8, letterSpacing: 0.5, color: PD.bio, paddingTop: 1 }}>
                          <Icon name="plus" size={12} color={PD.bio} /> ADD
                        </span>
                      </div>
                      <div onClick={() => setShotsOpen(true)} style={{ display: 'flex', gap: 8, cursor: 'pointer' }}>
                        {files.slice(0, 4).map((f, i) =>
                          <div key={i} style={{ width: 60, flexShrink: 0 }}><RealThumb file={f} /></div>
                        )}
                        {files.length > 4 &&
                          <div style={{ width: 60, flexShrink: 0, aspectRatio: '1 / 1.18', borderRadius: 3,
                            boxShadow: `inset 0 0 0 2px ${PD.line}`, display: 'flex', alignItems: 'center', justifyContent: 'center', color: PD.bone }}>
                            <span style={{ fontFamily: PX, fontSize: 17 }}>+{files.length - 4}</span>
                          </div>
                        }
                      </div>
                    </React.Fragment>
                }
              </PixelStep>
            </div>
          </div>{/* end scroll region */}

          {/* sea surface — collapses when keyboard is open so the form stays visible */}
          <div style={{ position: 'relative', flexShrink: 0, overflow: 'hidden', zIndex: 2,
            height: keyboardOpen ? 0 : 80, marginBottom: keyboardOpen ? 0 : 44,
            transition: 'height 0.22s ease, margin-bottom 0.22s ease' }}>
            <div style={{ position: 'absolute', left: 0, right: 0, bottom: 0, height: 28,
              background: 'linear-gradient(180deg, rgba(70,230,225,0.18), rgba(20,120,140,0.04))' }} />
            <div style={{ position: 'absolute', left: -14, right: -14, bottom: 27, height: 3,
              backgroundImage: 'repeating-linear-gradient(90deg, rgba(180,255,250,0.55) 0 7px, transparent 7px 14px)',
              animation: 'ferryWave 1.6s linear infinite' }} />
          </div>

          {!keyboardOpen && <SeaSignpost onTap={() => setConnOpen(true)} mark={signMark} label={DEST_LABEL} />}

          {errorMsg && <div style={{ padding: '0 22px 6px', fontFamily: PXJB, fontSize: 11, color: '#FF7A8A', textAlign: 'center' }}>{errorMsg}</div>}

          {/* CTA */}
          <div style={{ position: 'relative', flexShrink: 0, padding: keyboardOpen ? '4px 22px 10px' : '4px 22px 46px',
            transition: 'padding 0.22s ease' }}>
            <div onClick={startFerry} style={{
              height: 56, borderRadius: 4, cursor: files.length > 0 ? 'pointer' : 'not-allowed',
              display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 10,
              background: files.length > 0 ? 'linear-gradient(135deg,#46E6DC,#129AAC)' : PD.fill,
              boxShadow: files.length > 0 ? `0 12px 30px -8px rgba(63,224,216,0.6), inset 0 0 0 2px rgba(180,255,250,0.4)` : `inset 0 0 0 2px ${PD.line}`,
              fontFamily: PX, fontSize: 12, color: files.length > 0 ? '#03161A' : PD.faint, letterSpacing: 0.5, paddingTop: 2 }}>
              <span>{files.length > 0 ? `FERRY ${files.length} TO ${DEST_LABEL}` : `FERRY TO ${DEST_LABEL}`}</span>
              <Icon name="arrow" size={18} color={files.length > 0 ? '#03161A' : PD.faint} stroke={2.6} />
            </div>
          </div>
        </div>
      </div>

      {/* ── THE FERRY ── */}
      <div style={{ position: 'absolute', left: '50%', zIndex: 3,
        top: atSurface ? 'calc(100% - 226px)' : '40%',
        transition: 'top 1.15s cubic-bezier(0.5,0,0.25,1)',
        opacity: keyboardOpen ? 0 : 1, pointerEvents: keyboardOpen ? 'none' : 'auto',
        transition: 'top 1.15s cubic-bezier(0.5,0,0.25,1), opacity 0.18s ease' }}>
        <div style={{ position: 'relative', width: 120, height: 96, marginLeft: -60,
          transform: `scale(${atSurface ? 1 : 1.14})`, transformOrigin: '50% 42%',
          transition: 'transform 1.15s cubic-bezier(0.5,0,0.25,1)' }}>
          {atSurface && !shipHidden && <FerrySmoke />}
          {loading && <ForwardWake />}
          {(sending || done) && <Bubbles />}
          {done && <ExitTrail />}
          {(sending || done) &&
            <div style={{ position: 'absolute', inset: 0,
              animation: done
                ? 'ferryExit 2.4s cubic-bezier(0.4,0,0.85,0.95) both'
                : 'ferryDive 1.5s cubic-bezier(0.5,0,0.35,1) both, ferrySubSway 3.4s ease-in-out 1.5s infinite' }}>
              <FerryLights />
              {sending && <HullBubbles />}
            </div>
          }
          <div style={{ position: 'absolute', left: '50%', top: '50%', transform: 'translate(-50%,-50%)' }}>
            <div style={{
              transform: shipHidden ? 'translateX(-300px)' : undefined,
              animation: shipHidden ? 'none'
                : sending ? 'ferryDive 1.5s cubic-bezier(0.5,0,0.35,1) both, ferrySubSway 3.4s ease-in-out 1.5s infinite'
                : done ? 'ferryExit 2.4s cubic-bezier(0.4,0,0.85,0.95) both'
                : entering ? 'ferryEnter 1.2s cubic-bezier(0.2,0.7,0.25,1) both, ferryBob 2.8s ease-in-out 1.2s infinite'
                : 'ferryBob 2.8s ease-in-out infinite' }}>
              <div style={{ transform: 'scaleX(-1)', position: 'relative' }}>
                <FSprite map={MINI_FERRY} palette={FERRY_PAL} cell={5} glow="r" />
                {(sending || done) &&
                  <div style={{ position: 'absolute', left: 0, top: 0,
                    animation: 'deepIn 0.3s ease 0.08s both, lightFlick 2.4s ease-in-out 0.9s infinite' }}>
                    <FSprite map={MINI_FERRY} palette={CABIN_LIT} cell={5} glow="xo" />
                  </div>
                }
              </div>
            </div>
          </div>
          {loading && <FerryLoad onDone={onLoadDone} count={files.length} />}
        </div>
      </div>

      {shotsOpen && <ShotsModal onClose={() => setShotsOpen(false)} files={files} />}
      {connOpen && <ConnectionsModal onClose={() => setConnOpen(false)} dest={dest} miroConnected={miroConnected}
        onConnectMiro={() => { setMiroConnected(true); setDest('miro'); setConnOpen(false); }}
        onSetActive={key => { setDest(key); setConnOpen(false); }} />}
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// LOGIN SCREEN
// ─────────────────────────────────────────────────────────────
const LOGIN_SERVICES = {
  figma: { name: 'Figma', mark: <FigmaPixelMark cell={6} /> },
  miro: { name: 'Miro', mark: <MiroPixelMark size={26} /> },
};

function ServiceDropdown({ service, setService }) {
  const { useState } = React;
  const [open, setOpen] = useState(false);
  const cur = LOGIN_SERVICES[service];
  return (
    <div style={{ position: 'relative' }}>
      {open &&
        <div style={{ position: 'absolute', left: 0, right: 0, bottom: 'calc(100% + 8px)', borderRadius: 4, overflow: 'hidden',
          background: '#06222B', boxShadow: `inset 0 0 0 2px ${PD.line}, 0 14px 34px -10px rgba(0,0,0,0.7)`, zIndex: 6 }}>
          {Object.keys(LOGIN_SERVICES).map((k, i) =>
            <div key={k} onClick={() => { setService(k); setOpen(false); }}
              style={{ display: 'flex', alignItems: 'center', gap: 12, padding: '13px 14px', cursor: 'pointer',
                background: k === service ? PD.fill : 'transparent', boxShadow: i > 0 ? `inset 0 1.5px 0 ${PD.line}` : 'none' }}>
              <div style={{ width: 30, display: 'flex', justifyContent: 'center' }}>{LOGIN_SERVICES[k].mark}</div>
              <span style={{ flex: 1, fontFamily: PXJB, fontSize: 14.5, fontWeight: 700, color: PD.bone }}>{LOGIN_SERVICES[k].name}</span>
              {k === service && <Icon name="check" size={15} color={PD.bio} stroke={2.6} />}
            </div>
          )}
        </div>
      }
      <div onClick={() => setOpen(o => !o)}
        style={{ height: 54, borderRadius: 4, cursor: 'pointer', display: 'flex', alignItems: 'center', gap: 13, padding: '0 16px',
          background: PD.fill, boxShadow: `inset 0 0 0 2px ${open ? PD.edge : PD.line}` }}>
        <div style={{ width: 30, display: 'flex', justifyContent: 'center' }}>{cur.mark}</div>
        <div style={{ flex: 1, display: 'flex', flexDirection: 'column', gap: 1 }}>
          <span style={{ fontFamily: PXJB, fontSize: 10, color: PD.faint }}>Destination</span>
          <span style={{ fontFamily: PXJB, fontSize: 15, fontWeight: 700, color: PD.bone }}>{cur.name}</span>
        </div>
        <span style={{ display: 'inline-flex', transition: 'transform .2s ease', transform: open ? 'rotate(-90deg)' : 'rotate(90deg)' }}>
          <Icon name="chevR" size={16} color={PD.faint} />
        </span>
      </div>
    </div>
  );
}

function OptionFerryLogin() {
  const { useState } = React;
  const [service, setService] = useState('figma');
  const cur = LOGIN_SERVICES[service];

  const bub = [
    { l: -6, t: 6, s: 3, d: 0.0, rise: 60, drift: -6 },
    { l: 4, t: 2, s: 4, d: 0.6, rise: 72, drift: 5 },
    { l: -2, t: 9, s: 5, d: 0.3, rise: 64, drift: -3 },
    { l: 11, t: 4, s: 3, d: 1.0, rise: 76, drift: 8 },
    { l: 1, t: 7, s: 4, d: 1.5, rise: 62, drift: -5 },
    { l: 8, t: 2, s: 3, d: 1.9, rise: 70, drift: 4 },
    { l: -9, t: 6, s: 4, d: 2.4, rise: 74, drift: -7 },
  ];

  return (
    <div style={{ position: 'relative', height: '100%', overflow: 'hidden', background: deepBg, fontFamily: PXJB, color: PD.bone }}>
      <style>{`
        @keyframes lgBob { 0%,100%{transform:translateY(0)} 50%{transform:translateY(-8px)} }
        @keyframes lgBub { 0%{transform:translate(0,0);opacity:0} 16%{opacity:.9} 70%{opacity:.7} 100%{transform:translate(var(--drift,0px),calc(var(--rise,70px) * -1));opacity:0} }
        @keyframes lgIn { 0%{opacity:0;transform:translateY(16px)} 100%{opacity:1;transform:translateY(0)} }
        @keyframes lgBlink { 0%,92%{opacity:1} 96%{opacity:.25} 100%{opacity:1} }
      `}</style>
      <div style={{ position: 'absolute', inset: 0, opacity: 0.9 }}><DeepDecor /></div>
      <span style={{ position: 'absolute', left: 40, top: 150, width: 7, height: 7, background: PD.bio, boxShadow: `0 0 12px ${PD.bio}`, animation: 'lgBlink 5s steps(2) infinite' }} />
      <span style={{ position: 'absolute', right: 46, top: 224, width: 5, height: 5, background: PD.bio, boxShadow: `0 0 10px ${PD.bio}`, animation: 'lgBlink 5s steps(2) .6s infinite' }} />
      <span style={{ position: 'absolute', right: 70, top: 112, width: 4, height: 4, background: PD.bio, boxShadow: `0 0 8px ${PD.bio}`, animation: 'lgBlink 5s steps(2) 1.2s infinite' }} />
      <div style={{ position: 'relative', zIndex: 2, height: '100%', display: 'flex', flexDirection: 'column', padding: '0 26px' }}>
        <div style={{ flex: 1, display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', gap: 26 }}>
          <div style={{ position: 'relative' }}>
            <div style={{ position: 'absolute', left: '50%', top: '58%', transform: 'translate(-50%,-50%)', width: 190, height: 96,
              background: 'radial-gradient(ellipse at center, rgba(70,230,225,0.30), transparent 70%)' }} />
            <div style={{ position: 'relative', animation: 'lgBob 4.4s ease-in-out infinite' }}>
              <div style={{ position: 'relative', transform: 'scaleX(-1)' }}>
                <FSprite map={MINI_FERRY} palette={FERRY_PAL} cell={7} glow="RG" />
                <div style={{ position: 'absolute', left: 0, top: 0, animation: 'lgBlink 2.6s ease-in-out infinite' }}>
                  <FSprite map={MINI_FERRY} palette={CABIN_LIT} cell={7} glow="xo" />
                </div>
              </div>
            </div>
            {bub.map((b, i) =>
              <span key={i} style={{ position: 'absolute', left: `calc(50% + ${b.l}px)`, top: b.t, width: b.s, height: b.s, borderRadius: 99,
                background: 'rgba(190,248,242,0.9)', boxShadow: '0 0 5px rgba(120,230,225,0.6)',
                ['--rise']: b.rise + 'px', ['--drift']: b.drift + 'px',
                animation: `lgBub ${2.4 + b.s * 0.12}s ease-in ${b.d}s infinite` }} />
            )}
          </div>
          <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 13 }}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 11 }}>
              <span style={{ width: 6, height: 6, background: PD.bio, boxShadow: `0 0 10px ${PD.bio}` }} />
              <span style={{ fontFamily: PX, fontSize: 28, letterSpacing: 5, color: PD.bone }}>FERRY</span>
              <span style={{ width: 6, height: 6, background: PD.bio, boxShadow: `0 0 10px ${PD.bio}` }} />
            </div>
            <div style={{ fontFamily: PXJB, fontSize: 13.5, color: PD.ash, textAlign: 'center', maxWidth: 256, lineHeight: 1.55 }}>
              Send the screenshots on your phone straight to the canvas your team designs in.
            </div>
          </div>
        </div>
        <div style={{ display: 'flex', flexDirection: 'column', gap: 11, paddingBottom: 46 }}>
          <div style={{ fontFamily: PX, fontSize: 8.5, letterSpacing: 1, color: PD.faint, textAlign: 'center', marginBottom: 1 }}>CHOOSE WHERE TO SIGN IN</div>
          <ServiceDropdown service={service} setService={setService} />
          <div onClick={() => { window.location.href = '/auth/figma'; }}
            style={{ height: 54, borderRadius: 4, cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 10, userSelect: 'none',
              background: 'linear-gradient(135deg,#46E6DC,#129AAC)', color: '#03161A', boxShadow: 'inset 0 0 0 2px rgba(180,255,250,0.4), 0 7px 20px -7px rgba(63,224,216,0.6)' }}>
            <span style={{ fontFamily: PXJB, fontSize: 15, fontWeight: 700, letterSpacing: 0.2, whiteSpace: 'nowrap' }}>Sign in via {cur.name}</span>
            <Icon name="arrow" size={18} color="#03161A" stroke={2.6} />
          </div>
        </div>
      </div>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// CONNECT THE DESKTOP PLUGIN
// ─────────────────────────────────────────────────────────────
function OptionFerryConnect({ user, token, onConnected }) {
  const { useState, useEffect } = React;
  const [pairingCode, setPairingCode] = useState(() => localStorage.getItem('ferry_pairing_code'));
  const [copied, setCopied] = useState(false);
  const service = 'figma';
  const chipMark = <FigmaPixelMark cell={4} />;
  const body = { fontFamily: PXJB, fontSize: 12, color: PD.faint, lineHeight: 1.55 };
  const [handle, disc] = pairingCode && pairingCode.includes('#') ? pairingCode.split('#') : [pairingCode, null];

  useEffect(() => {
    if (pairingCode || !token) return;
    fetch('/auth/pair', { method: 'POST', headers: { Authorization: 'Bearer ' + token } })
      .then(r => r.ok ? r.json() : null)
      .then(d => { if (d && d.code) { setPairingCode(d.code); localStorage.setItem('ferry_pairing_code', d.code); } })
      .catch(() => {});
  }, []);

  function copyCode() {
    if (!pairingCode) return;
    navigator.clipboard.writeText(pairingCode).catch(() => {});
    setCopied(true);
    setTimeout(() => setCopied(false), 1800);
  }

  function handleConnected() {
    localStorage.setItem('ferry_connected', '1');
    onConnected();
  }

  const copyGlyph = <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke={PD.bio} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><rect x="8" y="8" width="12" height="12" rx="2" /><path d="M16 8V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v8a2 2 0 0 0 2 2h2" /></svg>;
  const checkGlyph = <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke={PD.bio} strokeWidth="2.6" strokeLinecap="round" strokeLinejoin="round"><path d="M5 12.5l4.5 4.5L19 7" /></svg>;

  return (
    <div style={{ position: 'relative', height: '100%', overflow: 'hidden', background: deepBg, fontFamily: PXJB, color: PD.bone, display: 'flex', flexDirection: 'column' }}>
      <style>{`@keyframes cBeacon { 0%{box-shadow:0 0 0 0 rgba(70,224,160,0.5)} 70%{box-shadow:0 0 0 7px rgba(70,224,160,0)} 100%{box-shadow:0 0 0 0 rgba(70,224,160,0)} }`}</style>
      <div style={{ position: 'absolute', inset: 0, backgroundImage: PX_GRAIN, opacity: 0.16, mixBlendMode: 'overlay', pointerEvents: 'none' }} />
      <div style={{ position: 'absolute', right: 24, top: 44, display: 'flex', alignItems: 'center', gap: 7, height: 30, padding: '0 12px 0 9px', borderRadius: 3,
        background: PD.fill, boxShadow: `inset 0 0 0 1.5px ${PD.line}`, imageRendering: 'pixelated', zIndex: 2 }}>
        <div style={{ width: 18, display: 'flex', justifyContent: 'center' }}>{chipMark}</div>
        <span style={{ fontFamily: PXJB, fontSize: 11.5, fontWeight: 700, color: PD.bone }}>Figma</span>
      </div>
      <div style={{ padding: '44px 24px 6px', position: 'relative', zIndex: 2 }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 16 }}>
          <span style={{ width: 7, height: 7, borderRadius: 99, background: PD_GREEN, boxShadow: `0 0 10px ${PD_GREEN}` }} />
          <span style={{ fontFamily: PX, fontSize: 8.5, letterSpacing: 1, color: PD_GREEN }}>SIGNED IN{user && user.handle ? ` AS ${user.handle}` : ''}</span>
        </div>
        <div style={{ fontFamily: PXJB, fontSize: 23, fontWeight: 700, letterSpacing: -0.5, lineHeight: 1.15 }}>Connect the<br />desktop plugin</div>
      </div>
      <div style={{ flex: 1, minHeight: 0, overflowY: 'auto', padding: '16px 24px 6px', position: 'relative', zIndex: 2 }}>
        <PixelStep n="1" title="Open Figma on desktop">
          <div style={body}>Sign in to the same Figma account — use the same credentials you just used here.</div>
        </PixelStep>
        <PixelStep n="2" title="Download the Ferry plugin">
          <div style={body}>Grab it from the Figma Community if you haven't already.</div>
          <div style={{ marginTop: 12, display: 'inline-flex', alignItems: 'center', gap: 8, height: 34, padding: '0 14px', borderRadius: 3, cursor: 'pointer',
            background: PD.fill, boxShadow: `inset 0 0 0 2px ${PD.edge}`, color: PD.bio, fontFamily: PX, fontSize: 9, letterSpacing: 0.5, userSelect: 'none' }}>
            GET THE PLUGIN <Icon name="arrow" size={14} color={PD.bio} stroke={2.4} />
          </div>
        </PixelStep>
        <PixelStep n="3" title="Enter your ID code" last>
          <div style={body}>In the plugin, paste this code to pair this phone:</div>
          <div style={{ marginTop: 12, height: 54, borderRadius: 3, background: PD.fill, boxShadow: `inset 0 0 0 2px ${PD.edge}`,
            display: 'flex', alignItems: 'center', gap: 10, padding: '0 8px 0 16px' }}>
            {!pairingCode
              ? <span style={{ flex: 1, fontFamily: PXJB, fontSize: 14, color: PD.faint }}>Generating…</span>
              : <span style={{ flex: 1, fontFamily: PXJB, fontSize: 18, fontWeight: 700, letterSpacing: 0.5, color: PD.bone }}>
                  {handle}<span style={{ color: PD.faint }}>{disc ? `#${disc}` : ''}</span>
                </span>
            }
            <div onClick={copyCode} style={{ width: 38, height: 38, flexShrink: 0, borderRadius: 2, cursor: 'pointer',
              display: 'flex', alignItems: 'center', justifyContent: 'center', boxShadow: `inset 0 0 0 1.5px ${PD.line}`,
              background: copied ? PD.bioDim : 'transparent' }}>
              {copied ? checkGlyph : copyGlyph}
            </div>
          </div>
        </PixelStep>
      </div>
      <div style={{ padding: '8px 24px 46px', position: 'relative', zIndex: 2 }}>
        <div onClick={handleConnected} style={{ height: 54, borderRadius: 4, cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 10, userSelect: 'none',
          background: 'linear-gradient(135deg,#46E6DC,#129AAC)', color: '#03161A', boxShadow: 'inset 0 0 0 2px rgba(180,255,250,0.4), 0 7px 20px -7px rgba(63,224,216,0.6)' }}>
          <span style={{ fontFamily: PXJB, fontSize: 15, fontWeight: 700, letterSpacing: 0.2, whiteSpace: 'nowrap' }}>It's connected</span>
          <Icon name="arrow" size={18} color="#03161A" stroke={2.6} />
        </div>
      </div>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// ROOT — handles auth state + screen routing
// ─────────────────────────────────────────────────────────────
function FerryApp() {
  const { useState } = React;
  const [token] = useState(() => localStorage.getItem('ferry_token'));
  const [user] = useState(() => { try { return JSON.parse(localStorage.getItem('ferry_user') || 'null'); } catch { return null; } });
  const [connected, setConnected] = useState(() => Boolean(localStorage.getItem('ferry_connected')));

  // All keyframes live here so they apply to every screen
  const css = `
    .ferryBatchInput::placeholder { color: rgba(220,239,242,0.32); opacity: 1; }
    .ferryBatchInput { -webkit-appearance: none; appearance: none; }
    @keyframes pxDrift { 0%{transform:translate(0,0)} 100%{transform:translate(var(--dx,0),74px)} }
    @keyframes pxBlink { 0%,92%{opacity:1} 96%{opacity:0.25} 100%{opacity:1} }
    @keyframes ferryBob { 0%,100%{transform:translateY(0) rotate(-1.5deg)} 50%{transform:translateY(-4px) rotate(1.5deg)} }
    @keyframes ferryWave { 0%{transform:translateX(0)} 100%{transform:translateX(-14px)} }
    @keyframes signBob { 0%,100%{transform:translateY(0) rotate(-1.4deg)} 50%{transform:translateY(-2.5px) rotate(1.4deg)} }
    @keyframes ferrySmoke { 0%{transform:translate(0,0) scale(0.5);opacity:0} 16%{opacity:0.6} 100%{transform:translate(-42px,-38px) scale(2.8);opacity:0} }
    @keyframes ferryDive { 0%{transform:translate(0,0) rotate(0deg)} 22%{transform:translate(9px,13px) rotate(34deg)} 55%{transform:translate(28px,27px) rotate(32deg)} 80%{transform:translate(40px,33px) rotate(16deg)} 100%{transform:translate(46px,34px) rotate(0deg)} }
    @keyframes ferrySubSway { 0%,100%{transform:translate(46px,34px) rotate(-2deg)} 50%{transform:translate(50px,31px) rotate(2deg)} }
    @keyframes ferryExit { 0%{transform:translate(46px,34px) rotate(0deg)} 100%{transform:translate(470px,88px) rotate(0deg)} }
    @keyframes ferryEnter { 0%{transform:translate(-260px,0) rotate(-2deg)} 72%{transform:translate(10px,0) rotate(1.5deg)} 100%{transform:translate(0,0) rotate(0deg)} }
    @keyframes wakeStreak { 0%{transform:translateX(8px);opacity:0} 25%{opacity:1} 100%{transform:translateX(-40px);opacity:0} }
    @keyframes bowSpray { 0%{transform:translate(0,0) scale(1);opacity:0} 20%{opacity:1} 100%{transform:translate(11px,-18px) scale(0.2);opacity:0} }
    @keyframes bubbleUp { 0%{transform:translateY(0);opacity:0} 20%{opacity:1} 100%{transform:translateY(-72px);opacity:0} }
    @keyframes bubbleRise { 0%{transform:translate(0,0);opacity:0} 16%{opacity:0.85} 72%{opacity:0.6} 100%{transform:translate(var(--bx,0),-94px);opacity:0} }
    @keyframes popIn { 0%{transform:scale(0.7);opacity:0} 100%{transform:scale(1);opacity:1} }
    @keyframes deepIn { 0%{opacity:0} 100%{opacity:1} }
    @keyframes textRise { 0%{opacity:0;transform:translateY(16px)} 100%{opacity:1;transform:translateY(0)} }
    @keyframes ferryHatch { 0%{transform:rotate(0deg)} 9%{transform:rotate(-108deg)} 76%{transform:rotate(-108deg)} 90%,100%{transform:rotate(0deg)} }
    @keyframes shotLoad { 0%{transform:translate(var(--sx,0),-64px) scale(0.7);opacity:0} 16%{opacity:1} 60%{transform:translate(calc(var(--sx,0) * 0.12),-5px) scale(1);opacity:1} 84%{transform:translate(0,2px) scale(0.78);opacity:1} 100%{transform:translate(0,3px) scale(0.05);opacity:0} }
    @keyframes beacon { 0%{box-shadow:0 0 6px #46E0A0, 0 0 0 0 rgba(70,224,160,0.55)} 70%{box-shadow:0 0 17px #46E0A0, 0 0 0 7px rgba(70,224,160,0)} 100%{box-shadow:0 0 6px #46E0A0, 0 0 0 0 rgba(70,224,160,0)} }
    @keyframes lightOn { 0%{opacity:0} 100%{opacity:1; box-shadow:0 0 6px 1px rgba(255,221,150,0.95)} }
    @keyframes lightFlick { 0%,100%{opacity:1} 46%{opacity:0.62} 50%{opacity:1} 72%{opacity:0.82} 76%{opacity:1} }
  `;

  if (!token || !user) return <React.Fragment><style>{css}</style><OptionFerryLogin /></React.Fragment>;
  if (!connected) return (
    <React.Fragment>
      <style>{css}</style>
      <OptionFerryConnect user={user} token={token} onConnected={() => setConnected(true)} />
    </React.Fragment>
  );
  return <React.Fragment><style>{css}</style><OptionFerryPixel user={user} token={token} /></React.Fragment>;
}

Object.assign(window, { FerryApp });
