// Split Crew — individual app screens

// ═══════════════════════════════════════════════════════════════
// HOME
// ═══════════════════════════════════════════════════════════════
function HomeScreen({ ctx }) {
  const [me] = useMe();
  return (
    <div>
      <AppHeader title="TRIPTAB" right={
        <button onClick={() => ctx.go('profile')} title="My profile" style={{
          background: 'transparent', border: 'none', padding: 0, cursor: 'pointer',
          display: 'flex', alignItems: 'center', gap: 6,
        }}>
          <MeAvatar size={28} />
        </button>
      } />

      <div style={{ padding: '20px 24px 0' }}>
        <div style={{ marginBottom: 40 }}>
          <div style={{ fontFamily: 'var(--font-display)', fontSize: 11, letterSpacing: '0.24em', color: 'var(--text-mu)', marginBottom: 8 }}>
            ◆ WELCOME BACK{me.name && me.name !== 'You' ? `, ${me.name.toUpperCase()}` : ''}
          </div>
          <h1 className="display" style={{ fontSize: 44, lineHeight: 0.95, marginBottom: 0 }}>
            Time to<br/>settle<br/><span style={{ color: 'var(--cyan-500)' }}>the tab</span>.
          </h1>
        </div>

        {/* Recent crews — only render if user has any trips */}
        {(() => {
          const recent = (ctx && ctx.recentTrips) || [];
          if (recent.length === 0) return null;
          return (
            <div style={{ marginBottom: 28 }}>
              <div style={{ fontSize: 10, color: 'var(--text-mu)', letterSpacing: '0.24em', fontFamily: 'var(--font-display)', marginBottom: 10, textTransform: 'uppercase' }}>Recent trips</div>
              {recent.map((trip, i) => (
                <div key={trip.id || i} onClick={() => ctx.openTrip ? ctx.openTrip(trip) : ctx.go('dashboard')} className={i === 0 ? 'bracket' : ''} style={{
                  background: i === 0 ? 'rgba(59,180,232,0.04)' : 'transparent',
                  border: '1px solid ' + (i === 0 ? 'var(--line)' : 'var(--line-subtle)'),
                  padding: i === 0 ? '14px 16px' : '12px 16px', cursor: 'pointer',
                  marginBottom: 8, opacity: trip.closed ? 0.6 : 1,
                }}>
                  <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
                    <div>
                      <div style={{ fontFamily: 'var(--font-display)', color: 'var(--text-hi)', fontSize: i === 0 ? 15 : 14, fontWeight: 600, letterSpacing: '0.04em' }}>{trip.name.toUpperCase()}</div>
                      <div style={{ fontSize: 11, color: 'var(--text-mu)', marginTop: 2 }}>{trip.members} crew · {trip.status}</div>
                    </div>
                  </div>
                </div>
              ))}
            </div>
          );
        })()}

        {/* Primary actions */}
        <div style={{ display: 'flex', flexDirection: 'column', gap: 10, marginTop: 32 }}>
          <PrimaryBtn onClick={() => ctx.startNewTrip ? ctx.startNewTrip() : ctx.go('create-name')} pulse>
            <span style={{ fontSize: 18, marginRight: 4 }}>+</span> New TripTab
          </PrimaryBtn>
          <GhostBtn onClick={() => ctx.go('join')}>
            <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><rect x="3" y="3" width="7" height="7"/><rect x="14" y="3" width="7" height="7"/><rect x="3" y="14" width="7" height="7"/><rect x="14" y="14" width="3" height="3"/></svg>
            Join via code or QR
          </GhostBtn>
        </div>
      </div>
    </div>
  );
}

