// screens-trip.jsx — 트립 탭 = 세로 여정 타임라인. 현재 단계만 펼침(active),
// 지난 단계 done(접힘/✓), 다음 단계 locked(흐릿). 각 단계는 '화면 상태(scr)'에
// 따라 before/after 변형을 보여준다 (디렉터의 '화면 상태' 카테고리에서 선택).

const PLAN_PLACES = [
  ...JJ.pins,
  { id: 'x1', name: '광안리 밤바다', scene: 'night', tag: '야경' },
  { id: 'x2', name: '동백섬 산책로', scene: 'sea', tag: '산책' },
  { id: 'x3', name: '전포 카페거리', scene: 'cafe', tag: '커피' },
];
const planPlace = (id) => PLAN_PLACES.find(p => p.id === id);

function EntryCard({ icon, title, desc, tone = 'coral', onClick, badge, done }) {
  return (
    <Card onClick={onClick} pad={13} style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
      <div style={{ width: 40, height: 40, borderRadius: 11, flexShrink: 0, display: 'flex', alignItems: 'center', justifyContent: 'center', background: `color-mix(in srgb, var(--${tone}) 12%, var(--card))` }}>
        <JJIcon name={done ? 'check' : icon} size={20} color={`var(--${tone})`} sw={1.8} />
      </div>
      <div style={{ flex: 1, minWidth: 0 }}>
        <div style={{ fontFamily: 'var(--f-display)', fontWeight: 700, fontSize: 15, color: 'var(--ink)' }}>{title}</div>
        <div style={{ fontFamily: 'var(--f-body)', fontSize: 12, color: done ? 'var(--sea)' : 'var(--ink-3)', marginTop: 1, lineHeight: 1.4 }}>{desc}</div>
      </div>
      {badge != null && <Tag tone="coral" solid>{badge}</Tag>}
      {done ? <Tag tone="sea">완료</Tag> : <JJIcon name="chevron" size={15} color="var(--line)" sw={2.2} />}
    </Card>
  );
}

