/*__IIFE_WRAPPED__*/
;(function(){
// screens-main.jsx — Home / Event-Create / Settings
const { useState: useStateM, useRef: useRefM, useEffect: useEffM } = React;
const W = window;
const { Icon, Btn } = window;

/* ─────────── 名前フォールバック / ホームのサジェスト（旧MOCK由来）─────────── */
const ME_FALLBACK = 'あなた';
const PARTNER_FALLBACK = 'パートナー';
const HOME_SUGGEST = ['デートのアイデア出して', '最近ちょっとすれ違い気味', 'アプリのここが使いにくい', 'サプライズを相談'];

/* 設定 →「このアプリについて」。ハッカソン提出作品としての位置づけと、
   データの扱いをまとめてここに集約する（利用規約とプライバシーポリシーは分けない）*/
const LEGAL_SECTIONS = [
  { icon: 'sparkle', title: 'ハッカソンの作品です',
    body: 'Amulet は「DevOps × AI Agent Hackathon」に向けて制作したプロトタイプです。商用サービスではなく、予告なく停止したり、データが削除されることがあります。' },
  { icon: 'note', title: 'あつめる情報',
    body: 'メールアドレス、表示名、最寄駅、付き合った日、予定・本音・チャットに入力した内容。これらは Google Cloud（Firebase Authentication / Firestore）に保存されます。' },
  { icon: 'chat', title: 'AIへの送信',
    body: 'プランの生成や相談のため、入力内容は Google Cloud の Vertex AI に送信されます。モデルの学習には使われません。' },
  { icon: 'heart', title: 'ふたりの本音',
    body: '「本音」に書いた原文は、相手には表示されません。AIが受け取って要約した結果だけが、プランというかたちで共有されます。' },
  { icon: 'lock', title: '利用状況の計測',
    body: 'Google Analytics 4 と Microsoft Clarity で、画面遷移などの匿名イベントのみを計測しています。氏名・メールアドレス・チャット本文は送信していません。' },
  { icon: 'clock', title: '免責',
    body: '提案されるプランやお店の情報には AI が生成した内容が含まれ、正確性は保証されません。営業時間や料金などは、おでかけ前にご自身でご確認ください。' },
];

/* 「このアプリについて」ダイアログ。設定画面とサインイン画面の両方から使う共通コンポーネント。
   open=false のときは何も描画しない。 */
function AboutAppDialog({ open, onClose }) {
  if (!open) return null;
  return (
    <div onClick={onClose} style={{ position: 'absolute', inset: 0, zIndex: 60, background: 'rgba(40,34,28,.32)', backdropFilter: 'blur(2px)', display: 'flex', alignItems: 'flex-end', animation: 'risefade .25s' }}>
      <div onClick={e => e.stopPropagation()} style={{ width: '100%', background: 'var(--paper)', borderRadius: '26px 26px 0 0', padding: '14px 22px 34px', boxShadow: '0 -10px 40px rgba(0,0,0,.18)', animation: 'floatup .3s ease', maxHeight: '78%', overflow: 'hidden', display: 'flex', flexDirection: 'column' }}>
        <div style={{ width: 40, height: 4, borderRadius: 9, background: 'var(--line-2)', margin: '0 auto 16px' }} />
        <div style={{ fontFamily: 'var(--font-serif)', fontSize: 20, color: 'var(--ink)', flexShrink: 0 }}>このアプリについて</div>
        <div style={{ fontSize: 12, color: 'var(--ink-faint)', marginTop: 3, marginBottom: 14, flexShrink: 0 }}>ハッカソン作品の注意事項・プライバシーの扱い</div>
        <div className="noscroll" style={{ overflowY: 'auto', flex: 1 }}>
          {LEGAL_SECTIONS.map(sec => (
            <div key={sec.title} style={{ marginBottom: 18 }}>
              <div style={{ display: 'flex', alignItems: 'center', gap: 7, marginBottom: 6 }}>
                <Icon name={sec.icon} size={15} style={{ color: 'var(--amethyst)' }} />
                <span style={{ fontSize: 13.5, fontWeight: 700, color: 'var(--ink)' }}>{sec.title}</span>
              </div>
              <p style={{ margin: 0, fontSize: 12.5, lineHeight: 1.85, color: 'var(--ink-soft)' }}>{sec.body}</p>
            </div>
          ))}
          <div style={{ fontSize: 11.5, color: 'var(--ink-faint)', lineHeight: 1.8, borderTop: '1px solid var(--line)', paddingTop: 14 }}>
            本アプリを使いはじめた時点で、上記に同意したものとみなします。<br />
            データの削除をご希望の場合は、制作者までご連絡ください。
          </div>
        </div>
        <div style={{ paddingTop: 14, flexShrink: 0 }}>
          <Btn variant="ghost" full size="md" onClick={onClose}>閉じる</Btn>
        </div>
      </div>
    </div>
  );
}
window.AboutAppDialog = AboutAppDialog;

/* ─────────── 日付ユーティリティ ─────────── */
const todayMid = () => { const d = new Date(); d.setHours(0, 0, 0, 0); return d; };
// "YYYY-MM-DD" → {y,m,d} / 失敗時 null
function parseISODate(s) {
  const m = /^(\d{4})-(\d{1,2})-(\d{1,2})/.exec(s || '');
  return m ? { y: +m[1], mo: +m[2], d: +m[3] } : null;
}
// 指定年月の events / since からカレンダーのマークを作る
function buildMarks(year, month, events, since) {
  const marks = {};
  (events || []).forEach(ev => {
    const p = parseISODate(ev.date);
    if (p && p.y === year && p.mo === month) marks[p.d] = { c: 'var(--partner)', title: ev.title || 'よてい' };
  });
  if (since) {
    const start = new Date(since.year, since.month - 1, since.day);
    const ds = Math.floor((todayMid() - start) / 86400000);
    // 直近の100日マイルストーン日 + 当年の周年日がこの月に入るならマーク
    const nextHundred = Math.ceil((Math.max(ds, 0) + 1) / 100) * 100;
    const mDate = new Date(start.getTime() + nextHundred * 86400000);
    if (mDate.getFullYear() === year && mDate.getMonth() + 1 === month) marks[mDate.getDate()] = { c: 'var(--gold)', title: `${nextHundred}日記念` };
    const annivThisYear = new Date(year, since.month - 1, since.day);
    if (annivThisYear.getMonth() + 1 === month) marks[since.day] = { c: 'var(--amethyst)', title: '記念日' };
  }
  return marks;
}

/* ─────────── shared month grid（実年月で描画）─────────── */
const WD = ['日', '月', '火', '水', '木', '金', '土'];
function MonthGrid({ year, month, selected, onSelect, marks = {}, today, compact = false }) {
  const now = new Date();
  const y = year || now.getFullYear();
  const mo = month || (now.getMonth() + 1);
  const days = new Date(y, mo, 0).getDate();
  const startDow = new Date(y, mo - 1, 1).getDay();
  const cells = [];
  for (let i = 0; i < startDow; i++) cells.push(null);
  for (let d = 1; d <= days; d++) cells.push(d);
  while (cells.length % 7) cells.push(null);
  // compact: ホームでカレンダーが場所を取りすぎないよう、セル・文字・マークを一回り小さく
  const dim = compact ? 25 : 30;
  const numFont = compact ? 13 : 15.5;
  const dotSize = compact ? 4 : 5;
  return (
    <div>
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(7,1fr)', marginBottom: compact ? 2 : 4 }}>
        {WD.map((w, i) => (
          <div key={w} style={{ textAlign: 'center', fontSize: compact ? 9.5 : 10.5, fontWeight: 700,
            color: i === 0 ? 'var(--me)' : i === 6 ? 'var(--partner)' : 'var(--ink-faint)', padding: compact ? '2px 0' : '4px 0' }}>{w}</div>
        ))}
      </div>
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(7,1fr)', gap: compact ? 1 : 2 }}>
        {cells.map((d, i) => {
          if (!d) return <div key={i} />;
          const dow = i % 7;
          const isToday = d === today;
          const isSel = d === selected;
          const mk = marks[d];
          return (
            <button key={i} onClick={() => onSelect && onSelect(d)} disabled={!onSelect} style={{
              height: compact ? dim + 8 : undefined, aspectRatio: compact ? undefined : '1 / 1',
              border: 'none', background: 'transparent', cursor: onSelect ? 'pointer' : 'default',
              display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', gap: compact ? 1 : 2,
              position: 'relative', padding: 0, borderRadius: 12,
            }}>
              <div style={{
                width: dim, height: dim, borderRadius: '50%', display: 'flex', alignItems: 'center', justifyContent: 'center',
                fontFamily: 'var(--font-serif)', fontSize: numFont,
                fontWeight: isSel || isToday ? 600 : 400,
                background: isSel ? 'var(--amethyst)' : isToday ? 'var(--surface-2)' : 'transparent',
                color: isSel ? '#fff' : isToday ? 'var(--ink)' : dow === 0 ? 'color-mix(in oklch, var(--me) 70%, var(--ink))' : dow === 6 ? 'color-mix(in oklch, var(--partner) 70%, var(--ink))' : 'var(--ink)',
                border: isToday && !isSel ? '1.5px solid var(--line-2)' : 'none',
                transition: 'all .15s',
              }}>{d}</div>
              <div style={{ height: dotSize, display: 'flex', gap: 2 }}>
                {mk && <span style={{ width: dotSize, height: dotSize, borderRadius: '50%', background: mk.c }} />}
              </div>
            </button>
          );
        })}
      </div>
    </div>
  );
}

/* ════════ HOME ════════ */
function HomeScreen() {
  const { go, t, live } = W.useApp();
  const isLive = !!(live.user && live.coupleId);
  const myName = live.userDoc?.name || ME_FALLBACK;
  const partnerName = live.partner?.name || PARTNER_FALLBACK;
  const events = (isLive && live.events) ? live.events.map(d => W.normalizeEvent(d, live.user.uid))
    .sort((a, b) => {
      const pa = parseISODate(a.raw?.date), pb = parseISODate(b.raw?.date);
      const ta = pa ? new Date(pa.y, pa.mo - 1, pa.d).getTime() : Infinity;
      const tb = pb ? new Date(pb.y, pb.mo - 1, pb.d).getTime() : Infinity;
      return ta - tb;
    }) : [];
  // 予定は昇順。ただし今日より前（過去）の予定は下部の折りたたみへ回す。
  const nowMid = todayMid().getTime();
  const eventTime = ev => { const p = parseISODate(ev.raw?.date); return p ? new Date(p.y, p.mo - 1, p.d).getTime() : Infinity; };
  const upcomingEvents = events.filter(ev => eventTime(ev) >= nowMid);
  const pastEvents = events.filter(ev => eventTime(ev) < nowMid);
  const unpaired = !!live.user && !live.coupleId;

  /* 記念日: live.since から計算（未設定なら null → 設定導線を出す）*/
  const since = live.since;
  const anniv = (() => {
    if (!since) return null;
    const start = new Date(since.year, since.month - 1, since.day);
    const daysSince = Math.floor((todayMid() - start) / 86400000);
    if (daysSince < 0) return null;
    const target = Math.ceil((daysSince + 1) / 100) * 100;
    const mDate = new Date(start.getTime() + target * 86400000);
    return {
      daysSince, target, daysToNext: target - daysSince,
      pct: Math.min(100, (daysSince / target) * 100),
      milestoneLabel: `${mDate.getMonth() + 1}月${mDate.getDate()}日`,
      milestoneISO: `${mDate.getFullYear()}-${String(mDate.getMonth() + 1).padStart(2, '0')}-${String(mDate.getDate()).padStart(2, '0')}`,
      sinceShort: `${since.year}.${String(since.month).padStart(2, '0')}.${String(since.day).padStart(2, '0')}`,
    };
  })();

  /* カレンダー: 実月から開始、前後ナビ */
  const now = new Date();
  const [calY, setCalY] = useStateM(now.getFullYear());
  const [calM, setCalM] = useStateM(now.getMonth() + 1);
  const shiftMonth = (delta) => {
    let m = calM + delta, y = calY;
    if (m < 1) { m = 12; y--; } else if (m > 12) { m = 1; y++; }
    setCalM(m); setCalY(y); setSelDay(null);
  };
  const calMarks = buildMarks(calY, calM, live.events, since);
  const calToday = (calY === now.getFullYear() && calM === now.getMonth() + 1) ? now.getDate() : null;

  /* カレンダーの予定がある日をタップ → 下部の該当日の予定カードへスクロール
     （1日に複数予定があり得るので、詳細を開かず一覧の該当位置へ寄せる）*/
  const cardRefs = useRefM({});
  cardRefs.current = {}; // 毎レンダーでクリア（ref callback が commit 時に再登録）
  const [selDay, setSelDay] = useStateM(null);
  const [pastOpen, setPastOpen] = useStateM(false); // 過去の予定の折りたたみ
  const pendingScroll = useRefM(null);              // 過去展開後にスクロールする対象 iso
  const pad2 = n => String(n).padStart(2, '0');
  const isoOf = (y, m, d) => `${y}-${pad2(m)}-${pad2(d)}`;
  // 該当カードへスムーススクロール＋一瞬ハイライト（リング＋淡い点滅）
  const scrollToCard = (iso) => {
    const node = cardRefs.current[iso];
    if (!node) return;
    node.scrollIntoView({ behavior: 'smooth', block: 'center' });
    const card = node.firstElementChild || node;
    if (card && card.animate) {
      const ac = getComputedStyle(document.documentElement).getPropertyValue('--amethyst').trim() || '#8E7DA6';
      const drop = '0 14px 30px -22px rgba(61,54,44,.5)';
      setTimeout(() => {
        card.animate([
          { boxShadow: `0 0 0 3px ${ac}, ${drop}`, offset: 0 },
          { boxShadow: `0 0 0 3px ${ac}, ${drop}`, offset: 0.55 },
          { boxShadow: `0 0 0 0 rgba(0,0,0,0), ${drop}`, offset: 1 },
        ], { duration: 1300, easing: 'ease-out' });
      }, 320); // スムーススクロールの完了を待ってから光らせる
    }
  };
  const onDayTap = (day) => {
    setSelDay(day);
    const iso = isoOf(calY, calM, day);
    const isPast = new Date(calY, calM - 1, day).getTime() < nowMid;
    // 過去の予定なら、まず折りたたみを開いてからスクロール（DOM反映を待つ）
    if (isPast && !pastOpen) { pendingScroll.current = iso; setPastOpen(true); }
    else scrollToCard(iso);
  };
  useEffM(() => {
    if (pastOpen && pendingScroll.current) {
      const iso = pendingScroll.current; pendingScroll.current = null;
      setTimeout(() => scrollToCard(iso), 60); // 展開描画後にスクロール
    }
  }, [pastOpen]);

  /* 「なんでも、相談」は上へスクロールして通り過ぎたら、画面下部に固定バーとして残す。
     まだ下にあって未到達のうちは出さない（＝Bodyの上端より上へ抜けたときだけ） */
  const bodyRef = useRefM(null);
  const chatEntryRef = useRefM(null);
  const [chatPinned, setChatPinned] = useStateM(false);
  useEffM(() => {
    const root = bodyRef.current, target = chatEntryRef.current;
    if (!root || !target || !window.IntersectionObserver) return;
    const io = new IntersectionObserver(([e]) => {
      const rb = e.rootBounds;
      setChatPinned(!e.isIntersecting && !!rb && e.boundingClientRect.bottom <= rb.top);
    }, { root, threshold: 0 });
    io.observe(target);
    return () => io.disconnect();
  }, []);
  /* チャットへの遷移: タップしたピルの矩形を渡して shared-element モーフさせる。
     ジェスチャ内で __prefocus → キーボードを先に呼び、フォーカスは遷移先の textarea が引き継ぐ。 */
  const openChat = (seed, el) => {
    let hero = null;
    if (el) {
      const r = el.getBoundingClientRect();
      hero = { left: r.left, top: r.top, width: r.width, height: r.height };
    }
    window.__prefocus && window.__prefocus();
    go('home-chat', { seed, hero, focus: true });
  };

  // 予定カード1枚（これから／過去 で共通利用。過去は compact で一回り小さく）
  const renderCard = (ev, compact) => {
    const p = parseISODate(ev.raw?.date);
    const iso = p ? isoOf(p.y, p.mo, p.d) : null;
    return (
      <div key={ev.id} ref={el => { if (el && iso && !cardRefs.current[iso]) cardRefs.current[iso] = el; }}>
        <W.Card pad={compact ? 11 : 14} onClick={() => go(ev.planStatus === 'ready' ? 'plan-reveal' : 'plan-pending', { ev })} style={{ cursor: 'pointer' }}>
          <div style={{ display: 'flex', gap: compact ? 11 : 13, alignItems: 'center' }}>
            <W.MotifMini kind={t.motif} progress={ev.progress} size={compact ? 42 : 52} />
            <div style={{ flex: 1, minWidth: 0 }}>
              <div style={{ display: 'flex', alignItems: 'center', gap: 7 }}>
                <span style={{ fontFamily: 'var(--font-serif)', fontSize: 12.5, color: 'var(--me)', fontWeight: 500 }}>{ev.date}（{ev.dow}）</span>
                {ev.planStatus !== 'ready' && (
                  <span style={{ display: 'inline-flex', alignItems: 'center', gap: 4, background: 'color-mix(in oklch, var(--amethyst) 12%, var(--paper))', border: '1px solid color-mix(in oklch, var(--amethyst) 24%, transparent)', borderRadius: 999, padding: '2px 8px', fontSize: 10.5, fontWeight: 700, color: 'color-mix(in oklch, var(--amethyst) 70%, var(--ink))' }}>
                    <span style={{ width: 5, height: 5, borderRadius: '50%', background: 'var(--amethyst)', animation: 'glowpulse 1.8s ease-in-out infinite' }} />
                    考え中
                  </span>
                )}
                <W.WeatherIcon dateISO={ev.raw?.date} area={ev.area} size={13} style={{ marginLeft: 'auto' }} />
              </div>
              <div style={{ fontWeight: 700, fontSize: compact ? 14.5 : 16, color: 'var(--ink)', marginTop: 1, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{ev.title}</div>
              <div style={{ display: 'flex', alignItems: 'center', gap: 4, fontSize: 11.5, color: 'var(--ink-soft)', marginTop: 1 }}>
                <Icon name="pin" size={12} /> {ev.area}
              </div>
            </div>
            <Icon name="chevR" size={16} style={{ color: 'var(--ink-faint)' }} />
          </div>
        </W.Card>
      </div>
    );
  };

  return (
    <div style={{ height: '100%', background: 'var(--bg)', display: 'flex', flexDirection: 'column', position: 'relative' }}>
      {/* slim header */}
      <div style={{ paddingTop: W.SAFE_TOP, paddingBottom: 6, paddingLeft: 20, paddingRight: 16,
        display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
        <div style={{ fontSize: 13.5, color: 'var(--ink-soft)', fontWeight: 600 }}>こんにちは、{myName}</div>
        <button onClick={() => go('settings')} style={{ display: 'flex', alignItems: 'center', gap: 6, background: 'var(--surface)', borderRadius: 999, padding: '5px 10px 5px 7px', border: '1px solid var(--line)', cursor: 'pointer' }}>
          <W.Charm size={22} linked={!unpaired} />
          <span style={{ fontSize: 11.5, fontWeight: 700, color: 'var(--ink-soft)' }}>{unpaired ? myName[0] : `${myName[0]}＆${partnerName[0]}`}</span>
        </button>
      </div>

      <W.Body nav pad={16} scrollRef={bodyRef}>
        {/* ⓪ unpaired banner */}
        {unpaired && (
          <button onClick={() => go('pairing')} style={{
            width: '100%', display: 'flex', alignItems: 'center', gap: 12, cursor: 'pointer', textAlign: 'left',
            background: 'color-mix(in oklch, var(--amethyst) 10%, var(--paper))',
            border: '1.5px solid color-mix(in oklch, var(--amethyst) 30%, transparent)',
            borderRadius: 18, padding: '14px 16px', marginTop: 6, marginBottom: 16,
          }}>
            <W.Charm size={30} linked={false} />
            <div style={{ flex: 1 }}>
              <div style={{ fontWeight: 700, fontSize: 14.5, color: 'var(--ink)', fontFamily: 'var(--font-ui)' }}>パートナーを招待しよう</div>
              <div style={{ fontSize: 12, color: 'var(--ink-soft)', marginTop: 1, fontFamily: 'var(--font-ui)' }}>ふたりが揃うと、Amuletが本領を発揮します</div>
            </div>
            <Icon name="chevR" size={16} style={{ color: 'var(--amethyst)' }} />
          </button>
        )}

        {/* ① anniversary counter（live.since 未設定なら設定導線）*/}
        {anniv ? (
        <button onClick={() => go('event-create', { initISO: anniv.milestoneISO })} style={{
          display: 'block', width: '100%', textAlign: 'left', cursor: 'pointer', padding: 0, border: 'none',
          borderRadius: 22, marginTop: 6, marginBottom: 16, position: 'relative', overflow: 'hidden',
          aspectRatio: '1308 / 533',
          background: 'url(/assets/topcard.png) center/cover no-repeat',
          boxShadow: '0 14px 30px -22px rgba(61,54,44,.5)',
        }}>
          {/* 左半分にテキスト（右側は背景画像の手のイラスト） */}
          <div style={{ position: 'absolute', inset: 0, padding: '15px 18px 14px', display: 'flex', flexDirection: 'column', width: '66%' }}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
              <Icon name="sparkle" size={13} style={{ color: 'color-mix(in oklch, var(--ink) 70%, var(--me))' }} />
              <span style={{ fontFamily: 'ui-monospace,monospace', fontSize: 9.5, letterSpacing: '.14em', fontWeight: 700, color: 'color-mix(in oklch, var(--ink) 62%, var(--me))' }}>NEXT ANNIVERSARY</span>
            </div>
            {/* 「あと N 日」— 数字は文字の形の白ハロー付きの可愛いフォント */}
            <div style={{ display: 'flex', alignItems: 'baseline', gap: 5, marginTop: 4 }}>
              <span style={{ fontSize: 14, color: 'var(--ink)', fontWeight: 700 }}>あと</span>
              <span style={{
                fontFamily: 'var(--font-ui)', fontWeight: 900, fontSize: 50, lineHeight: 0.95, color: 'var(--ink)',
                WebkitTextStroke: '6px #fff', paintOrder: 'stroke fill',
              }}>{anniv.daysToNext}</span>
              <span style={{ fontSize: 16, color: 'var(--ink)', fontWeight: 800, WebkitTextStroke: '3px #fff', paintOrder: 'stroke fill' }}>日</span>
            </div>
            <div style={{ fontSize: 12.5, color: 'var(--ink)', fontWeight: 700, marginTop: 1 }}>{anniv.target}日記念まで</div>
            <div style={{ marginTop: 'auto', display: 'flex', alignItems: 'baseline', gap: 7, fontSize: 11, color: 'color-mix(in oklch, var(--ink) 78%, transparent)' }}>
              <span>つきあって <b style={{ color: 'var(--ink)' }}>{anniv.daysSince}</b>日</span>
              <span style={{ opacity: .55 }}>·</span>
              <span>{anniv.sinceShort} 〜</span>
            </div>
          </div>
        </button>
        ) : (!unpaired && (
          <button onClick={() => go('settings')} style={{
            width: '100%', textAlign: 'left', cursor: 'pointer', marginTop: 6, marginBottom: 16,
            borderRadius: 24, padding: '20px 22px', border: '1px dashed color-mix(in oklch, var(--amethyst) 40%, transparent)',
            background: 'color-mix(in oklch, var(--amethyst) 7%, var(--paper))',
          }}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 9 }}>
              <Icon name="heart" size={18} style={{ color: 'var(--amethyst)' }} />
              <div style={{ flex: 1 }}>
                <div style={{ fontWeight: 700, fontSize: 14.5, color: 'var(--ink)' }}>付き合った日を登録しよう</div>
                <div style={{ fontSize: 12, color: 'var(--ink-soft)', marginTop: 1 }}>記念日までのカウントダウンが始まります</div>
              </div>
              <Icon name="chevR" size={16} style={{ color: 'var(--amethyst)' }} />
            </div>
          </button>
        ))}

        {/* ② shared month calendar（コンパクト表示） */}
        <W.Card pad={13} style={{ marginBottom: 16 }}>
          <div style={{ display: 'flex', alignItems: 'center', marginBottom: 6 }}>
            <button onClick={() => shiftMonth(-1)} style={{ width: 26, height: 26, borderRadius: 999, border: '1px solid var(--line-2)', background: 'var(--surface)', cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center', color: 'var(--ink-soft)' }}><Icon name="chevL" size={14} /></button>
            <div style={{ flex: 1, textAlign: 'center' }}>
              <div style={{ fontFamily: 'var(--font-serif)', fontSize: 17, color: 'var(--ink)', fontWeight: 600 }}>{calM}月<span style={{ fontSize: 11, color: 'var(--ink-faint)', marginLeft: 6 }}>{calY}</span></div>
            </div>
            <button onClick={() => shiftMonth(1)} style={{ width: 26, height: 26, borderRadius: 999, border: '1px solid var(--line-2)', background: 'var(--surface)', cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center', color: 'var(--ink-soft)' }}><Icon name="chevR" size={14} /></button>
          </div>
          <MonthGrid year={calY} month={calM} marks={calMarks} today={calToday} selected={selDay} onSelect={onDayTap} compact />
          <div style={{ display: 'flex', gap: 12, justifyContent: 'center', marginTop: 8, paddingTop: 8, borderTop: '1px solid var(--line)' }}>
            {[['記念日', 'var(--amethyst)'], ['1000日', 'var(--gold)'], ['よてい', 'var(--partner)']].map(([l, col]) => (
              <div key={l} style={{ display: 'flex', alignItems: 'center', gap: 5, fontSize: 10.5, fontWeight: 600, color: 'var(--ink-soft)' }}>
                <span style={{ width: 6, height: 6, borderRadius: '50%', background: col }} />{l}
              </div>
            ))}
          </div>
        </W.Card>

        {/* ③ chat entry */}
        <div ref={chatEntryRef} style={{ marginBottom: 22 }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 11 }}>
            <W.AiAvatar size={26} />
            <div style={{ fontFamily: 'var(--font-serif)', fontSize: 18, color: 'var(--ink)' }}>なんでも、相談</div>
          </div>
          <button onClick={e => openChat(undefined, e.currentTarget)} style={{
            width: '100%', display: 'flex', alignItems: 'center', gap: 12, cursor: 'pointer', textAlign: 'left',
            background: 'var(--surface)', border: '1.5px solid var(--line-2)', borderRadius: 18, padding: '14px 14px 14px 18px',
            boxShadow: '0 10px 26px -20px rgba(61,54,44,.5)',
          }}>
            <span style={{ flex: 1, fontFamily: 'var(--font-ui)', fontSize: 14.5, color: 'var(--ink-faint)' }}>悩み、デートの相談、アプリへの不満…なんでも</span>
            <span style={{ width: 40, height: 40, borderRadius: '50%', background: 'var(--amethyst)', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}><Icon name="send" size={19} stroke="#fff" /></span>
          </button>
          <div className="noscroll" style={{ display: 'flex', gap: 8, overflowX: 'auto', marginTop: 11 }}>
            {HOME_SUGGEST.map(s => (
              <button key={s} onClick={e => openChat(s, e.currentTarget)} style={{
                flexShrink: 0, padding: '8px 14px', borderRadius: 999, cursor: 'pointer', whiteSpace: 'nowrap',
                border: '1px solid var(--line-2)', background: 'var(--paper)',
                fontFamily: 'var(--font-ui)', fontSize: 12.5, fontWeight: 600, color: 'var(--ink-soft)',
              }}>{s}</button>
            ))}
          </div>
        </div>

        {/* ④ schedule cards */}
        <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 12 }}>
          <W.Eyebrow>よていカード · {upcomingEvents.length}</W.Eyebrow>
        </div>
        {isLive && events.length === 0 && (
          <div style={{ textAlign: 'center', padding: '26px 18px', background: 'var(--surface)', borderRadius: 18, border: '1px solid var(--line)', marginBottom: 2 }}>
            <div style={{ marginBottom: 8, color: 'var(--ink-faint)' }}><Icon name="cal" size={30} /></div>
            <div style={{ fontWeight: 700, fontSize: 15, color: 'var(--ink)' }}>まだ予定がありません</div>
            <div style={{ fontSize: 12.5, color: 'var(--ink-soft)', marginTop: 4, lineHeight: 1.6 }}>最初のデートをつくって、<br />ふたりの本音を集め始めましょう</div>
          </div>
        )}
        <div style={{ display: 'flex', flexDirection: 'column', gap: 11 }}>
          {upcomingEvents.map(ev => renderCard(ev))}
        </div>
        {isLive && events.length > 0 && upcomingEvents.length === 0 && (
          <div style={{ textAlign: 'center', padding: '18px 12px', color: 'var(--ink-soft)', fontSize: 13 }}>これからの予定はまだありません</div>
        )}

        {/* 過去の予定（折りたたみ）— 開いた中身が「トグルの中」に見えるよう、
             ヘッダと一覧をひとつの枠で包む。中身は一回り小さいカードで階層をつける。 */}
        {pastEvents.length > 0 && (
          <div style={{
            marginTop: 11, borderRadius: 16, overflow: 'hidden',
            border: '1px solid var(--line)',
            background: pastOpen ? 'color-mix(in srgb, var(--ink) 3%, var(--surface))' : 'var(--surface)',
            transition: 'background .2s',
          }}>
            <button onClick={() => setPastOpen(o => !o)} style={{
              width: '100%', display: 'flex', alignItems: 'center', gap: 9, cursor: 'pointer', textAlign: 'left',
              padding: '12px 14px', border: 'none', background: 'var(--surface)',
              borderBottom: pastOpen ? '1px solid var(--line)' : 'none',
              fontFamily: 'var(--font-ui)', fontSize: 13.5, fontWeight: 700, color: 'var(--ink-soft)',
            }}>
              <Icon name="clock" size={16} style={{ color: 'var(--ink-faint)' }} />
              <span style={{ flex: 1 }}>過去の予定 · {pastEvents.length}</span>
              <Icon name="chevD" size={16} style={{ color: 'var(--ink-faint)', transform: pastOpen ? 'rotate(180deg)' : 'none', transition: 'transform .2s' }} />
            </button>
            {pastOpen && (
              <div style={{ display: 'flex', flexDirection: 'column', gap: 9, padding: '11px 11px 13px', opacity: 0.82, animation: 'floatup .22s ease both' }}>
                {pastEvents.map(ev => renderCard(ev, true))}
              </div>
            )}
          </div>
        )}

        {/* add */}
        <button onClick={() => go('event-create')} style={{
          width: '100%', marginTop: 13, padding: '16px', borderRadius: 18, cursor: 'pointer',
          border: '1.5px dashed color-mix(in oklch, var(--amethyst) 45%, var(--line-2))',
          background: 'color-mix(in oklch, var(--amethyst) 7%, var(--paper))',
          display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 9,
          fontFamily: 'var(--font-ui)', fontWeight: 700, fontSize: 15, color: 'var(--amethyst)',
        }}>
          <Icon name="plus" size={19} /> 新しいデートをつくる
        </button>
        {chatPinned && <div style={{ height: 46 }} /> /* 固定バーが最後の要素に被らないように */}
      </W.Body>

      {/* 「なんでも、相談」固定バー（本体を通り過ぎたあいだだけ） */}
      {chatPinned && (
        <button onClick={e => openChat(undefined, e.currentTarget)} style={{
          position: 'absolute', left: 14, right: 14, bottom: W.NAV_H + 6, zIndex: 35,
          display: 'flex', alignItems: 'center', gap: 10, cursor: 'pointer', textAlign: 'left',
          background: 'color-mix(in srgb, var(--surface) 92%, transparent)',
          backdropFilter: 'blur(12px)', WebkitBackdropFilter: 'blur(12px)',
          border: '1.5px solid var(--line-2)', borderRadius: 999, padding: '8px 8px 8px 16px',
          boxShadow: '0 16px 32px -16px rgba(61,54,44,.6)', animation: 'floatup .22s ease both',
        }}>
          <Icon name="sparkle" size={16} style={{ color: 'var(--amethyst)', flexShrink: 0 }} />
          <span style={{ flex: 1, minWidth: 0, fontFamily: 'var(--font-ui)', fontSize: 13.5, fontWeight: 600, color: 'var(--ink-soft)', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>なんでも、相談</span>
          <span style={{ width: 34, height: 34, borderRadius: '50%', background: 'var(--amethyst)', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>
            <Icon name="send" size={16} stroke="#fff" />
          </span>
        </button>
      )}
      <W.BottomNav active="home" go={go} />
    </div>
  );
}

/* ─────────── drag-to-select time band ─────────── */
const H0 = 6, H1 = 24;
function fmtH(h) { const hh = Math.floor(h); const mm = Math.round((h - hh) * 60); return `${String(hh).padStart(2, '0')}:${mm === 30 ? '30' : '00'}`; }
function isNight(h) { return h < 7 || h >= 18; }

function TimeBand({ value, onChange }) {
  const [range, setRange] = useStateM(value || { s: 13, e: 19 });
  const trackRef = useRefM(null);
  const drag = useRefM(null);
  const snap = useRefM(null);
  const pct = h => ((h - H0) / (H1 - H0)) * 100;

  // 範囲が変わったら親に通知（プリフィル値で初期化＋ドラッグ変更を反映）
  useEffM(() => { if (onChange) onChange(range); }, [range.s, range.e]);

  useEffM(() => {
    const hourAt = clientX => {
      const r = trackRef.current.getBoundingClientRect();
      let h = H0 + ((clientX - r.left) / r.width) * (H1 - H0);
      h = Math.round(h * 2) / 2;
      return Math.max(H0, Math.min(H1, h));
    };
    const move = e => {
      if (!drag.current) return;
      e.preventDefault();
      if (drag.current === 'band') {
        const r = trackRef.current.getBoundingClientRect();
        const dh = Math.round(((e.clientX - snap.current.x) / r.width) * (H1 - H0) * 2) / 2;
        const dur = snap.current.e - snap.current.s;
        let ns = snap.current.s + dh, ne = snap.current.e + dh;
        if (ns < H0) { ns = H0; ne = H0 + dur; }
        if (ne > H1) { ne = H1; ns = H1 - dur; }
        setRange({ s: ns, e: ne });
      } else {
        const h = hourAt(e.clientX);
        setRange(R => drag.current === 's' ? { s: Math.min(h, R.e - 1), e: R.e } : { s: R.s, e: Math.max(h, R.s + 1) });
      }
    };
    const up = () => { drag.current = null; };
    window.addEventListener('pointermove', move, { passive: false });
    window.addEventListener('pointerup', up);
    return () => { window.removeEventListener('pointermove', move); window.removeEventListener('pointerup', up); };
  }, []);

  const startDrag = (mode, e) => { e.preventDefault(); drag.current = mode; snap.current = { x: e.clientX, s: range.s, e: range.e }; };
  const ticks = [6, 9, 12, 15, 18, 21, 24];
  const handle = (which, h) => {
    const night = isNight(h);
    return (
      <div onPointerDown={e => startDrag(which, e)} style={{
        position: 'absolute', left: `${pct(h)}%`, top: '50%', transform: 'translate(-50%,-50%)',
        width: 44, height: 44, borderRadius: '50%', cursor: 'grab', touchAction: 'none', zIndex: 3,
        background: '#fff', border: `2.5px solid ${night ? 'var(--amethyst)' : 'var(--gold)'}`,
        boxShadow: '0 6px 16px -6px rgba(61,54,44,.6)', display: 'flex', alignItems: 'center', justifyContent: 'center',
      }}>
        <Icon name={night ? 'moon' : 'sun'} size={22} stroke={night ? 'var(--amethyst)' : 'var(--gold)'} fill={night ? 'var(--amethyst)' : 'none'} />
        <div style={{ position: 'absolute', top: -30, left: '50%', transform: 'translateX(-50%)', background: 'var(--ink)', color: 'var(--paper)', fontSize: 12, fontWeight: 700, padding: '3px 9px', borderRadius: 8, whiteSpace: 'nowrap', fontFamily: 'var(--font-serif)' }}>{fmtH(h)}</div>
      </div>
    );
  };

  const dur = range.e - range.s;
  return (
    <div>
      <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', marginBottom: 12 }}>
        <div style={{ fontSize: 12.5, fontWeight: 700, color: 'var(--ink-soft)' }}>時間帯</div>
        <div style={{ display: 'flex', alignItems: 'baseline', gap: 8 }}>
          <span style={{ fontFamily: 'var(--font-serif)', fontSize: 19, color: 'var(--ink)', fontWeight: 600 }}>{fmtH(range.s)} – {fmtH(range.e)}</span>
          <span style={{ fontSize: 12, color: 'var(--ink-faint)' }}>約{Math.round(dur)}時間</span>
        </div>
      </div>
      {/* track */}
      <div ref={trackRef} style={{
        position: 'relative', height: 60, borderRadius: 16, marginTop: 26, touchAction: 'none',
        background: 'linear-gradient(90deg, #f3d3ad 0%, #ecd6ac 10%, #cfe1ea 36%, #bcd3e8 52%, #d7c3dd 70%, #aa98bf 84%, #534c69 100%)',
        boxShadow: 'inset 0 1px 4px rgba(61,54,44,.25)', overflow: 'visible',
      }}>
        {/* dim outside selection */}
        <div style={{ position: 'absolute', inset: 0, borderRadius: 16, background: `linear-gradient(90deg, rgba(247,241,231,.62) ${pct(range.s)}%, transparent ${pct(range.s)}%, transparent ${pct(range.e)}%, rgba(247,241,231,.62) ${pct(range.e)}%)` }} />
        {/* selection band */}
        <div onPointerDown={e => startDrag('band', e)} style={{
          position: 'absolute', top: 0, bottom: 0, left: `${pct(range.s)}%`, width: `${pct(range.e) - pct(range.s)}%`,
          cursor: 'grab', touchAction: 'none', borderRadius: 4, boxShadow: 'inset 0 0 0 2.5px rgba(255,255,255,.9)',
        }} />
        {handle('s', range.s)}
        {handle('e', range.e)}
      </div>
      {/* ticks */}
      <div style={{ position: 'relative', height: 16, marginTop: 6 }}>
        {ticks.map(tk => (
          <span key={tk} style={{ position: 'absolute', left: `${pct(tk)}%`, transform: 'translateX(-50%)', fontSize: 10.5, color: 'var(--ink-faint)', fontFamily: 'ui-monospace,monospace' }}>{tk}</span>
        ))}
      </div>
      <div style={{ display: 'flex', alignItems: 'center', gap: 6, marginTop: 6, fontSize: 11.5, color: 'var(--ink-faint)' }}>
        <Icon name="sun" size={13} style={{ color: 'var(--gold)' }} /> 日中
        <Icon name="moon" size={13} style={{ color: 'var(--amethyst)', marginLeft: 8 }} fill="var(--amethyst)" /> 夜
        <span style={{ marginLeft: 'auto' }}>ハンドルをドラッグして範囲を選択</span>
      </div>
    </div>
  );
}

/* ════════ EVENT CREATE ════════ */
// 時間ヘルパ: "13:30"→13.5 / 13.5→"13:30"（TimeBand は 0.5 刻み）
const parseHM = s => { const [H, M] = String(s).split(':').map(Number); return (H || 0) + (M >= 30 ? 0.5 : 0); };
const hhmm = h => `${String(Math.floor(h)).padStart(2, '0')}:${(h % 1) ? '30' : '00'}`;
const parseTimeRange = tr => (Array.isArray(tr) && tr.length === 2) ? { s: parseHM(tr[0]), e: parseHM(tr[1]) } : null;

function EventCreateScreen({ params }) {
  const { go, back, live, toast } = W.useApp();
  // initISO/initTitle/initArea/initTimeRange: 記念日タップや「デート作成サジェスト」から事前入力で開かれる
  const now = new Date();
  const init = (() => {
    const p = params?.initISO && parseISODate(params.initISO);
    return p ? { y: p.y, mo: p.mo, d: p.d } : { y: now.getFullYear(), mo: now.getMonth() + 1, d: now.getDate() };
  })();
  const [calY, setCalY] = useStateM(init.y);
  const [calM, setCalM] = useStateM(init.mo);
  const [selDay, setSelDay] = useStateM(init.d);
  const [title, setTitle] = useStateM(params?.initTitle || '');
  const [area, setArea] = useStateM(params?.initArea || '渋谷あたり');
  const [timeRange, setTimeRange] = useStateM(parseTimeRange(params?.initTimeRange) || { s: 13, e: 19 });
  const [busy, setBusy] = useStateM(false);
  const shiftMonth = (delta) => {
    let m = calM + delta, y = calY;
    if (m < 1) { m = 12; y--; } else if (m > 12) { m = 1; y++; }
    setCalM(m); setCalY(y);
    const maxD = new Date(y, m, 0).getDate();
    if (selDay > maxD) setSelDay(maxD);
  };
  const calToday = (calY === now.getFullYear() && calM === now.getMonth() + 1) ? now.getDate() : null;

  const create = async () => {
    if (!live.coupleId) { toast('ペアリングが必要です'); return; }
    const iso = `${calY}-${String(calM).padStart(2, '0')}-${String(selDay).padStart(2, '0')}`;
    const dow = WD[new Date(calY, calM - 1, selDay).getDay()];
    const dateLabel = `${calM}月${selDay}日`;
    setBusy(true);
    try {
      const evData = {
        title: title.trim() || 'ただの週末',
        date: iso, dateLabel, dow,
        area: area.trim() || '都内',
        timeRange: [hhmm(timeRange.s), hhmm(timeRange.e)],
      };
      // ホームチャットからの事前入力に要約があれば、秘密チャットへの引き継ぎ用に一緒に保存する。
      // 末尾の句読点は正規化しておく（プラン相談画面のイントロ文に埋め込むため。AIが句点付きで
      // 返しても「〜。とのことだったね。」のように文が二重に終止しないようにする保険）。
      if (params?.initSummary) {
        const cleanSummary = params.initSummary.trim().replace(/[。.!！?？]+$/, '');
        if (cleanSummary) evData.homeChatSummary = cleanSummary;
      }
      const id = await window.Amulet.createEvent(live.coupleId, evData);
      // raw に ISO/timeRange を載せておくと、plan-pending 側で即座に編集・時間表示ができる
      // 作成済みなので、戻ってこの入力フォームに帰らせない（履歴を置き換える）
      go('plan-pending', { ev: { id, live: true, date: dateLabel, dow, title: evData.title, area: evData.area, progress: 0.04, weather: 'sun', planStatus: 'none', raw: { id, ...evData } }, fresh: true }, { replace: true });
    } catch (e) {
      console.error(e);
      toast(window.Amulet.friendlyError(e));
    } finally { setBusy(false); }
  };
  return (
    <div style={{ height: '100%', background: 'var(--bg)', display: 'flex', flexDirection: 'column' }}>
      <W.TopBar title="新しいデート" onBack={back} />
      <W.Body>
        <p style={{ color: 'var(--ink-soft)', fontSize: 14, lineHeight: 1.7, margin: '4px 0 20px' }}>
          大枠だけ、ざっくり決めましょう。<br />細かいことは、これから少しずつ。
        </p>

        {/* date — calendar */}
        <W.Card pad={16} style={{ marginBottom: 20 }}>
          <div style={{ display: 'flex', alignItems: 'center', marginBottom: 10 }}>
            <button onClick={() => shiftMonth(-1)} style={{ width: 28, height: 28, borderRadius: 999, border: '1px solid var(--line-2)', background: 'var(--surface)', cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center', color: 'var(--ink-soft)' }}><Icon name="chevL" size={15} /></button>
            <div style={{ flex: 1, textAlign: 'center', fontFamily: 'var(--font-serif)', fontSize: 18, color: 'var(--ink)', fontWeight: 600 }}>{calM}月 {calY}</div>
            <button onClick={() => shiftMonth(1)} style={{ width: 28, height: 28, borderRadius: 999, border: '1px solid var(--line-2)', background: 'var(--surface)', cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center', color: 'var(--ink-soft)' }}><Icon name="chevR" size={15} /></button>
          </div>
          <MonthGrid year={calY} month={calM} selected={selDay} onSelect={setSelDay} today={calToday} />
        </W.Card>

        {/* time band */}
        <W.Card pad={18} style={{ marginBottom: 20 }}>
          <TimeBand value={timeRange} onChange={setTimeRange} />
        </W.Card>

        <div style={{ marginBottom: 16 }}>
          <W.Field label="どのあたり？" icon="pin" placeholder="「渋谷あたり」「都内」くらいでOK" value={area} onChange={setArea} />
        </div>
        <div style={{ marginBottom: 8 }}>
          <W.Field label="タイトル（任意）" icon="edit" placeholder="記念日 / ただの週末 …" value={title} onChange={setTitle} />
        </div>

        <div style={{ marginTop: 26 }}>
          <Btn variant="amethyst" size="lg" full icon="arrow" disabled={busy} onClick={create}>
            {busy ? 'つくっています…' : 'つくる'}
          </Btn>
        </div>
      </W.Body>
    </div>
  );
}

/* ─────────── 記念日マイルストーン計算 ─────────── */
function computeMilestones(since) {
  const DOW = ['日', '月', '火', '水', '木', '金', '土'];
  const start = new Date(since.year, since.month - 1, since.day);
  const today = new Date(); today.setHours(0, 0, 0, 0);
  const daysSince = Math.floor((today - start) / 86400000);
  if (daysSince < 0) return [];

  const all = [];
  let d = Math.ceil((daysSince + 1) / 100) * 100;
  for (let i = 0; i < 10; i++, d += 100) {
    const date = new Date(start.getTime() + d * 86400000);
    all.push({ date, label: `${d}日記念` });
  }
  for (let yr = 1; yr <= 8; yr++) {
    const date = new Date(since.year + yr, since.month - 1, since.day);
    if (date > today) all.push({ date, label: `${yr}周年記念` });
  }
  return all
    .filter(m => m.date > today)
    .sort((a, b) => a.date - b.date)
    .slice(0, 8)
    .map(m => {
      const daysLeft = Math.floor((m.date - today) / 86400000);
      const dt = m.date;
      return {
        label: m.label,
        dateStr: `${dt.getFullYear()}年${dt.getMonth() + 1}月${dt.getDate()}日（${DOW[dt.getDay()]}）`,
        daysLeft,
      };
    });
}

/* ════════ SETTINGS ════════ */
const DEFAULT_SINCE = { year: new Date().getFullYear(), month: 1, day: 1 };
function SettingsScreen() {
  const { go, live, toast, theme, setTheme, themes } = W.useApp();
  const myName = live.userDoc?.name || ME_FALLBACK;
  const myEmail = live.userDoc?.email || '';
  const partnerName = live.partner?.name || PARTNER_FALLBACK;
  const logout = async () => {
    try { await window.Amulet.signOut(); } catch (e) { console.error(e); }
    location.href = location.origin + location.pathname; // 状態を完全リセット
  };
  const [datePicker, setDatePicker] = useStateM(false);
  const [milestoneOpen, setMilestoneOpen] = useStateM(false);
  const [legalOpen, setLegalOpen] = useStateM(false);

  // 最寄駅（プロフィール）: 真実は Firestore（live.userDoc）。保存すると listener で即反映
  const myStation = live.userDoc?.nearestStation || '';
  const [stationOpen, setStationOpen] = useStateM(false);
  const [tmpStation, setTmpStation] = useStateM(myStation);
  const [stationBusy, setStationBusy] = useStateM(false);
  const saveStation = async () => {
    setStationBusy(true);
    try {
      await window.Amulet.saveProfile({ nearestStation: tmpStation.trim().slice(0, 30) });
      setStationOpen(false);
    } catch (e) { console.error(e); toast(window.Amulet.friendlyError(e)); }
    finally { setStationBusy(false); }
  };
  const sinceDate = live.since || null; // 真実は Firestore（live）。保存すると listener で即反映
  const [tmpDate, setTmpDate] = useStateM(sinceDate || DEFAULT_SINCE);
  const saveSince = async () => {
    if (!live.coupleId) { toast('ペアリングが必要です'); setDatePicker(false); return; }
    setDatePicker(false);
    try { await window.Amulet.setAnniversary(live.coupleId, { ...tmpDate }); }
    catch (e) { console.error(e); toast(window.Amulet.friendlyError(e)); }
  };

  const sinceLabelFmt = d => (d ? `${d.year}年${d.month}月${d.day}日` : '未設定');
  const milestones = sinceDate ? computeMilestones(sinceDate) : [];
  const daysSince = sinceDate ? Math.floor((new Date() - new Date(sinceDate.year, sinceDate.month - 1, sinceDate.day)) / 86400000) : null;
  const nextMilestone = milestones[0];

  const Row = ({ icon, label, detail, danger, onClick, last, toggleVal, onToggle }) => (
    <div onClick={onClick} style={{
      display: 'flex', alignItems: 'center', gap: 13, padding: '15px 16px', cursor: onClick ? 'pointer' : 'default',
      borderTop: last ? '1px solid var(--line)' : 'none',
    }}>
      <div style={{ width: 32, height: 32, borderRadius: 9, background: danger ? 'color-mix(in oklch, var(--me) 16%, var(--paper))' : 'var(--surface-2)',
        display: 'flex', alignItems: 'center', justifyContent: 'center', color: danger ? 'var(--me)' : 'var(--ink-soft)', flexShrink: 0 }}>
        <Icon name={icon} size={18} />
      </div>
      <span style={{ flex: 1, fontSize: 15, fontWeight: 600, color: danger ? 'var(--me)' : 'var(--ink)' }}>{label}</span>
      {detail && <span style={{ fontSize: 13, color: 'var(--ink-faint)' }}>{detail}</span>}
      {onToggle ? (
        <button onClick={(e) => { e.stopPropagation(); onToggle(); }} style={{
          width: 46, height: 28, borderRadius: 999, border: 'none', cursor: 'pointer', position: 'relative',
          background: toggleVal ? 'var(--partner)' : 'var(--line-2)', transition: 'background .2s', flexShrink: 0,
        }}>
          <span style={{ position: 'absolute', top: 3, left: toggleVal ? 21 : 3, width: 22, height: 22, borderRadius: '50%', background: '#fff', transition: 'left .2s', boxShadow: '0 1px 3px rgba(0,0,0,.2)' }} />
        </button>
      ) : onClick && <Icon name="chevR" size={16} style={{ color: 'var(--ink-faint)' }} />}
    </div>
  );
  const Group = ({ header, children }) => (
    <div style={{ marginBottom: 22 }}>
      <div style={{ marginBottom: 9 }}><W.Eyebrow>{header}</W.Eyebrow></div>
      <div style={{ background: 'var(--surface)', borderRadius: 18, overflow: 'hidden', border: '1px solid var(--line)' }}>{children}</div>
    </div>
  );

  const selStyle = { flex: 1, padding: '11px 10px', borderRadius: 10, border: '1px solid var(--line-2)', background: 'var(--surface-2)', fontFamily: 'var(--font-ui)', fontSize: 15, color: 'var(--ink)', outline: 'none' };

  return (
    <div style={{ height: '100%', background: 'var(--bg)', display: 'flex', flexDirection: 'column', position: 'relative' }}>
      <W.TopBar title="設定" />
      <W.Body nav>
        {/* profile */}
        <div style={{ display: 'flex', alignItems: 'center', gap: 15, padding: '6px 4px 20px' }}>
          <W.Avatar name={myName[0]} color="var(--me)" size={62} />
          <div style={{ flex: 1 }}>
            <div style={{ fontFamily: 'var(--font-serif)', fontSize: 22, color: 'var(--ink)' }}>{myName}</div>
            <div style={{ fontSize: 13, color: 'var(--ink-faint)' }}>{myEmail}</div>
          </div>
          <Btn variant="soft" size="sm" icon="edit" onClick={() => go('onboarding')}>編集</Btn>
        </div>

        <Group header="PROFILE">
          <Row icon="pin" label="最寄駅" detail={myStation || '未設定'}
            onClick={() => { setTmpStation(myStation); setStationOpen(true); }} last />
        </Group>

        <Group header="PARTNER">
          <div style={{ display: 'flex', alignItems: 'center', gap: 13, padding: '15px 16px' }}>
            <W.Avatar name={partnerName[0]} color="var(--partner)" size={40} />
            <div style={{ flex: 1 }}>
              <div style={{ fontWeight: 700, fontSize: 15, color: 'var(--ink)' }}>{partnerName}</div>
              <div style={{ fontSize: 12, color: 'var(--partner)', fontWeight: 600 }}>ペアリング済み{daysSince != null ? ` · ${daysSince}日` : ''}</div>
            </div>
            <W.Charm size={28} />
          </div>
          <Row icon="link" label="ペアリングを解除" last />
        </Group>

        {/* ふたりの記念日 */}
        <Group header="ふたりの記念日">
          <Row icon="heart" label="付き合った日" detail={sinceLabelFmt(sinceDate)}
            onClick={() => { setTmpDate(sinceDate ? { ...sinceDate } : DEFAULT_SINCE); setDatePicker(true); }} />
          <Row icon="sparkle" label="次の記念日"
            detail={nextMilestone ? `${nextMilestone.label} · あと${nextMilestone.daysLeft}日` : '—'}
            onClick={() => setMilestoneOpen(true)} last />
        </Group>

        <Group header="みため">
          <div style={{ padding: 12, display: 'flex', flexDirection: 'column', gap: 10 }}>
            {(themes || []).map(th => {
              const on = th.id === theme;
              return (
                <button key={th.id} onClick={() => setTheme(th.id)} style={{
                  display: 'flex', alignItems: 'center', gap: 13, width: '100%', textAlign: 'left', cursor: 'pointer',
                  padding: '11px 12px', borderRadius: 14, transition: 'border-color .15s, background .15s',
                  border: on ? '1.5px solid var(--amethyst)' : '1px solid var(--line-2)',
                  background: on ? 'color-mix(in oklch, var(--amethyst) 8%, var(--surface))' : 'var(--surface)',
                }}>
                  <div style={{ display: 'flex', flexShrink: 0, borderRadius: 9, overflow: 'hidden', border: '1px solid var(--line)' }}>
                    {th.swatch.map((c, i) => (<span key={i} style={{ width: 16, height: 34, background: c }} />))}
                  </div>
                  <div style={{ flex: 1, minWidth: 0 }}>
                    <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
                      <span style={{ fontWeight: 700, fontSize: 14.5, color: 'var(--ink)' }}>{th.label}</span>
                      {th.recommended && (
                        <span style={{ fontSize: 10, fontWeight: 700, color: 'var(--amethyst)', background: 'color-mix(in oklch, var(--amethyst) 14%, var(--paper))', borderRadius: 999, padding: '1px 7px' }}>おすすめ</span>
                      )}
                    </div>
                    <div style={{ fontSize: 11.5, color: 'var(--ink-soft)', marginTop: 2 }}>{th.desc}</div>
                  </div>
                  <div style={{ width: 22, height: 22, borderRadius: '50%', flexShrink: 0, display: 'flex', alignItems: 'center', justifyContent: 'center',
                    border: on ? 'none' : '1.5px solid var(--line-2)', background: on ? 'var(--amethyst)' : 'transparent' }}>
                    {on && <Icon name="check" size={13} stroke="#fff" sw={2.5} />}
                  </div>
                </button>
              );
            })}
          </div>
        </Group>

        <Group header="ACCOUNT">
          <Row icon="note" label="このアプリについて" detail="ハッカソン作品" onClick={() => setLegalOpen(true)} last />
          <Row icon="back" label="ログアウト" danger onClick={logout} last />
        </Group>

        <div style={{ textAlign: 'center', color: 'var(--ink-faint)', fontSize: 11.5, marginTop: 6 }} className="wm">amulet · v1.0</div>
      </W.Body>
      <W.BottomNav active="settings" go={go} />

      {/* ── 最寄駅 編集 overlay ── */}
      {stationOpen && (
        <div onClick={() => setStationOpen(false)} style={{ position: 'absolute', inset: 0, zIndex: 60, background: 'rgba(40,34,28,.32)', backdropFilter: 'blur(2px)', display: 'flex', alignItems: 'flex-end', animation: 'risefade .25s' }}>
          <div onClick={e => e.stopPropagation()} style={{ width: '100%', background: 'var(--paper)', borderRadius: '26px 26px 0 0', padding: '14px 22px 40px', boxShadow: '0 -10px 40px rgba(0,0,0,.18)', animation: 'floatup .3s ease' }}>
            <div style={{ width: 40, height: 4, borderRadius: 9, background: 'var(--line-2)', margin: '0 auto 16px' }} />
            <div style={{ fontFamily: 'var(--font-serif)', fontSize: 20, color: 'var(--ink)', marginBottom: 8 }}>最寄駅を設定</div>
            <p style={{ fontSize: 12.5, color: 'var(--ink-soft)', lineHeight: 1.7, margin: '0 0 18px' }}>
              プラン作成のとき、出発点や待ち合わせ場所の参考にします。<br />ふだん使う駅をひとつ入れてください。
            </p>
            <input value={tmpStation} onChange={e => setTmpStation(e.target.value)} placeholder="例: 渋谷駅"
              onKeyDown={e => e.key === 'Enter' && !stationBusy && saveStation()}
              style={{ width: '100%', padding: '13px 14px', borderRadius: 12, border: '1px solid var(--line-2)', background: 'var(--surface-2)', fontFamily: 'var(--font-ui)', fontSize: 16, color: 'var(--ink)', outline: 'none', marginBottom: 22, boxSizing: 'border-box' }} />
            <div style={{ display: 'flex', gap: 10 }}>
              <Btn variant="ghost" full size="md" onClick={() => setStationOpen(false)}>キャンセル</Btn>
              <Btn variant="amethyst" full size="md" disabled={stationBusy} onClick={saveStation}>{stationBusy ? '保存中…' : '保存'}</Btn>
            </div>
          </div>
        </div>
      )}

      {/* ── 付き合った日 date picker overlay ── */}
      {datePicker && (
        <div onClick={() => setDatePicker(false)} style={{ position: 'absolute', inset: 0, zIndex: 60, background: 'rgba(40,34,28,.32)', backdropFilter: 'blur(2px)', display: 'flex', alignItems: 'flex-end', animation: 'risefade .25s' }}>
          <div onClick={e => e.stopPropagation()} style={{ width: '100%', background: 'var(--paper)', borderRadius: '26px 26px 0 0', padding: '14px 22px 40px', boxShadow: '0 -10px 40px rgba(0,0,0,.18)', animation: 'floatup .3s ease' }}>
            <div style={{ width: 40, height: 4, borderRadius: 9, background: 'var(--line-2)', margin: '0 auto 16px' }} />
            <div style={{ fontFamily: 'var(--font-serif)', fontSize: 20, color: 'var(--ink)', marginBottom: 20 }}>付き合った日を選択</div>
            <div style={{ display: 'flex', gap: 8, marginBottom: 24 }}>
              <select value={tmpDate.year} onChange={e => setTmpDate(d => ({ ...d, year: +e.target.value }))} style={selStyle}>
                {Array.from({ length: 15 }, (_, i) => 2015 + i).map(y => <option key={y} value={y}>{y}年</option>)}
              </select>
              <select value={tmpDate.month} onChange={e => setTmpDate(d => ({ ...d, month: +e.target.value }))} style={selStyle}>
                {Array.from({ length: 12 }, (_, i) => i + 1).map(m => <option key={m} value={m}>{m}月</option>)}
              </select>
              <select value={tmpDate.day} onChange={e => setTmpDate(d => ({ ...d, day: +e.target.value }))} style={selStyle}>
                {Array.from({ length: 31 }, (_, i) => i + 1).map(d => <option key={d} value={d}>{d}日</option>)}
              </select>
            </div>
            <div style={{ display: 'flex', gap: 10 }}>
              <Btn variant="ghost" full size="md" onClick={() => setDatePicker(false)}>キャンセル</Btn>
              <Btn variant="amethyst" full size="md" onClick={saveSince}>保存</Btn>
            </div>
          </div>
        </div>
      )}

      {/* ── 次の記念日リスト overlay ── */}
      {milestoneOpen && (
        <div onClick={() => setMilestoneOpen(false)} style={{ position: 'absolute', inset: 0, zIndex: 60, background: 'rgba(40,34,28,.32)', backdropFilter: 'blur(2px)', display: 'flex', alignItems: 'flex-end', animation: 'risefade .25s' }}>
          <div onClick={e => e.stopPropagation()} style={{ width: '100%', background: 'var(--paper)', borderRadius: '26px 26px 0 0', padding: '14px 22px 40px', boxShadow: '0 -10px 40px rgba(0,0,0,.18)', animation: 'floatup .3s ease', maxHeight: '70%', overflow: 'hidden', display: 'flex', flexDirection: 'column' }}>
            <div style={{ width: 40, height: 4, borderRadius: 9, background: 'var(--line-2)', margin: '0 auto 16px' }} />
            <div style={{ fontFamily: 'var(--font-serif)', fontSize: 20, color: 'var(--ink)', marginBottom: 16, flexShrink: 0 }}>これからの記念日</div>
            <div className="noscroll" style={{ overflowY: 'auto', flex: 1 }}>
              {milestones.map((m, i) => (
                <div key={i} style={{ display: 'flex', alignItems: 'center', gap: 14, padding: '14px 0', borderBottom: i < milestones.length - 1 ? '1px solid var(--line)' : 'none' }}>
                  <div style={{ width: 40, height: 40, borderRadius: 12, background: 'color-mix(in oklch, var(--amethyst) 14%, var(--paper))', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>
                    <Icon name="sparkle" size={19} style={{ color: 'var(--amethyst)' }} />
                  </div>
                  <div style={{ flex: 1 }}>
                    <div style={{ fontWeight: 700, fontSize: 15, color: 'var(--ink)' }}>{m.label}</div>
                    <div style={{ fontSize: 12.5, color: 'var(--ink-faint)', marginTop: 2 }}>{m.dateStr}</div>
                  </div>
                  <div style={{ fontSize: 13, fontWeight: 700, color: 'var(--amethyst)', background: 'color-mix(in oklch, var(--amethyst) 10%, var(--paper))', borderRadius: 999, padding: '4px 11px' }}>
                    あと{m.daysLeft}日
                  </div>
                </div>
              ))}
              {milestones.length === 0 && <div style={{ textAlign: 'center', color: 'var(--ink-faint)', fontSize: 13, padding: '20px 0' }}>記念日が見つかりません</div>}
            </div>
          </div>
        </div>
      )}

      {/* ── このアプリについて（ハッカソン作品の注意事項）— 共通ダイアログ ── */}
      <AboutAppDialog open={legalOpen} onClose={() => setLegalOpen(false)} />
    </div>
  );
}

Object.assign(window, { HomeScreen, EventCreateScreen, SettingsScreen, MonthGrid, TimeBand, parseISODate, parseTimeRange, hhmm, WD });

})();