// ═══════════════════════════════════════════════════════════════
// CREATE — NAME
// ═══════════════════════════════════════════════════════════════
function CreateNameScreen({ ctx }) {
  const [me, setMe] = useMe();
  const [name, setName] = React.useState('');
  const [displayName, setDisplayName] = React.useState(me.name && me.name !== 'You' && me.name !== 'Du' ? me.name : '');
  const [homeCurrency, setHomeCurrency] = React.useState('SEK');
  const [showAll, setShowAll] = React.useState(false);

  const needsDisplayName = !(me.name && me.name !== 'You' && me.name !== 'Du');
  const tripNameOk = name.trim().length >= 2;
  const displayNameOk = !needsDisplayName || displayName.trim().length >= 2;
  const canContinue = tripNameOk && displayNameOk;

  const MAIN = [['SEK','🇸🇪'],['EUR','🇪🇺'],['USD','🇺🇸']];
  const ALL = [
    ['SEK','🇸🇪','Swedish krona'],['EUR','🇪🇺','Euro'],['USD','🇺🇸','US Dollar'],
    ['NOK','🇳🇴','Norwegian krone'],['DKK','🇩🇰','Danish krone'],['GBP','🇬🇧','Pound'],
    ['CHF','🇨🇭','Swiss franc'],['JPY','🇯🇵','Yen'],['ISK','🇮🇸','Icelandic krona'],
    ['PLN','🇵🇱','Zloty'],['THB','🇹🇭','Baht'],['AUD','🇦🇺','AU Dollar'],
    ['CAD','🇨🇦','CA Dollar'],['HUF','🇭🇺','Forint'],['CZK','🇨🇿','Koruna'],
    ['TRY','🇹🇷','Lira'],
  ];

  return (
    <div>
      <AppHeader back={() => ctx.go('home')} title="NEW TRIPTAB · 1 / 2" />
      <div style={{ padding: '8px 24px 0' }}>
        <h1 className="display" style={{ fontSize: 32, lineHeight: 1.05, marginBottom: 8 }}>What should you call it?</h1>
        <p style={{ fontSize: 13, color: 'var(--text-mu)', lineHeight: 1.5, marginBottom: 28 }}>
          A name helps you find the tab later. Change it anytime.
        </p>

        <div className="bracket" style={{
          padding: '24px 18px', border: '1px solid var(--cyan-500)',
          background: 'rgba(59,180,232,0.04)', marginBottom: 20,
        }}>
          <div style={{ fontSize: 10, letterSpacing: '0.24em', color: 'var(--text-mu)', fontFamily: 'var(--font-display)', marginBottom: 8 }}>TRIP NAME</div>
          <input value={name} onChange={e => setName(e.target.value)} style={{
            background: 'transparent', border: 'none', outline: 'none',
            fontFamily: 'var(--font-display)', fontWeight: 700, fontSize: 28,
            color: 'var(--text-hi)', width: '100%', letterSpacing: '-0.01em', padding: 0,
          }} />
          <div style={{ height: 1, background: 'var(--cyan-500)', marginTop: 8, boxShadow: '0 0 8px var(--cyan-500)' }} />
        </div>

        {needsDisplayName && (
          <div className="bracket" style={{
            padding: '18px 16px', border: '1px solid var(--line)',
            background: 'rgba(10,20,32,0.4)', marginBottom: 20,
          }}>
            <div style={{ fontSize: 10, letterSpacing: '0.24em', color: 'var(--text-mu)', fontFamily: 'var(--font-display)', marginBottom: 8 }}>YOUR NAME (HOW THE CREW SEES YOU)</div>
            <input
              value={displayName}
              onChange={e => setDisplayName(e.target.value)}
              placeholder="e.g. Emil"
              autoCapitalize="words"
              style={{
                background: 'transparent', border: 'none', outline: 'none',
                fontFamily: 'var(--font-display)', fontWeight: 600, fontSize: 20,
                color: 'var(--text-hi)', width: '100%', letterSpacing: '0.02em', padding: 0,
              }}
            />
            <div style={{ height: 1, background: 'var(--line)', marginTop: 8 }} />
          </div>
        )}

        <div style={{ marginBottom: 28 }}>
          <div style={{ fontSize: 10, color: 'var(--text-mu)', letterSpacing: '0.24em', fontFamily: 'var(--font-display)', marginBottom: 10 }}>HOME CURRENCY</div>
          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: 6 }}>
            {MAIN.map(([c, flag]) => {
              const sel = homeCurrency === c;
              return (
                <button key={c} onClick={() => setHomeCurrency(c)} style={{
                  padding: '12px 6px',
                  border: '1px solid ' + (sel ? 'var(--cyan-500)' : 'var(--line-subtle)'),
                  background: sel ? 'rgba(59,180,232,0.08)' : 'transparent',
                  color: 'var(--text-hi)', cursor: 'pointer',
                  fontFamily: 'var(--font-display)', fontSize: 13, fontWeight: 600,
                  letterSpacing: '0.1em',
                }}>
                  <div style={{ fontSize: 18, marginBottom: 2 }}>{flag}</div>
                  {c}
                </button>
              );
            })}
            {/* "Show all" slot — shows currently-selected exotic currency, or generic globe */}
            {(() => {
              const isExotic = !MAIN.find(([c]) => c === homeCurrency);
              const exoticRow = isExotic ? ALL.find(([c]) => c === homeCurrency) : null;
              return (
                <button onClick={() => setShowAll(true)} style={{
                  padding: '12px 6px',
                  border: '1px solid ' + (isExotic ? 'var(--cyan-500)' : 'var(--line-subtle)'),
                  background: isExotic ? 'rgba(59,180,232,0.08)' : 'transparent',
                  color: isExotic ? 'var(--text-hi)' : 'var(--cyan-500)', cursor: 'pointer',
                  fontFamily: 'var(--font-display)', fontSize: isExotic ? 13 : 9, fontWeight: 600,
                  letterSpacing: isExotic ? '0.1em' : '0.16em',
                  display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center',
                }}>
                  <div style={{ fontSize: 18, marginBottom: 2 }}>{isExotic ? exoticRow[1] : '🌐'}</div>
                  {isExotic ? exoticRow[0] : <>SHOW<br />ALL</>}
                </button>
              );
            })()}
          </div>
          <div style={{ fontSize: 11, color: 'var(--text-mu)', marginTop: 8 }}>
            All debts are converted to {homeCurrency}.{' '}
            <button onClick={() => setShowAll(true)} style={{
              background: 'transparent', border: 'none', padding: 0, cursor: 'pointer',
              color: 'var(--cyan-500)', fontSize: 11, textDecoration: 'underline',
            }}>Change currency →</button>
          </div>
        </div>

        {showAll && (
          <div onClick={() => setShowAll(false)} style={{
            position: 'absolute', inset: 0, background: 'rgba(0,0,0,0.7)', zIndex: 150,
            display: 'flex', alignItems: 'flex-end', justifyContent: 'center',
          }}>
            <div onClick={e => e.stopPropagation()} style={{
              width: '100%', maxHeight: '72%',
              background: '#050a10', borderTop: '1px solid var(--cyan-500)',
              padding: '16px 18px 24px', overflow: 'auto',
            }}>
              <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 12 }}>
                <div className="display" style={{ fontSize: 18, color: 'var(--text-hi)', letterSpacing: '0.04em' }}>Choose home currency</div>
                <button onClick={() => setShowAll(false)} style={{
                  background: 'transparent', border: '1px solid var(--line)', color: 'var(--text-mu)',
                  padding: '4px 8px', cursor: 'pointer', fontFamily: 'var(--font-display)', fontSize: 10, letterSpacing: '0.18em',
                }}>CLOSE</button>
              </div>
              <div style={{ display: 'grid', gridTemplateColumns: '1fr', gap: 2 }}>
                {ALL.map(([c, flag, nm]) => {
                  const sel = homeCurrency === c;
                  return (
                    <button key={c} onClick={() => { setHomeCurrency(c); setShowAll(false); }} style={{
                      display: 'flex', alignItems: 'center', gap: 12, padding: '10px 12px',
                      background: sel ? 'rgba(59,180,232,0.08)' : 'transparent',
                      border: '1px solid ' + (sel ? 'var(--cyan-500)' : 'var(--line-subtle)'),
                      cursor: 'pointer', textAlign: 'left',
                    }}>
                      <span style={{ fontSize: 20 }}>{flag}</span>
                      <span style={{ fontFamily: 'var(--font-display)', fontWeight: 700, color: 'var(--text-hi)', letterSpacing: '0.08em', minWidth: 44 }}>{c}</span>
                      <span style={{ fontSize: 12, color: 'var(--text-mu)', flex: 1 }}>{nm}</span>
                      {sel && <span style={{ color: 'var(--cyan-500)', fontFamily: 'var(--font-display)', fontSize: 11, letterSpacing: '0.18em' }}>✓</span>}
                    </button>
                  );
                })}
              </div>
              <div style={{ marginTop: 10, fontSize: 10, color: 'var(--text-mu)', fontFamily: 'var(--font-display)', letterSpacing: '0.18em', textAlign: 'center' }}>
                ◉ FX RATES UPDATED DAILY
              </div>
            </div>
          </div>
        )}

        <PrimaryBtn disabled={!canContinue} onClick={() => {
          if (needsDisplayName) setMe({ ...me, name: displayName.trim() });
          ctx.setPot({ ...ctx.pot, name: name.trim(), homeCurrency });
          ctx.go('create-qr');
        }} pulse={canContinue}>
          Continue <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><path d="M5 12h14M12 5l7 7-7 7" /></svg>
        </PrimaryBtn>
      </div>
    </div>
  );
}