// ── Day별 플래너 (인터랙티브) ─────────────────────────────────
function DayPlanner({ persona, seed }) {
  const isHost = persona === 'host';
  const [plan, setPlan] = React.useState(seed || { 1: ['p1', 'p2'], 2: ['x1'], 3: [] });
  const [pick, setPick] = React.useState(null);
  const days = [{ n: 1, d: '6/13 토' }, { n: 2, d: '6/14 일' }, { n: 3, d: '6/15 월' }];
  const add = (day, id) => { setPlan(p => ({ ...p, [day]: [...p[day], id] })); setPick(null); };
  const remove = (day, id) => setPlan(p => ({ ...p, [day]: p[day].filter(x => x !== id) }));
  const used = Object.values(plan).flat();

  return (
    <Card pad={15}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 4 }}>
        <JJIcon name="heart" size={17} color="var(--coral)" fill />
        <span style={{ fontFamily: 'var(--f-display)', fontWeight: 700, fontSize: 15.5, color: 'var(--ink)', flex: 1 }}>{isHost ? '민서의 날짜별 계획' : '날짜별로 가고 싶은 곳'}</span>
        <Tag tone="coral">늘 우선</Tag>
      </div>
      <div style={{ fontFamily: 'var(--f-body)', fontSize: 12, color: 'var(--ink-3)', marginBottom: 12 }}>
        {isHost ? '민서가 담은 곳을 보며 동선을 맞춰줘요.' : '시간표가 아니라 느슨한 목록. 담고 빼며 그날의 중심을 정해요.'}
      </div>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 4 }}>
        {days.map((day, di) => {
          const ids = plan[day.n];
          const avail = PLAN_PLACES.filter(p => !used.includes(p.id));
          const open = pick === day.n;
          return (
            <div key={day.n} style={{ position: 'relative', display: 'flex', gap: 11 }}>
              <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', width: 14, flexShrink: 0 }}>
                <div style={{ width: 11, height: 11, borderRadius: '50%', background: ids.length ? 'var(--coral)' : 'var(--card)', border: `2px solid ${ids.length ? 'var(--coral)' : 'var(--line)'}`, marginTop: 3 }} />
                {di < days.length - 1 && <div style={{ flex: 1, width: 2, background: 'var(--line-soft)', marginTop: 3 }} />}
              </div>
              <div style={{ flex: 1, paddingBottom: 14, minWidth: 0 }}>
                <div style={{ display: 'flex', alignItems: 'baseline', gap: 7 }}>
                  <span style={{ fontFamily: 'var(--f-display)', fontWeight: 700, fontSize: 14, color: 'var(--ink)' }}>Day {day.n}</span>
                  <span style={{ fontFamily: 'var(--f-body)', fontSize: 11, color: 'var(--ink-3)' }}>{day.d}</span>
                </div>
                <div style={{ display: 'flex', flexDirection: 'column', gap: 6, marginTop: 7 }}>
                  {ids.map(id => {
                    const p = planPlace(id);
                    return (
                      <div key={id} style={{ display: 'flex', alignItems: 'center', gap: 9, background: 'var(--paper-2)', border: '1px solid var(--line-soft)', borderRadius: 11, padding: '6px 9px' }}>
                        <Photo scene={p.scene} h={32} r={8} style={{ width: 32, flexShrink: 0 }} />
                        <div style={{ flex: 1, minWidth: 0 }}>
                          <div style={{ fontFamily: 'var(--f-display)', fontWeight: 700, fontSize: 13, color: 'var(--ink)', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{p.name}</div>
                          <div style={{ fontFamily: 'var(--f-body)', fontSize: 10.5, color: 'var(--ink-3)' }}>{p.tag}{JJ.pins.find(x => x.id === id) ? ' · 쩨 지도' : ' · 직접 추가'}</div>
                        </div>
                        {!isHost && (
                          <button onClick={() => remove(day.n, id)} style={{ width: 24, height: 24, borderRadius: '50%', border: 'none', background: 'transparent', cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>
                            <JJIcon name="close" size={13} color="var(--ink-3)" sw={2} />
                          </button>
                        )}
                      </div>
                    );
                  })}
                  {ids.length === 0 && !open && (
                    <div style={{ fontFamily: 'var(--f-hand)', fontSize: 'calc(15px * var(--hand-scale))', color: 'var(--ink-3)', padding: '2px 2px' }}>아직 비어 있어요{isHost ? '' : ' — 담아볼까요?'}</div>
                  )}
                </div>
                {!isHost && (open ? (
                  <div style={{ marginTop: 8, background: 'var(--card)', border: '1px solid var(--coral)', borderRadius: 12, padding: 9, boxShadow: '0 6px 18px var(--shadow)' }}>
                    <div style={{ display: 'flex', alignItems: 'center', marginBottom: 7 }}>
                      <span style={{ fontFamily: 'var(--f-body)', fontSize: 11.5, fontWeight: 600, color: 'var(--ink-2)', flex: 1 }}>Day {day.n}에 담을 곳</span>
                      <button onClick={() => setPick(null)} style={{ border: 'none', background: 'none', cursor: 'pointer', padding: 2 }}><JJIcon name="close" size={14} color="var(--ink-3)" sw={2} /></button>
                    </div>
                    <div style={{ display: 'flex', flexDirection: 'column', gap: 5, maxHeight: 168, overflowY: 'auto' }}>
                      {avail.map(p => (
                        <button key={p.id} onClick={() => add(day.n, p.id)} style={{ display: 'flex', alignItems: 'center', gap: 9, width: '100%', textAlign: 'left', background: 'var(--paper-2)', border: '1px solid var(--line-soft)', borderRadius: 9, padding: '6px 8px', cursor: 'pointer' }}>
                          <Photo scene={p.scene} h={28} r={7} style={{ width: 28, flexShrink: 0 }} />
                          <span style={{ flex: 1, fontFamily: 'var(--f-body)', fontSize: 12.5, fontWeight: 500, color: 'var(--ink)' }}>{p.name}</span>
                          <span style={{ width: 22, height: 22, borderRadius: '50%', background: 'var(--accent-soft)', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}><JJIcon name="plus" size={13} color="var(--coral)" sw={2.2} /></span>
                        </button>
                      ))}
                      {avail.length === 0 && <div style={{ fontFamily: 'var(--f-body)', fontSize: 12, color: 'var(--ink-3)', textAlign: 'center', padding: 8 }}>담을 수 있는 곳을 다 담았어요 🎉</div>}
                    </div>
                  </div>
                ) : (
                  <button onClick={() => setPick(day.n)} style={{ marginTop: 8, display: 'inline-flex', alignItems: 'center', gap: 6, background: 'transparent', border: '1px dashed var(--line)', borderRadius: 999, padding: '6px 13px', cursor: 'pointer', fontFamily: 'var(--f-body)', fontSize: 12, fontWeight: 600, color: 'var(--coral)' }}>
                    <JJIcon name="plus" size={14} color="var(--coral)" sw={2} />장소 담기
                  </button>
                ))}
              </div>
            </div>
          );
        })}
      </div>
    </Card>
  );
}

// 공통 — 빈 상태 안내 카드
function EmptyHint({ icon, title, desc, tone = 'ink' }) {
  return (
    <Card pad={18} style={{ textAlign: 'center', background: 'var(--paper-2)', borderStyle: 'dashed' }}>
      <div style={{ width: 46, height: 46, borderRadius: 14, margin: '0 auto 10px', background: `color-mix(in srgb, var(--${tone === 'ink' ? 'ink-3' : tone}) 12%, var(--card))`, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
        <JJIcon name={icon} size={22} color={`var(--${tone === 'ink' ? 'ink-3' : tone})`} />
      </div>
      <div style={{ fontFamily: 'var(--f-display)', fontWeight: 700, fontSize: 15, color: 'var(--ink)' }}>{title}</div>
      <div style={{ fontFamily: 'var(--f-body)', fontSize: 12.5, color: 'var(--ink-3)', marginTop: 4, lineHeight: 1.5 }}>{desc}</div>
    </Card>
  );
}

// ── 단계별 본문 (active일 때 펼침) — scr로 before/after 분기 ──
// 여행(재방문) 요청 폼 — 손님이 '가고 싶다'를 먼저 보낸다
function TripRequestForm({ title, sub, cta }) {
  const dates = ['이번 주말', '다음 주', '이번 여름', '직접 고르기'];
  const [sel, setSel] = React.useState(1);
  const [sent, setSent] = React.useState(false);
  if (sent) return <RequestSent when={dates[sel]} />;
  return (
    <Card pad={16}>
      <Kicker color="var(--coral)">여행 요청 · 가고 싶어요</Kicker>
      <div style={{ fontFamily: 'var(--f-display)', fontWeight: 700, fontSize: 17, color: 'var(--ink)', margin: '9px 0 3px' }}>{title}</div>
      <div style={{ fontFamily: 'var(--f-body)', fontSize: 12.5, color: 'var(--ink-2)', marginBottom: 13 }}>{sub}</div>
      <div style={{ fontFamily: 'var(--f-body)', fontSize: 11, fontWeight: 600, color: 'var(--ink-3)', marginBottom: 7 }}>언제쯤 가고 싶어요?</div>
      <div style={{ display: 'flex', flexWrap: 'wrap', gap: 7, marginBottom: 13 }}>
        {dates.map((d, i) => (
          <button key={d} onClick={() => setSel(i)} style={{ fontFamily: 'var(--f-body)', fontSize: 12.5, fontWeight: 600, padding: '7px 13px', borderRadius: 999, cursor: 'pointer', background: sel === i ? 'var(--coral)' : 'var(--card)', color: sel === i ? '#fff' : 'var(--ink-2)', border: sel === i ? 'none' : '1px solid var(--line)' }}>{d}</button>
        ))}
      </div>
      <div style={{ padding: '11px 13px', borderRadius: 12, background: 'var(--paper-2)', border: '1px dashed var(--line)', fontFamily: 'var(--f-hand)', fontSize: 'calc(16px * var(--hand-scale))', color: 'var(--ink-3)', marginBottom: 13 }}>한 마디 — “오랜만에 부산 가고 싶어요!”</div>
      <BtnPrimary icon="send" full onClick={() => setSent(true)}>{cta || '요청 보내기'}</BtnPrimary>
      <div style={{ fontFamily: 'var(--f-body)', fontSize: 11.5, color: 'var(--ink-3)', textAlign: 'center', marginTop: 10 }}>예약이 아니라, 가고 싶다는 마음을 먼저 전해요.</div>
    </Card>
  );
}
function RequestSent({ when }) {
  return (
    <Card pad={16} style={{ textAlign: 'center' }}>
      <div style={{ width: 46, height: 46, borderRadius: '50%', margin: '0 auto 11px', background: 'var(--accent-soft)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}><JJIcon name="send" size={22} color="var(--coral)" /></div>
      <div style={{ fontFamily: 'var(--f-display)', fontWeight: 700, fontSize: 16, color: 'var(--ink)' }}>요청을 보냈어요</div>
      <div style={{ fontFamily: 'var(--f-body)', fontSize: 12.5, color: 'var(--ink-2)', margin: '4px 0 12px' }}>{when} · 쩨가 수락하면 초대장이 도착해요.</div>
      <Tag tone="amber">쩨의 수락 대기 중</Tag>
    </Card>
  );
}
// 부산역 픽업 요청 (손님)
function PickupRequest() {
  const [req, setReq] = React.useState(false);
  return (
    <Card pad={14} style={{ background: req ? 'var(--accent-soft)' : 'var(--card)', border: req ? '1px solid color-mix(in srgb, var(--coral) 25%, transparent)' : '1px solid var(--line-soft)' }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 11 }}>
        {req ? <Avatar name={JJ.host.initial} tone="host" size={38} /> : <div style={{ width: 38, height: 38, borderRadius: 11, background: 'var(--accent-soft)', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}><JJIcon name="pin" size={19} color="var(--coral)" /></div>}
        <div style={{ flex: 1 }}>
          <div style={{ fontFamily: 'var(--f-display)', fontWeight: 700, fontSize: 14.5, color: 'var(--ink)' }}>{req ? '쩨가 마중 나와요' : '부산역 픽업'}</div>
          <div style={{ fontFamily: 'var(--f-body)', fontSize: 12, color: 'var(--ink-3)' }}>{req ? '도착 10분 전 알림 → 3번 출구' : '혼자 오기 부담되면 마중을 부탁해요'}</div>
        </div>
        {req ? <Tag tone="coral" solid>요청됨</Tag> : <button onClick={() => setReq(true)} style={{ fontFamily: 'var(--f-body)', fontSize: 12.5, fontWeight: 600, color: '#fff', background: 'var(--coral)', border: 'none', borderRadius: 999, padding: '8px 14px', cursor: 'pointer', flexShrink: 0 }}>요청하기</button>}
      </div>
    </Card>
  );
}

function StageBody({ persona, state, scr, go, openSheet }) {
  const isHost = persona === 'host';
  const t = JJ.trip;
  const opts = SCREEN_STATES[persona + ':' + state] || [];
  const cur = (opts.find(o => o.k === scr) || opts[0] || {}).k;

  // ===================== GUEST =====================
  if (!isHost) {
    if (state === 'requested') {
      if (cur === 'sent') return <RequestSent when="6월 13–16일" />;
      return <TripRequestForm title="쩨네 집에 가보고 싶어요" sub="동래 바다가 집, 며칠 신세 져도 될까요?" />;
    }
    if (state === 'invited') {
      const ready = cur === 'ready';
      return (
        <div>
          <div style={{ position: 'relative', borderRadius: 16, overflow: 'hidden' }}>
            <Photo scene="sunset" h={140} r={16} />
            <div style={{ position: 'absolute', inset: 0, background: 'linear-gradient(180deg, transparent 30%, rgba(123,74,85,.55))' }} />
            <div style={{ position: 'absolute', left: 14, bottom: 12 }}>
              <Tag solid tone="coral" style={{ background: 'rgba(255,255,255,.92)', color: 'var(--coral)' }}>초대장이 도착했어요</Tag>
              <div style={{ fontFamily: 'var(--f-hand)', fontSize: 'calc(30px * var(--hand-scale))', color: '#fff', marginTop: 6, textShadow: '0 2px 10px rgba(0,0,0,.4)' }}>곧 만나요</div>
            </div>
          </div>
          <Card pad={15} style={{ marginTop: 10, background: 'var(--paper-2)' }}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 10 }}>
              <Avatar name={JJ.host.initial} tone="host" size={36} ring />
              <div><div style={{ fontFamily: 'var(--f-body)', fontSize: 11, color: 'var(--ink-3)' }}>{JJ.host.name} 호스트가 초대했어요</div><div style={{ fontFamily: 'var(--f-display)', fontWeight: 700, fontSize: 14.5, color: 'var(--ink)' }}>{JJ.home.name} · {JJ.home.place}</div></div>
            </div>
            <div style={{ fontFamily: 'var(--f-display)', fontSize: 15.5, lineHeight: 1.7, color: 'var(--ink)', whiteSpace: 'pre-line' }}>{t.welcome}</div>
            <div style={{ display: 'flex', gap: 7, marginTop: 11 }}><Tag tone="sea"><JJIcon name="clock" size={12} color="var(--sea)" />{t.dates}</Tag><Tag tone="amber">{t.nights}박 · 무료</Tag></div>
          </Card>
          <div style={{ display: 'flex', flexDirection: 'column', gap: 8, marginTop: 10 }}>
            <EntryCard icon="map" title="나만의 부산 지도" desc={ready ? '미리 둘러봤어요' : "쩨가 고른 '우리의 부산' 미리보기"} tone="sea" done={ready} onClick={() => go('map')} />
            <EntryCard icon="user" title="선호 남기기" desc={ready ? '알레르기·취향 남겼어요' : '알레르기 · 취향 미리 알려줘요'} tone="coral" done={ready} onClick={() => go('home', 'prefs')} />
          </div>
          {ready && <div style={{ textAlign: 'center', marginTop: 12 }}><Hand size={20} color="var(--coral)">이제 가기만 하면 돼요!</Hand></div>}
        </div>
      );
    }

    if (state === 'prearrival') {
      if (cur === 'pre') {
        return (
          <div>
            <Card pad={16} style={{ textAlign: 'center' }}>
              <div style={{ width: 46, height: 46, borderRadius: 14, margin: '0 auto 10px', background: 'var(--accent-soft)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}><JJIcon name="train" size={23} color="var(--coral)" /></div>
              <div style={{ fontFamily: 'var(--f-display)', fontWeight: 700, fontSize: 16, color: 'var(--ink)' }}>도착 정보를 공유할까요?</div>
              <div style={{ fontFamily: 'var(--f-body)', fontSize: 12.5, color: 'var(--ink-2)', margin: '5px 0 14px', lineHeight: 1.55 }}>KTX·SRT 티켓만 공유하면 쩨가 도착 시각에 맞춰 마중 나와요.</div>
              <BtnPrimary icon="send" full onClick={() => openSheet && go('trip')}>티켓 공유하기</BtnPrimary>
            </Card>
            <div style={{ display: 'flex', flexDirection: 'column', gap: 8, marginTop: 9 }}>
              <EntryCard icon="key" title="웰컴 키트" desc="도어락 · 와이파이 · 충전기 위치" tone="amber" onClick={() => go('home', 'kit')} />
              <EntryCard icon="home" title="집 안내" desc="오는 법 · 날씨 · 동선" tone="sea" onClick={() => go('home', 'guide')} />
            </div>
          </div>
        );
      }
      return (
        <div>
          <Card pad={0} style={{ overflow: 'hidden' }}>
            <div style={{ padding: '12px 15px', display: 'flex', alignItems: 'center', gap: 9, borderBottom: '1px dashed var(--line)' }}>
              <JJIcon name="train" size={19} color="var(--sea)" /><div style={{ fontFamily: 'var(--f-display)', fontWeight: 700, fontSize: 14.5, color: 'var(--ink)', flex: 1 }}>티켓을 공유했어요</div><Tag tone="sea" solid>전달됨</Tag>
            </div>
            <div style={{ padding: '13px 15px', display: 'flex', alignItems: 'center', gap: 14 }}>
              <div><div style={{ fontFamily: 'var(--f-display)', fontWeight: 700, fontSize: 21, color: 'var(--ink)' }}>{t.arrive.train}</div><div style={{ fontFamily: 'var(--f-body)', fontSize: 11.5, color: 'var(--ink-3)' }}>{t.arrive.from} → 부산</div></div>
              <div style={{ flex: 1, textAlign: 'right' }}><div style={{ fontFamily: 'var(--f-body)', fontSize: 13, fontWeight: 600, color: 'var(--sea)' }}>{t.arrive.time}</div><div style={{ fontFamily: 'var(--f-body)', fontSize: 11.5, color: 'var(--ink-3)', marginTop: 1 }}>{t.arrive.platform}</div></div>
            </div>
          </Card>
          <div style={{ marginTop: 9 }}><PickupRequest /></div>
          <div style={{ display: 'flex', flexDirection: 'column', gap: 8, marginTop: 9 }}>
            <EntryCard icon="home" title="집 안내" desc="오는 법 · 날씨 · 동선" tone="sea" onClick={() => go('home', 'guide')} />
            <EntryCard icon="key" title="웰컴 키트" desc="도어락 · 와이파이 · 충전기 위치" tone="amber" onClick={() => go('home', 'kit')} />
          </div>
        </div>
      );
    }

    if (state === 'staying') {
      return (
        <div>
          <DayPlanner key={cur} persona={persona} seed={cur === 'empty' ? { 1: [], 2: [], 3: [] } : undefined} />
          <div style={{ marginTop: 10, display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 8 }}>
            <Card onClick={() => go('album')} pad={12}><JJIcon name="album" size={19} color="var(--sea)" /><div style={{ fontFamily: 'var(--f-display)', fontWeight: 700, fontSize: 13.5, color: 'var(--ink)', marginTop: 6 }}>공유 앨범</div></Card>
            <Card onClick={() => go('wallet')} pad={12}><JJIcon name="wallet" size={19} color="var(--amber)" /><div style={{ fontFamily: 'var(--f-display)', fontWeight: 700, fontSize: 13.5, color: 'var(--ink)', marginTop: 6 }}>공동지갑</div></Card>
          </div>
          <Card pad={13} onClick={() => openSheet('request')} style={{ marginTop: 10, display: 'flex', alignItems: 'center', gap: 11 }}>
            <div style={{ width: 38, height: 38, borderRadius: 11, background: 'var(--accent-soft)', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}><JJIcon name="bell" size={19} color="var(--coral)" /></div>
            <div style={{ flex: 1 }}><div style={{ fontFamily: 'var(--f-display)', fontWeight: 700, fontSize: 14, color: 'var(--ink)' }}>필요한 거, 편하게 말해요</div><div style={{ fontFamily: 'var(--f-body)', fontSize: 11.5, color: 'var(--ink-3)' }}>수건 · 충전기 · 늦잠…</div></div>
            <JJIcon name="chevron" size={15} color="var(--line)" sw={2.2} />
          </Card>
        </div>
      );
    }

    if (state === 'departing') {
      const left = cur === 'left';
      return (
        <div>
          <Card onClick={() => openSheet('memory')} pad={0} style={{ overflow: 'hidden', cursor: 'pointer' }}>
            <div style={{ position: 'relative', height: 150 }}>
              <Photo scene={JJ.memory.cover} h={150} r={0} />
              <div style={{ position: 'absolute', inset: 0, background: 'linear-gradient(180deg, transparent, rgba(123,74,85,.6))' }} />
              <div style={{ position: 'absolute', left: 14, right: 14, bottom: 12 }}>
                <Tag solid tone="coral" style={{ background: 'rgba(255,255,255,.92)', color: 'var(--coral)' }}><JJIcon name="gift" size={12} color="var(--coral)" />추억 선물</Tag>
                <div style={{ fontFamily: 'var(--f-display)', fontWeight: 700, fontSize: 19, color: '#fff', marginTop: 6, textShadow: '0 2px 10px rgba(0,0,0,.4)' }}>{JJ.memory.title}</div>
              </div>
            </div>
            <div style={{ padding: 13, display: 'flex', alignItems: 'center', gap: 12 }}>
              {[['장소', JJ.memory.stats.places], ['사진', JJ.memory.stats.photos], ['함께', JJ.memory.stats.days]].map(([l, n]) => (
                <div key={l} style={{ flex: 1, textAlign: 'center' }}><div style={{ fontFamily: 'var(--f-display)', fontWeight: 700, fontSize: 18, color: 'var(--coral)' }}>{n}</div><div style={{ fontFamily: 'var(--f-body)', fontSize: 10.5, color: 'var(--ink-3)' }}>{l}</div></div>
              ))}
              <BtnPrimary onClick={(e) => { e.stopPropagation(); openSheet('memory'); }}>열어보기</BtnPrimary>
            </div>
          </Card>
          {left ? (
            <Card pad={14} style={{ marginTop: 9, background: 'var(--paper-2)' }}>
              <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 8 }}><JJIcon name="book" size={17} color="var(--sea)" /><span style={{ fontFamily: 'var(--f-display)', fontWeight: 700, fontSize: 14.5, color: 'var(--ink)', flex: 1 }}>방명록에 남겼어요</span><Tag tone="sea">완료</Tag></div>
              <div style={{ padding: '11px 13px', borderRadius: 12, background: 'var(--card)', border: '1px solid var(--line-soft)' }}>
                <Hand size={20} color="var(--ink)">막걸리도 흰여울 아침도 다 좋았어요. 여기 오면 부산이 우리집 같아져요. 또 올게요!</Hand>
                <div style={{ fontFamily: 'var(--f-body)', fontSize: 11, color: 'var(--ink-3)', marginTop: 5 }}>— 민서 · 이번 방문</div>
              </div>
            </Card>
          ) : (
            <Card pad={13} onClick={() => openSheet('guestbook')} style={{ marginTop: 9, display: 'flex', alignItems: 'center', gap: 11, background: 'var(--paper-2)' }}>
              <div style={{ width: 38, height: 38, borderRadius: 11, background: 'color-mix(in srgb, var(--sea) 12%, var(--card))', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}><JJIcon name="book" size={19} color="var(--sea)" /></div>
              <div style={{ flex: 1 }}><div style={{ fontFamily: 'var(--f-display)', fontWeight: 700, fontSize: 14, color: 'var(--ink)' }}>방명록에 한 줄 남기기</div><div style={{ fontFamily: 'var(--f-body)', fontSize: 11.5, color: 'var(--ink-3)' }}>이 집을 거쳐간 사람들 사이에</div></div>
              <Hand size={16}>또 와요</Hand>
            </Card>
          )}
        </div>
      );
    }

    // after
    if (cur === 'request') {
      return (
        <div>
          <TripRequestForm title="또 가고 싶어요" sub="동백섬 한 바퀴 약속, 지키러 갈래요." cta="다시 여행 요청 보내기" />
        </div>
      );
    }
    return (
      <div>
        <Card pad={13} style={{ display: 'flex', alignItems: 'center', gap: 11, background: 'var(--accent-soft)', border: '1px solid color-mix(in srgb, var(--coral) 22%, transparent)' }}>
          <div style={{ width: 38, height: 38, borderRadius: 11, background: 'var(--card)', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}><JJIcon name="loop" size={19} color="var(--coral)" /></div>
          <div style={{ flex: 1 }}><div style={{ fontFamily: 'var(--f-display)', fontWeight: 700, fontSize: 14, color: 'var(--ink)' }}>회고가 도착했어요</div><div style={{ fontFamily: 'var(--f-body)', fontSize: 11.5, color: 'var(--ink-2)' }}>부산 다녀온 지 일주일째 · 다시 펼쳐볼래요?</div></div>
        </Card>
        <Card onClick={() => openSheet('memory')} pad={0} style={{ overflow: 'hidden', marginTop: 9 }}>
          <div style={{ position: 'relative', height: 110 }}>
            <Photo scene={JJ.memory.cover} h={110} r={0} />
            <div style={{ position: 'absolute', inset: 0, background: 'linear-gradient(180deg, transparent, rgba(123,74,85,.55))' }} />
            <div style={{ position: 'absolute', left: 13, bottom: 10 }}><Tag solid tone="coral" style={{ background: 'rgba(255,255,255,.9)', color: 'var(--coral)' }}><JJIcon name="gift" size={11} color="var(--coral)" />추억 선물 다시 보기</Tag></div>
          </div>
        </Card>
        <EntryCard icon="book" title="방명록" desc="내 한 줄이 집의 역사로 남았어요" tone="sea" onClick={() => go('home', 'guestbook')} />
        <Card pad={13} style={{ marginTop: 10, display: 'flex', alignItems: 'center', gap: 11, background: 'var(--paper-2)' }}>
          <div style={{ width: 38, height: 38, borderRadius: 11, background: 'color-mix(in srgb, var(--coral) 12%, var(--card))', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}><JJIcon name="loop" size={19} color="var(--coral)" /></div>
          <div style={{ flex: 1 }}><div style={{ fontFamily: 'var(--f-display)', fontWeight: 700, fontSize: 14, color: 'var(--ink)' }}>또 가고 싶다면</div><div style={{ fontFamily: 'var(--f-body)', fontSize: 11.5, color: 'var(--ink-3)' }}>‘다시 여행 요청’ 상태에서 보낼 수 있어요</div></div>
          <Hand size={16}>또 와요</Hand>
        </Card>
      </div>
    );
  }

  // ===================== HOST =====================
  if (state === 'requested') {
    if (cur === 'accepted') {
      return (
        <Card pad={16} style={{ textAlign: 'center' }}>
          <div style={{ width: 48, height: 48, borderRadius: '50%', margin: '0 auto 11px', background: 'color-mix(in srgb, var(--coral) 15%, var(--card))', display: 'flex', alignItems: 'center', justifyContent: 'center' }}><JJIcon name="check" size={24} color="var(--coral)" sw={2.4} /></div>
          <div style={{ fontFamily: 'var(--f-display)', fontWeight: 700, fontSize: 16, color: 'var(--ink)' }}>수락했어요</div>
          <div style={{ fontFamily: 'var(--f-body)', fontSize: 12.5, color: 'var(--ink-2)', margin: '4px 0 12px' }}>민서에게 초대장을 발행했어요. 이제 ‘초대됨’ 단계예요.</div>
          <Tag tone="coral" solid>초대장 발행됨</Tag>
        </Card>
      );
    }
    return (
      <Card pad={15}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 11 }}>
          <Avatar name={JJ.guest.initial} tone="guest" size={38} />
          <div style={{ flex: 1 }}><div style={{ fontFamily: 'var(--f-display)', fontWeight: 700, fontSize: 15, color: 'var(--ink)' }}>민서의 여행 요청</div><div style={{ fontFamily: 'var(--f-body)', fontSize: 11.5, color: 'var(--ink-3)' }}>가고 싶다고 먼저 연락이 왔어요</div></div>
          <Tag tone="coral" solid>새 요청</Tag>
        </div>
        <div style={{ padding: '11px 13px', borderRadius: 12, background: 'var(--paper-2)', marginBottom: 12 }}>
          <div style={{ display: 'flex', gap: 7, marginBottom: 7 }}><Tag tone="sea"><JJIcon name="clock" size={12} color="var(--sea)" />6월 13–16일 (3박)</Tag></div>
          <Hand size={20} color="var(--ink)">“오랜만에 부산 가고 싶어요!”</Hand>
        </div>
        <div style={{ display: 'flex', gap: 8 }}>
          <BtnGhost full>나중에</BtnGhost>
          <BtnPrimary icon="send" full onClick={() => go('trip')}>수락하고 초대</BtnPrimary>
        </div>
        <div style={{ fontFamily: 'var(--f-body)', fontSize: 11.5, color: 'var(--ink-3)', textAlign: 'center', marginTop: 10 }}>수락하면 ‘초대됨’으로 넘어가요.</div>
      </Card>
    );
  }
  if (state === 'invited') {
    if (cur === 'compose') {
      return (
        <div>
          <Card pad={16} style={{ textAlign: 'center' }}>
            <Avatar name={JJ.guest.initial} tone="guest" size={44} ring />
            <div style={{ fontFamily: 'var(--f-display)', fontWeight: 700, fontSize: 16, color: 'var(--ink)', marginTop: 10 }}>{JJ.guest.name}를 초대할까요?</div>
            <div style={{ fontFamily: 'var(--f-body)', fontSize: 12.5, color: 'var(--ink-2)', margin: '5px 0 14px' }}>{t.dates} · 설치 없이 링크 하나로. 예약이 아니라 환대의 시작.</div>
            <BtnPrimary icon="send" full onClick={() => go('trip')}>초대 보내기</BtnPrimary>
          </Card>
          <div style={{ display: 'flex', flexDirection: 'column', gap: 8, marginTop: 9 }}>
            <EntryCard icon="map" title="부산 지도 큐레이션" desc={`'우리의 부산' 핀 ${JJ.pins.length}곳`} tone="sea" onClick={() => go('map')} />
            <EntryCard icon="key" title="웰컴 키트 준비" desc="한 번 만들면 트립마다 재사용" tone="amber" onClick={() => go('home', 'kit')} />
          </div>
        </div>
      );
    }
    return (
      <div>
        <Card pad={14}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
            <Avatar name={JJ.guest.initial} tone="guest" size={38} />
            <div style={{ flex: 1 }}><div style={{ fontFamily: 'var(--f-display)', fontWeight: 700, fontSize: 15, color: 'var(--ink)' }}>{JJ.guest.name}에게 초대장 발행</div><div style={{ fontFamily: 'var(--f-body)', fontSize: 11.5, color: 'var(--ink-3)' }}>{t.dates} · 설치 없이 링크로</div></div>
            <Tag tone="coral" solid>전송됨</Tag>
          </div>
          <div style={{ marginTop: 11, padding: '9px 11px', borderRadius: 10, background: 'var(--paper-2)', border: '1px dashed var(--line)', display: 'flex', alignItems: 'center', gap: 8 }}>
            <JJIcon name="send" size={14} color="var(--coral)" /><div style={{ flex: 1, fontFamily: 'var(--f-body)', fontSize: 12, color: 'var(--ink-2)', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>jjeus.house/min-seo</div><span style={{ fontFamily: 'var(--f-body)', fontSize: 11.5, fontWeight: 600, color: 'var(--sea)' }}>복사</span>
          </div>
        </Card>
        <div style={{ display: 'flex', flexDirection: 'column', gap: 8, marginTop: 10 }}>
          <EntryCard icon="map" title="부산 지도 큐레이션" desc={`'우리의 부산' 핀 ${JJ.pins.length}곳`} tone="sea" onClick={() => go('map')} />
          <EntryCard icon="user" title="민서가 남긴 선호" desc="땅콩·갑각류 알레르기 — 주의" tone="coral" badge="1" onClick={() => go('home', 'prefs')} />
        </div>
      </div>
    );
  }

  if (state === 'prearrival') {
    if (cur === 'waiting') {
      return (
        <div>
          <EmptyHint icon="clock" title="도착 정보를 기다리는 중" desc="민서가 아직 티켓을 공유하지 않았어요. 공유되면 마중 타이밍을 잡아줄게요." tone="sea" />
          <Card pad={13} style={{ marginTop: 9, display: 'flex', gap: 10, alignItems: 'center', background: 'var(--accent-soft)' }}>
            <JJIcon name="bell" size={18} color="var(--coral)" /><div style={{ fontFamily: 'var(--f-body)', fontSize: 12.5, color: 'var(--ink-2)', flex: 1 }}>티켓이 오면 <b style={{ color: 'var(--ink)' }}>자동으로 알림</b>이 와요.</div>
          </Card>
        </div>
      );
    }
    return (
      <div>
        <Card pad={0} style={{ overflow: 'hidden' }}>
          <div style={{ padding: '12px 15px', display: 'flex', alignItems: 'center', gap: 9, borderBottom: '1px dashed var(--line)' }}>
            <Avatar name={JJ.guest.initial} tone="guest" size={30} /><div style={{ fontFamily: 'var(--f-display)', fontWeight: 700, fontSize: 14.5, color: 'var(--ink)', flex: 1 }}>{JJ.guest.name}의 도착</div><Tag tone="sea">티켓 공유됨</Tag>
          </div>
          <div style={{ padding: '13px 15px', textAlign: 'center' }}>
            <div style={{ fontFamily: 'var(--f-body)', fontSize: 11.5, color: 'var(--ink-3)' }}>{t.arrive.train} · {t.arrive.from}발</div>
            <div style={{ fontFamily: 'var(--f-display)', fontWeight: 700, fontSize: 26, color: 'var(--sea)', margin: '3px 0' }}>14:32 도착</div>
            <Tag tone="coral"><JJIcon name="clock" size={12} color="var(--coral)" />지금 출발하면 딱 맞아요</Tag>
          </div>
          <div style={{ padding: '0 15px 14px' }}><BtnPrimary icon="pin" full tone="sea">부산역 3번 출구로 마중</BtnPrimary></div>
        </Card>
      </div>
    );
  }

  if (state === 'staying') {
    const reqByCur = cur === 'none' ? [] : cur === 'done' ? JJ.requests.map(r => ({ ...r, state: 'done' })) : JJ.requests;
    return (
      <div>
        <DayPlanner persona={persona} />
        <Card pad={14} style={{ marginTop: 10 }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 9 }}>
            <JJIcon name="bell" size={17} color="var(--coral)" /><span style={{ fontFamily: 'var(--f-display)', fontWeight: 700, fontSize: 14.5, color: 'var(--ink)', flex: 1 }}>민서의 요청</span>
            {cur === 'incoming' && <Tag tone="coral" solid>1 진행중</Tag>}
            {cur === 'done' && <Tag tone="sea">모두 완료</Tag>}
          </div>
          {reqByCur.length === 0 ? (
            <div style={{ fontFamily: 'var(--f-hand)', fontSize: 'calc(17px * var(--hand-scale))', color: 'var(--ink-3)', textAlign: 'center', padding: '6px 0' }}>아직 요청이 없어요 — 조용한 하루</div>
          ) : reqByCur.map((r, i) => (
            <div key={r.id} style={{ display: 'flex', alignItems: 'center', gap: 9, padding: '7px 0', borderTop: i ? '1px solid var(--line-soft)' : 'none' }}>
              <div style={{ width: 7, height: 7, borderRadius: '50%', background: r.state === 'done' ? 'var(--sea)' : 'var(--coral)', flexShrink: 0 }} />
              <div style={{ flex: 1, fontFamily: 'var(--f-body)', fontSize: 12.5, color: r.state === 'done' ? 'var(--ink-3)' : 'var(--ink)' }}>{r.text}</div>
              <span style={{ fontFamily: 'var(--f-body)', fontSize: 10.5, fontWeight: 600, color: r.state === 'done' ? 'var(--ink-3)' : 'var(--coral)' }}>{r.state === 'done' ? '완료' : '챙기는 중'}</span>
            </div>
          ))}
        </Card>
        <div style={{ marginTop: 10, display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 8 }}>
          <Card onClick={() => go('album')} pad={12}><JJIcon name="album" size={19} color="var(--sea)" /><div style={{ fontFamily: 'var(--f-display)', fontWeight: 700, fontSize: 13.5, color: 'var(--ink)', marginTop: 6 }}>공유 앨범</div></Card>
          <Card onClick={() => go('wallet')} pad={12}><JJIcon name="wallet" size={19} color="var(--amber)" /><div style={{ fontFamily: 'var(--f-display)', fontWeight: 700, fontSize: 13.5, color: 'var(--ink)', marginTop: 6 }}>공동지갑</div></Card>
        </div>
      </div>
    );
  }

  if (state === 'departing') {
    const letter = cur === 'letter';
    return (
      <div>
        <Card pad={0} style={{ overflow: 'hidden' }}>
          <div style={{ position: 'relative', height: 130 }}>
            <Photo scene={JJ.memory.cover} h={130} r={0} />
            <div style={{ position: 'absolute', inset: 0, background: 'linear-gradient(180deg, transparent, rgba(123,74,85,.6))' }} />
            <div style={{ position: 'absolute', left: 14, bottom: 12 }}><Tag solid tone="coral" style={{ background: 'rgba(255,255,255,.92)', color: 'var(--coral)' }}><JJIcon name="gift" size={12} color="var(--coral)" />추억 선물 (자동 생성됨)</Tag><div style={{ fontFamily: 'var(--f-display)', fontWeight: 700, fontSize: 17, color: '#fff', marginTop: 6 }}>{JJ.memory.title}</div></div>
          </div>
          <div style={{ padding: 13 }}>
            {letter ? (
              <React.Fragment>
                <div style={{ fontFamily: 'var(--f-body)', fontSize: 12, color: 'var(--ink-2)', marginBottom: 9 }}>손글씨 한 줄을 더했어요. 배웅 때 건네면 완성.</div>
                <div style={{ padding: '10px 12px', borderRadius: 11, background: 'var(--paper-2)', border: '1px dashed var(--coral)' }}><Hand size={20} color="var(--ink)" style={{ whiteSpace: 'pre-line', display: 'block' }}>{JJ.memory.letter}</Hand></div>
                <BtnPrimary icon="send" full style={{ marginTop: 11 }} onClick={() => openSheet('memory')}>배웅 때 건네기</BtnPrimary>
              </React.Fragment>
            ) : (
              <React.Fragment>
                <div style={{ fontFamily: 'var(--f-body)', fontSize: 12, color: 'var(--ink-2)', marginBottom: 9 }}>앨범·장소·순간이 한 편으로 엮였어요. 손글씨 한 줄만 더하면 완성.</div>
                <div style={{ padding: '12px', borderRadius: 11, background: 'var(--paper-2)', border: '1px dashed var(--line)', textAlign: 'center', fontFamily: 'var(--f-hand)', fontSize: 'calc(16px * var(--hand-scale))', color: 'var(--ink-3)' }}>여기에 손글씨 한 줄을 더해보세요</div>
                <BtnGhost icon="edit" full style={{ marginTop: 11 }} onClick={() => openSheet('memory')}>편지 쓰기</BtnGhost>
              </React.Fragment>
            )}
          </div>
        </Card>
      </div>
    );
  }

  // host after
  const received = cur === 'received';
  const rerequest = cur === 'rerequest';
  return (
    <div>
      <Card pad={13} style={{ display: 'flex', alignItems: 'center', gap: 11 }}>
        <div style={{ width: 38, height: 38, borderRadius: 11, background: 'color-mix(in srgb, var(--sea) 12%, var(--card))', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}><JJIcon name="loop" size={19} color="var(--sea)" /></div>
        <div style={{ flex: 1 }}><div style={{ fontFamily: 'var(--f-display)', fontWeight: 700, fontSize: 14, color: 'var(--ink)' }}>회고를 보냈어요</div><div style={{ fontFamily: 'var(--f-body)', fontSize: 11.5, color: 'var(--ink-3)' }}>일주일 뒤, 민서에게 추억이 다시 도착</div></div>
        <Tag tone="sea">발송됨</Tag>
      </Card>
      {rerequest ? (
        <Card pad={15} style={{ marginTop: 10, background: 'var(--accent-soft)', border: '1px solid color-mix(in srgb, var(--coral) 25%, transparent)' }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 10 }}>
            <Avatar name={JJ.guest.initial} tone="guest" size={36} />
            <div style={{ flex: 1 }}><div style={{ fontFamily: 'var(--f-display)', fontWeight: 700, fontSize: 14.5, color: 'var(--ink)' }}>민서가 또 오고 싶대요</div><div style={{ fontFamily: 'var(--f-body)', fontSize: 11.5, color: 'var(--ink-3)' }}>이번 여름쯤 재방문 요청</div></div>
            <Tag tone="coral" solid>새 요청</Tag>
          </div>
          <BtnPrimary icon="send" full onClick={() => go('trip')}>수락하고 새 초대장 보내기</BtnPrimary>
          <div style={{ fontFamily: 'var(--f-body)', fontSize: 11.5, color: 'var(--ink-2)', textAlign: 'center', marginTop: 9 }}>수락하면 새 여정으로 ‘요청 → 초대됨’부터 다시 시작돼요.</div>
        </Card>
      ) : received ? (
        <Card pad={14} style={{ marginTop: 10 }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 9 }}><JJIcon name="book" size={17} color="var(--sea)" /><span style={{ fontFamily: 'var(--f-display)', fontWeight: 700, fontSize: 14.5, color: 'var(--ink)', flex: 1 }}>민서가 남긴 한 줄</span></div>
          <div style={{ padding: '11px 13px', borderRadius: 12, background: 'var(--paper-2)' }}>
            <Hand size={20} color="var(--ink)">막걸리도 흰여울 아침도 다 좋았어요. 여기 오면 부산이 우리집 같아져요. 또 올게요!</Hand>
            <div style={{ fontFamily: 'var(--f-body)', fontSize: 11, color: 'var(--ink-3)', marginTop: 5 }}>— 민서 · 이번 방문</div>
          </div>
          <div style={{ fontFamily: 'var(--f-body)', fontSize: 12, color: 'var(--ink-2)', marginTop: 10 }}>이 집을 거쳐간 사람이 {JJ.home.visitsCount}명이 됐어요.</div>
        </Card>
      ) : (
        <div style={{ marginTop: 10 }}><EmptyHint icon="book" title="방명록을 기다리는 중" desc="민서가 아직 방명록을 안 남겼어요. 남기면 집에 한 줄이 쌓여요." tone="sea" /></div>
      )}
      <Card pad={15} style={{ marginTop: 10, textAlign: 'center', background: 'var(--paper-2)' }}>
        <Hand size={22}>또 부르고 싶은 사람</Hand>
        <div style={{ marginTop: 9 }}><BtnPrimary icon="plus" full>새 손님 초대하기</BtnPrimary></div>
      </Card>
    </div>
  );
}

// 단계 메타 (요약 / 잠금 라벨)
const STAGE_META = {
  guest: {
    requested:  { recap: '가고 싶다고 요청했어요', locked: '아직 요청 전이에요' },
    invited:    { recap: '초대를 받고 미리 둘러봤어요' },
    prearrival: { recap: '티켓 공유 · 마중 약속 완료', locked: '도착 전이 되면 열려요' },
    staying:    { recap: '함께한 며칠 · 가고 싶은 곳을 담았어요', locked: '머무는 동안 열려요' },
    departing:  { recap: '추억 선물과 방명록을 받았어요', locked: '떠나는 날 열려요' },
    after:      { recap: '회고로 다시 이어졌어요', locked: '다녀온 뒤 열려요' },
  },
  host: {
    requested:  { recap: '민서의 요청을 받았어요', locked: '아직 요청 전이에요' },
    invited:    { recap: '민서에게 초대장을 보냈어요' },
    prearrival: { recap: '마중 약속을 잡았어요', locked: '손님 도착 전이 되면 열려요' },
    staying:    { recap: '요청을 챙기고 동선을 맞췄어요', locked: '머무는 동안 열려요' },
    departing:  { recap: '추억 선물에 손편지를 더해 건넸어요', locked: '떠나는 날 열려요' },
    after:      { recap: '방명록이 집에 쌓였어요', locked: '배웅한 뒤 열려요' },
  },
};

// ── 여정 노드 ────────────────────────────────────────────────
function JourneyNode({ stage, status, last, persona, scr, go, openSheet }) {
  const [open, setOpen] = React.useState(false);
  const tone = stage.tone;
  const meta = STAGE_META[persona][stage.key];
  const lineColor = status === 'locked' ? 'var(--line)' : `var(--${tone})`;

  return (
    <div style={{ display: 'flex', gap: 14, opacity: status === 'locked' ? 0.5 : 1 }}>
      <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', width: 18, flexShrink: 0 }}>
        <div style={{
          width: status === 'active' ? 18 : 15, height: status === 'active' ? 18 : 15, borderRadius: '50%',
          background: status === 'locked' ? 'var(--card)' : `var(--${tone})`,
          border: status === 'locked' ? '2px solid var(--line)' : `2px solid var(--${tone})`,
          boxShadow: status === 'active' ? `0 0 0 5px color-mix(in srgb, var(--${tone}) 18%, transparent)` : 'none',
          display: 'flex', alignItems: 'center', justifyContent: 'center', marginTop: 3, transition: '.2s',
        }}>
          {status === 'done' && <JJIcon name="check" size={9} color="#fff" sw={3} />}
          {status === 'active' && <span style={{ width: 6, height: 6, borderRadius: '50%', background: '#fff' }} />}
        </div>
        {!last && <div style={{ flex: 1, width: 2.5, background: lineColor, marginTop: 4, borderRadius: 2, minHeight: 14 }} />}
      </div>
      <div style={{ flex: 1, minWidth: 0, paddingBottom: last ? 4 : 24 }}>
        <button onClick={() => status === 'done' && setOpen(o => !o)} style={{ display: 'flex', alignItems: 'center', gap: 9, width: '100%', textAlign: 'left', background: 'none', border: 'none', padding: 0, cursor: status === 'done' ? 'pointer' : 'default' }}>
          <div style={{ flex: 1, minWidth: 0 }}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
              <span style={{ fontFamily: 'var(--f-display)', fontWeight: 700, fontSize: status === 'active' ? 17 : 15, color: 'var(--ink)' }}>{stage.name}</span>
              <Hand size={status === 'active' ? 19 : 16} color={`var(--${tone})`}>{stage.phrase}</Hand>
              {status === 'active' && <span style={{ fontFamily: 'var(--f-body)', fontSize: 9.5, fontWeight: 700, letterSpacing: '.04em', color: '#fff', background: `var(--${tone})`, borderRadius: 5, padding: '2px 7px' }}>지금</span>}
            </div>
            <div style={{ fontFamily: 'var(--f-body)', fontSize: 12, color: 'var(--ink-3)', marginTop: 2 }}>{status === 'locked' ? meta.locked : meta.recap}</div>
          </div>
          {status === 'done' && <JJIcon name={open ? 'close' : 'chevron'} size={14} color="var(--ink-3)" sw={2} style={{ transform: open ? 'none' : 'rotate(90deg)' }} />}
          {status === 'locked' && <div style={{ width: 22, height: 22, borderRadius: '50%', border: '1.5px solid var(--line)', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}><JJIcon name="clock" size={12} color="var(--ink-3)" /></div>}
        </button>
        {(status === 'active' || (status === 'done' && open)) && (
          <div style={{ marginTop: 12 }}>
            <StageBody persona={persona} state={stage.key} scr={status === 'active' ? scr : null} go={go} openSheet={openSheet} />
          </div>
        )}
      </div>
    </div>
  );
}

// ── 타임라인 ─────────────────────────────────────────────────
function TripTab({ persona, tripState, scr, go, openSheet }) {
  const cur = JJ_STATES.findIndex(s => s.key === tripState);
  const curState = JJ_STATES[cur];
  const stOpts = SCREEN_STATES[persona + ':' + tripState] || [];
  const stLabel = (stOpts.find(o => o.k === scr) || stOpts[0] || {}).label;
  return (
    <div>
      <div style={{ marginBottom: 16 }}>
        <Kicker color="var(--coral)">손님의 여정 · {persona === 'host' ? '호스트 시점' : '손님 시점'}<span style={{ flex: 1, height: 1, background: 'var(--line)' }} /></Kicker>
        <div style={{ fontFamily: 'var(--f-display)', fontWeight: 700, fontSize: 22, color: 'var(--ink)', marginTop: 9, lineHeight: 1.3 }}>곧 만나요 → 또 와요</div>
        <div style={{ fontFamily: 'var(--f-body)', fontSize: 12.5, color: 'var(--ink-2)', marginTop: 5 }}>
          지금은 <b style={{ color: `var(--${curState.tone})` }}>{curState.name}</b>{stLabel ? <span> · <b style={{ color: 'var(--sea)' }}>{stLabel}</b></span> : null} 단계예요.
        </div>
      </div>
      {JJ_STATES.map((s, i) => (
        <JourneyNode key={s.key} stage={s} status={i < cur ? 'done' : i === cur ? 'active' : 'locked'} last={i === JJ_STATES.length - 1} persona={persona} scr={scr} go={go} openSheet={openSheet} />
      ))}
    </div>
  );
}

Object.assign(window, { TripTab, DayPlanner, JourneyNode, StageBody });