// ═══════════════════════════════════════════════════════════════
// CREATE — QR
// ═══════════════════════════════════════════════════════════════
function CreateQRScreen({ ctx }) {
  return <QRScreenBase ctx={ctx} mode="create" />;
}

function InviteQRScreen({ ctx }) {
  return <QRScreenBase ctx={ctx} mode="invite" />;
}

function QRScreenBase({ ctx, mode }) {
  const [me] = useMe();

  // Ensure a code exists. If we somehow landed here without one, generate it.
  React.useEffect(() => {
    if (!ctx.pot || !ctx.pot.code) {
      const ALPHABET = '23456789ABCDEFGHJKLMNPQRSTUVWXYZ';
      let code = '';
      for (let i = 0; i < 6; i++) code += ALPHABET[Math.floor(Math.random() * ALPHABET.length)];
      ctx.setPot({ ...(ctx.pot || { members: [me.name || 'Du'] }), code });
    }
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  const tripCode = (ctx.pot && ctx.pot.code) || '';
  const formattedCode = tripCode.length === 6 ? tripCode.slice(0, 3) + '-' + tripCode.slice(3) : tripCode;

  // Commit the trip the moment this screen mounts so the user can leave anytime.
  React.useEffect(() => {
    if (mode === 'create' && ctx.commitTrip) ctx.commitTrip();
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);
  const myName = ctx.myName || (me.name || 'Du');
  const crewRows = ctx.crewMembers || [];
  const palette = [PEOPLE_COLORS.E, PEOPLE_COLORS.M, PEOPLE_COLORS.S, PEOPLE_COLORS.L];
  const adminDeviceId = ctx.admin ? ctx.admin.device_id : null;
  const myDeviceId = ctx.deviceId;

  // Build connected list from canonical DB rows when available; fall back to pot.members.
  let connected;
  if (crewRows.length) {
    let otherIdx = 0;
    connected = crewRows.map(row => {
      const isMe = row.device_id && row.device_id === myDeviceId;
      const display = isMe ? ((me.name || row.name || '').trim() || row.name || 'You') : row.name;
      const isAdmin = row.device_id && row.device_id === adminDeviceId;
      const color = isMe ? PEOPLE_COLORS.Y : palette[otherIdx++ % palette.length];
      return {
        name: display,
        initial: display.charAt(0).toUpperCase() || '?',
        color,
        photo: isMe ? me.photo : undefined,
        isMe,
        isAdmin,
        deviceId: row.device_id,
      };
    });
  } else {
    const members = (ctx.pot && ctx.pot.members) ? ctx.pot.members : [myName];
    let otherIdx = 0;
    connected = members.map(slot => {
      if (slot === myName) {
        const display = (me.name || '').trim() || 'You';
        return {
          name: display,
          initial: display.charAt(0).toUpperCase() || 'Y',
          color: PEOPLE_COLORS.Y,
          photo: me.photo,
          isMe: true,
          isAdmin: true, // creator-only fallback before DB sync
          deviceId: myDeviceId,
        };
      }
      const color = palette[otherIdx % palette.length];
      otherIdx++;
      return {
        name: slot,
        initial: (slot.charAt(0) || '?').toUpperCase(),
        color,
        isMe: false,
        isAdmin: false,
        deviceId: null,
      };
    });
  }

  // My balance — used to gate the "Leave trip" affordance for non-admins.
  // Per the flow rules: a guest can leave only when all bills FOR them are
  // settled, OR no debt from them is registered. Both reduce to balance == 0.
  const tripExpenses = ctx.expenses || [];
  const balanceMembers = (ctx.pot && ctx.pot.members && ctx.pot.members.length) ? ctx.pot.members : [myName];
  let myBalance = 0;
  for (const e of tripExpenses) {
    // Use canonical home-currency amount; fall back to SEK for legacy expenses.
    const amt = (e.home != null ? Number(e.home) : Number(e.sek)) || 0;
    const share = amt / Math.max(1, balanceMembers.length);
    myBalance -= share;
    if (e.paidBy === myName) myBalance += amt;
  }
  myBalance = Math.round(myBalance);
  const noDebtRegistered = tripExpenses.length === 0;
  const canLeave = !ctx.isAdmin && myBalance === 0 && crewRows.length > 1;

  // Creator-side gates per the flow chart:
  //  - kicking a guest is allowed only before any debt has been settled
  //  - the trip itself can be deleted only before any debt has been settled
  const hasSettlements = !!ctx.hasSettlements;
  const maxMembers = ctx.maxMembers || 10;
  const memberCount = connected.length;
  const tripFull = memberCount >= maxMembers;

  const handleRemove = async (deviceId, name) => {
    if (!deviceId || !ctx.removeCrewMember) return;
    if (hasSettlements) {
      window.alert(`Can't remove ${name} — settlements have already been recorded for this trip. Members can only be removed before any debt is settled.`);
      return;
    }
    if (!window.confirm(`Remove ${name} from this trip?\n\nTheir expenses stay; any unsettled bills get redistributed across the remaining crew.`)) return;
    await ctx.removeCrewMember(deviceId);
  };

  const handleLeave = async () => {
    if (!myDeviceId || !ctx.removeCrewMember) return;
    const reason = noDebtRegistered
      ? 'You have no expenses in this trip.'
      : 'All your bills are settled.';
    if (!window.confirm(`Leave this trip?\n\n${reason} You can rejoin later with the code.`)) return;
    await ctx.removeCrewMember(myDeviceId);
  };

  const handleCreatorDeleteTrip = () => {
    if (hasSettlements) return;
    if (!window.confirm(`Delete "${ctx.pot.name}"?\n\nThis permanently removes the trip, every expense, and every crew member. Allowed only because no debt has been settled yet.`)) return;
    if (ctx.deleteTrip) ctx.deleteTrip();
    ctx.go('home');
  };

  return (
    <div>
      <AppHeader
        back={() => mode === 'create' ? ctx.go('create-name') : ctx.go(ctx.lastScreen || 'dashboard')}
        title={mode === 'create' ? 'NEW TRIPTAB · 2 / 2' : 'INVITE'}
      />
      <div style={{ padding: '8px 24px 0' }}>
        <h1 className="display" style={{ fontSize: 28, lineHeight: 1.05, marginBottom: 8 }}>Invite the crew</h1>
        <p style={{ fontSize: 12, color: 'var(--text-mu)', lineHeight: 1.5, marginBottom: 20 }}>
          Let them scan the QR code or share the code below. No signup.
        </p>

        {/* QR card */}
        <div className="bracket" style={{
          border: '1px solid var(--cyan-500)',
          background: 'linear-gradient(180deg, rgba(59,180,232,0.06), rgba(59,180,232,0.02))',
          padding: 20,
          marginBottom: 16,
          boxShadow: '0 0 40px rgba(59,180,232,0.2)',
          opacity: tripFull ? 0.55 : 1,
          position: 'relative',
        }}>
          <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 14 }}>
            <span className="mono" style={{ fontSize: 10, color: 'var(--cyan-500)', letterSpacing: '0.2em' }}>
              ◆ {ctx.pot.name.toUpperCase()}
            </span>
            <span className="mono" style={{ fontSize: 10, color: 'var(--text-mu)', letterSpacing: '0.18em' }}>
              CREW CODE
            </span>
          </div>

          <div style={{
            background: '#000', padding: 14, border: '1px solid var(--line)',
            display: 'flex', justifyContent: 'center', alignItems: 'center',
            position: 'relative', aspectRatio: '1',
            width: 'min(60vh, 100%)',
            maxWidth: 240,
            margin: '0 auto',
          }}>
            <QRCode code={tripCode || '8A4F2K'} />
            <div style={{ position: 'absolute', top: 6, left: 6, width: 20, height: 20, borderTop: '2px solid var(--cyan-500)', borderLeft: '2px solid var(--cyan-500)' }} />
            <div style={{ position: 'absolute', top: 6, right: 6, width: 20, height: 20, borderTop: '2px solid var(--cyan-500)', borderRight: '2px solid var(--cyan-500)' }} />
            <div style={{ position: 'absolute', bottom: 6, left: 6, width: 20, height: 20, borderBottom: '2px solid var(--cyan-500)', borderLeft: '2px solid var(--cyan-500)' }} />
            <div style={{ position: 'absolute', bottom: 6, right: 6, width: 20, height: 20, borderBottom: '2px solid var(--cyan-500)', borderRight: '2px solid var(--cyan-500)' }} />
            {tripFull && (
              <div style={{
                position: 'absolute', inset: 0, background: 'rgba(0,0,0,0.78)',
                display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center',
                gap: 4,
              }}>
                <div style={{ fontFamily: 'var(--font-display)', fontSize: 10, letterSpacing: '0.28em', color: '#E86B3B' }}>◆ TRIP FULL</div>
                <div style={{ fontSize: 11, color: 'var(--text)', letterSpacing: '0.06em' }}>{maxMembers} / {maxMembers} crew</div>
              </div>
            )}
          </div>

          <div style={{
            marginTop: 14, textAlign: 'center',
            fontFamily: 'var(--font-display)', fontWeight: 700, fontSize: 22,
            color: 'var(--cyan-100)', letterSpacing: '0.2em',
          }}>{formattedCode || '— — —'}</div>
          <div style={{ textAlign: 'center', fontSize: 10, color: 'var(--text-mu)', marginTop: 4, letterSpacing: '0.18em', fontFamily: 'var(--font-display)' }}>
            {tripFull ? 'NO MORE SLOTS' : 'OR TYPE THE CODE'}
          </div>
        </div>

        {/* Connected members live */}
        <div style={{ marginBottom: 16 }}>
          <div style={{
            display: 'flex', alignItems: 'baseline', justifyContent: 'space-between',
            marginBottom: 8,
          }}>
            <div style={{ fontSize: 10, color: 'var(--text-mu)', letterSpacing: '0.22em', fontFamily: 'var(--font-display)' }}>
              ◉ CONNECTED
            </div>
            <div style={{
              fontSize: 10, fontFamily: 'var(--font-display)', letterSpacing: '0.22em',
              color: tripFull ? '#E86B3B' : 'var(--cyan-100)',
            }}>
              {memberCount} / {maxMembers}
            </div>
          </div>
          <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
            {connected.map((p, i) => (
              <div key={i} style={{
                display: 'flex', alignItems: 'center', gap: 10,
                padding: '8px 12px', border: '1px solid var(--line-subtle)',
                background: 'rgba(10,20,32,0.4)',
              }}>
                <CrewAvatar color={p.color} initial={p.initial} size={26} photo={p.photo} />
                <div style={{ flex: 1, minWidth: 0, display: 'flex', alignItems: 'baseline', gap: 6, flexWrap: 'wrap' }}>
                  <span style={{
                    fontSize: 13, color: 'var(--text-hi)', fontWeight: 500,
                    overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap',
                  }}>{p.name}</span>
                  {p.isMe && (
                    <span style={{
                      fontSize: 9, color: 'var(--cyan-500)',
                      fontFamily: 'var(--font-display)', letterSpacing: '0.2em', fontWeight: 600,
                    }}>YOU</span>
                  )}
                  {p.isAdmin && (
                    <span style={{
                      fontSize: 9, color: '#F5C64A',
                      fontFamily: 'var(--font-display)', letterSpacing: '0.2em', fontWeight: 600,
                      border: '1px solid rgba(245,198,74,0.4)', padding: '1px 5px',
                    }}>ADMIN</span>
                  )}
                </div>
                {ctx.isAdmin && !p.isMe && p.deviceId && (
                  <button
                    onClick={() => handleRemove(p.deviceId, p.name)}
                    disabled={hasSettlements}
                    title={hasSettlements
                      ? `Can't remove ${p.name} — settlements have already started`
                      : `Remove ${p.name}`}
                    style={{
                      background: 'transparent',
                      border: `1px solid ${hasSettlements ? 'var(--line-subtle)' : 'rgba(232,107,59,0.45)'}`,
                      color: hasSettlements ? 'var(--text-mu)' : '#E86B3B',
                      cursor: hasSettlements ? 'not-allowed' : 'pointer',
                      opacity: hasSettlements ? 0.4 : 1,
                      width: 22, height: 22, display: 'flex', alignItems: 'center', justifyContent: 'center',
                      fontSize: 14, lineHeight: 1, padding: 0,
                    }}
                  >×</button>
                )}
                <span style={{
                  width: 6, height: 6, borderRadius: '50%',
                  background: '#7DE08B', boxShadow: '0 0 6px #7DE08B',
                }} />
              </div>
            ))}
          </div>
          {/* Guest controls — leave self */}
          {!ctx.isAdmin && canLeave && (
            <button
              onClick={handleLeave}
              style={{
                marginTop: 10, width: '100%',
                background: 'transparent', border: '1px solid rgba(232,107,59,0.4)',
                color: '#E86B3B', cursor: 'pointer',
                padding: '10px 12px', fontFamily: 'var(--font-display)',
                fontSize: 11, letterSpacing: '0.2em', fontWeight: 600,
              }}
            >{noDebtRegistered ? 'LEAVE TRIP · NO DEBT REGISTERED' : 'LEAVE TRIP · BALANCE SETTLED'}</button>
          )}
          {!ctx.isAdmin && myBalance !== 0 && crewRows.length > 1 && (
            <div style={{
              marginTop: 10, fontSize: 10, color: 'var(--text-mu)',
              fontFamily: 'var(--font-display)', letterSpacing: '0.16em', textAlign: 'center',
            }}>
              SETTLE YOUR BALANCE TO LEAVE THE TRIP
            </div>
          )}

          {/* Creator controls — delete whole trip (only before any debt is settled) */}
          {ctx.isAdmin && (
            <div style={{ marginTop: 14 }}>
              <button
                onClick={handleCreatorDeleteTrip}
                disabled={hasSettlements}
                style={{
                  width: '100%',
                  background: 'transparent',
                  border: `1px solid ${hasSettlements ? 'var(--line-subtle)' : 'rgba(232,107,59,0.5)'}`,
                  color: hasSettlements ? 'var(--text-mu)' : '#E86B3B',
                  cursor: hasSettlements ? 'not-allowed' : 'pointer',
                  opacity: hasSettlements ? 0.55 : 1,
                  padding: '10px 12px', fontFamily: 'var(--font-display)',
                  fontSize: 11, letterSpacing: '0.2em', fontWeight: 600,
                  display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 8,
                }}
              >
                <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><path d="M3 6h18M8 6V4a2 2 0 012-2h4a2 2 0 012 2v2M10 11v6M14 11v6M5 6l1 14a2 2 0 002 2h8a2 2 0 002-2l1-14"/></svg>
                DELETE TRIP
              </button>
              <div style={{
                marginTop: 6, fontSize: 10, color: 'var(--text-mu)',
                fontFamily: 'var(--font-display)', letterSpacing: '0.14em', textAlign: 'center', lineHeight: 1.5,
              }}>
                {hasSettlements
                  ? 'LOCKED · DEBT ALREADY SETTLED IN THIS TRIP'
                  : 'AS CREATOR · ONLY BEFORE ANY DEBT IS SETTLED'}
              </div>
            </div>
          )}
        </div>

        {mode === 'create' && (
          <PrimaryBtn onClick={() => { if (ctx.commitTrip) ctx.commitTrip(); ctx.go('dashboard'); }} pulse>
            Continue to trip
            <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><path d="M5 12h14M12 5l7 7-7 7" /></svg>
          </PrimaryBtn>
        )}
      </div>
    </div>
  );
}

// Mock QR code
function QRCode({ code = '8A4F2K' }) {
  const N = 21;
  const grid = React.useMemo(() => {
    // Deterministic pseudo-random from code
    let seed = 0;
    for (let i = 0; i < code.length; i++) seed = (seed * 31 + code.charCodeAt(i)) | 0;
    const rand = () => { seed = (seed * 9301 + 49297) % 233280; return seed / 233280; };
    const g = Array(N).fill(0).map(() => Array(N).fill(0).map(() => rand() > 0.5 ? 1 : 0));
    // finder patterns at 3 corners
    const drawFinder = (r, c) => {
      for (let i = 0; i < 7; i++) for (let j = 0; j < 7; j++) {
        const inOuter = i === 0 || i === 6 || j === 0 || j === 6;
        const inInner = i >= 2 && i <= 4 && j >= 2 && j <= 4;
        g[r + i][c + j] = (inOuter || inInner) ? 1 : 0;
      }
    };
    drawFinder(0, 0); drawFinder(0, N - 7); drawFinder(N - 7, 0);
    return g;
  }, [code]);

  return (
    <svg viewBox={`0 0 ${N} ${N}`} width="100%" style={{ display: 'block', imageRendering: 'pixelated' }}>
      {grid.flatMap((row, r) => row.map((v, c) => v ? <rect key={`${r}-${c}`} x={c} y={r} width={1} height={1} fill="var(--cyan-500)" /> : null))}
    </svg>
  );
}

// ═══════════════════════════════════════════════════════════════
// PROFILE — edit name + photo for "Du"
// ═══════════════════════════════════════════════════════════════
function ProfileScreen({ ctx }) {
  const [me, setMe] = useMe();
  const [name, setName] = React.useState(me.name || '');
  const [photo, setPhoto] = React.useState(me.photo);
  const fileRef = React.useRef(null);

  const pickPhoto = (file) => {
    if (!file) return;
    const reader = new FileReader();
    reader.onload = e => setPhoto(e.target.result);
    reader.readAsDataURL(file);
  };

  const save = () => {
    setMe({ name: (name || 'You').trim(), photo });
    ctx.go('home');
  };

  return (
    <div>
      <AppHeader back={() => ctx.go('home')} title="MY PROFILE" />
      <div style={{ padding: '0 24px 40px' }}>
        <h1 className="display" style={{ fontSize: 28, lineHeight: 1.05, marginBottom: 20 }}>
          This is <span style={{ color: 'var(--cyan-500)' }}>you</span>.
        </h1>

        {/* Avatar preview + picker */}
        <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', marginBottom: 28 }}>
          <div style={{ position: 'relative', marginBottom: 14 }}>
            <CrewAvatar
              color="#3BB4E8"
              initial={(name || 'D').trim().charAt(0).toUpperCase() || 'D'}
              size={120}
              photo={photo}
            />
            {/* Scan-line overlay for style */}
            <div style={{
              position: 'absolute', inset: 0, borderRadius: '50%', pointerEvents: 'none',
              background: 'linear-gradient(180deg, transparent 48%, rgba(59,180,232,0.2) 50%, transparent 52%)',
              mixBlendMode: 'screen',
            }} />
          </div>

          <input ref={fileRef} type="file" accept="image/*"
            onChange={e => pickPhoto(e.target.files?.[0])}
            style={{ display: 'none' }} />

          <div style={{ display: 'flex', gap: 6 }}>
            <button onClick={() => fileRef.current?.click()} style={{
              padding: '9px 14px', background: 'rgba(59,180,232,0.08)',
              border: '1px dashed var(--cyan-500)', color: 'var(--cyan-100)',
              fontFamily: 'var(--font-display)', letterSpacing: '0.2em', fontSize: 10, fontWeight: 600,
              cursor: 'pointer',
            }}>
              {photo ? '↻ CHANGE PHOTO' : '📷 ADD PHOTO'}
            </button>
            {photo && (
              <button onClick={() => setPhoto(null)} style={{
                padding: '9px 12px', background: 'transparent',
                border: '1px solid rgba(232,107,59,0.5)', color: '#E86B3B',
                fontFamily: 'var(--font-display)', letterSpacing: '0.18em', fontSize: 10, fontWeight: 600,
                cursor: 'pointer',
              }}>✕</button>
            )}
          </div>
          <div style={{ fontSize: 10, color: 'var(--text-mu)', marginTop: 8, fontFamily: 'var(--font-display)', letterSpacing: '0.16em' }}>
            {photo ? '◉ PHOTO LINKED · STORED LOCALLY' : '○ NO PHOTO · SHOWING INITIAL'}
          </div>
        </div>

        {/* Name */}
        <div style={{ marginBottom: 14, border: '1px solid var(--line)', padding: '10px 14px', background: 'rgba(10,20,32,0.5)' }}>
          <div style={{ fontSize: 9, letterSpacing: '0.22em', color: 'var(--text-mu)', fontFamily: 'var(--font-display)', marginBottom: 4 }}>YOUR NAME</div>
          <input
            value={name}
            onChange={e => setName(e.target.value)}
            placeholder="e.g. Ylva"
            maxLength={20}
            style={{
              background: 'transparent', border: 'none', outline: 'none',
              color: 'var(--text-hi)', fontSize: 18, width: '100%',
              fontFamily: 'var(--font-display)', fontWeight: 600, letterSpacing: '0.02em',
              padding: '2px 0',
            }}
          />
        </div>
        <div style={{ fontSize: 11, color: 'var(--text-mu)', marginBottom: 20, lineHeight: 1.5 }}>
          Your name is shown to the crew in every tab you're part of. Change it anytime.
        </div>

        <PrimaryBtn onClick={save}>Save profile</PrimaryBtn>
      </div>
    </div>
  );
}

Object.assign(window, { HomeScreen, CreateNameScreen, CreateQRScreen, InviteQRScreen, QRScreenBase, QRCode, ProfileScreen });
