/* ════════════════════════════════════════════════════════════════
   Cây Bồ Đề — Mobile App (bright saffron + white, Bchannel style)
   No emoji — clean SVG line icons.
   "APP LÀM THỬ FULL": mọi chức năng thao tác được, state thật qua
   module store (pub/sub + localStorage 'sdtd_app_v1').
   Persona: Trần Minh An (pháp danh Minh An).
   ════════════════════════════════════════════════════════════════ */
const { useState, useEffect, useRef } = React;

const C = {
  bg:     '#fffdf5',   // near-white content
  cream:  '#fcf2d2',
  card:   '#ffffff',
  card2:  '#fff8e8',
  line:   '#f0e2bd',
  saffron:'#f59000',
  saffronD:'#e07700',
  gold:   '#fbc117',
  amber:  '#ffbe3d',
  brown:  '#97561a',
  ink:    '#3d2509',
  soft:   '#7a521f',
  faint:  '#a9824a',
  white:  '#ffffff',
};
const F = "'Manrope', system-ui, sans-serif";

// ── SVG icon set (stroke, currentColor) ──
function Icon({ name, size = 22, fill = false, color = 'currentColor', sw = 1.9 }) {
  const p = {
    home: <path d="M3 10.5 12 3l9 7.5M5 9.5V20h5v-6h4v6h5V9.5"/>,
    award: <g><circle cx="12" cy="9" r="6"/><path d="M9 14.5 7.5 22 12 19.5 16.5 22 15 14.5"/></g>,
    plus: <path d="M12 5v14M5 12h14"/>,
    temple: <g><path d="M3 9h18M4 9l8-5 8 5M5 9v11M19 9v11M9.5 9v11M14.5 9v11M3 20h18"/></g>,
    person: <g><circle cx="12" cy="8" r="3.6"/><path d="M5.5 20a6.5 6.5 0 0 1 13 0"/></g>,
    leaf: <path d="M5 19c0-8 6-13 14-13 0 8-5 14-13 14-1 0-1-1-1-1zM7 17c3-4 6-6 9-7"/>,
    bell: <g><path d="M6 9a6 6 0 0 1 12 0c0 5 2 6 2 6H4s2-1 2-6z"/><path d="M10 20a2 2 0 0 0 4 0"/></g>,
    check: <path d="M5 12.5 10 17l9-10"/>,
    shield: <g><path d="M12 3l7 3v5c0 5-3 8-7 10-4-2-7-5-7-10V6z"/><path d="M9 12l2 2 4-4"/></g>,
    qr: <g><rect x="3.5" y="3.5" width="6" height="6" rx="1"/><rect x="14.5" y="3.5" width="6" height="6" rx="1"/><rect x="3.5" y="14.5" width="6" height="6" rx="1"/><path d="M14.5 14.5h2.5M20.5 14.5v6M14.5 17.5v3h3"/></g>,
    chevron: <path d="M9 6l6 6-6 6"/>,
    book: <path d="M4 5.5C4 4.7 4.7 4 5.5 4H11v15H5.5A1.5 1.5 0 0 0 4 20.5zM20 5.5C20 4.7 19.3 4 18.5 4H13v15h5.5a1.5 1.5 0 0 1 1.5 1.5z"/>,
    hands: <path d="M12 21c-4-2-8-5-8-9a3 3 0 0 1 5.2-2L12 12l2.8-2A3 3 0 0 1 20 12c0 4-4 7-8 9z"/>,
    connect: <g><circle cx="6" cy="12" r="2.6"/><circle cx="18" cy="12" r="2.6"/><path d="M8.6 12h6.8"/></g>,
    clock: <g><circle cx="12" cy="12" r="8.2"/><path d="M12 7.5V12l3 1.8"/></g>,
    pin: <g><path d="M12 21s6.5-5.5 6.5-11A6.5 6.5 0 0 0 5.5 10c0 5.5 6.5 11 6.5 11z"/><circle cx="12" cy="10" r="2.3"/></g>,
    sparkle: <path d="M12 3l1.8 5.2L19 10l-5.2 1.8L12 17l-1.8-5.2L5 10l5.2-1.8z"/>,
    calendar: <g><rect x="4" y="5" width="16" height="15" rx="2"/><path d="M4 9.5h16M8.5 3v4M15.5 3v4"/></g>,
    gift: <g><rect x="4" y="9" width="16" height="11" rx="1.5"/><path d="M4 13h16M12 9v11M12 9c-1.5-3-6-3-6 0M12 9c1.5-3 6-3 6 0"/></g>,
    meditate: <g><circle cx="12" cy="5.5" r="2"/><path d="M12 8c-2 3-2 5-2 6m2-6c2 3 2 5 2 6M5 19c2-3 4.5-3 7-3s5 0 7 3M7 16l5-2 5 2"/></g>,
    drop: <path d="M12 3c4 5 6 8 6 11a6 6 0 0 1-12 0c0-3 2-6 6-11z"/>,
    star: <path d="M12 3l2.6 5.6 6.1.7-4.5 4.2 1.2 6L12 16.8 6.6 19.5l1.2-6L3.3 9.3l6.1-.7z"/>,
    send: <path d="M21 3 3 10.5l7.5 3L13.5 21 21 3zM10.5 13.5 21 3"/>,
    chat: <path d="M21 11.5a8.5 8.5 0 0 1-8.5 8.5c-1.6 0-3.1-.4-4.4-1.2L3 20l1.2-5.1A8.5 8.5 0 1 1 21 11.5z"/>,
    camera: <g><rect x="3" y="7" width="18" height="13" rx="2.5"/><path d="M8.5 7 10 4.5h4L15.5 7"/><circle cx="12" cy="13.2" r="3.4"/></g>,
    lock: <g><rect x="5.5" y="10.5" width="13" height="9.5" rx="2"/><path d="M8.5 10.5V8a3.5 3.5 0 0 1 7 0v2.5"/></g>,
    edit: <path d="M4 20h4L19.5 8.5a2.1 2.1 0 0 0-3-3L5 17z M13.5 7l3 3"/>,
    refresh: <path d="M20 12a8 8 0 1 1-2.3-5.6M20 4v4h-4"/>,
  }[name];
  return (
    <svg width={size} height={size} viewBox="0 0 24 24" fill={fill ? color : 'none'}
      stroke={fill ? 'none' : color} strokeWidth={sw} strokeLinecap="round" strokeLinejoin="round">
      {p}
    </svg>
  );
}

const Leaf = ({ s = 15, color = C.saffron }) => (
  <span style={{ display: 'inline-flex', verticalAlign: 'middle' }}><Icon name="leaf" size={s} color={color} fill /></span>
);

function Card({ children, style, onClick }) {
  return <div onClick={onClick} style={{
    background: C.card, border: `1px solid ${C.line}`, borderRadius: 20,
    boxShadow: '0 1px 2px rgba(151,86,26,0.04), 0 8px 24px rgba(245,144,0,0.06)',
    cursor: onClick ? 'pointer' : 'default', ...style,
  }}>{children}</div>;
}

// header used inside white content
function Header({ title, sub, back }) {
  return (
    <div style={{ padding: '54px 22px 14px' }}>
      {back && <button onClick={back} style={{ background: 'rgba(245,144,0,0.12)', border: 0, color: C.saffronD, borderRadius: 100, padding: '6px 14px', fontSize: 12.5, fontWeight: 700, cursor: 'pointer', fontFamily: F, display: 'inline-flex', alignItems: 'center', gap: 5, marginBottom: 12 }}>‹ Trang chủ</button>}
      <p style={{ margin: 0, color: C.saffronD, fontSize: 13, fontWeight: 700 }}>{sub}</p>
      <h1 style={{ margin: '2px 0 0', color: C.ink, fontSize: 27, fontWeight: 800, letterSpacing: '-0.02em' }}>{title}</h1>
    </div>
  );
}

function Avatar({ size = 38, icon = 'meditate' }) {
  return (
    <div style={{ width: size, height: size, borderRadius: 100, flexShrink: 0,
      background: 'linear-gradient(150deg,#ffd35e,#f59000)', display: 'flex', alignItems: 'center', justifyContent: 'center', color: '#fff' }}>
      <Icon name={icon} size={size * 0.5} color="#fff" />
    </div>
  );
}

function Ring({ pct, size = 92, label, value }) {
  const r = size / 2 - 7, c = 2 * Math.PI * r;
  return (
    <div style={{ position: 'relative', width: size, height: size }}>
      <svg width={size} height={size} style={{ transform: 'rotate(-90deg)' }}>
        <circle cx={size/2} cy={size/2} r={r} fill="none" stroke="rgba(255,255,255,0.45)" strokeWidth="7"/>
        <circle cx={size/2} cy={size/2} r={r} fill="none" stroke="#fff" strokeWidth="7" strokeLinecap="round"
          strokeDasharray={c} strokeDashoffset={c * (1 - pct)} style={{ transition: 'stroke-dashoffset 1s' }}/>
      </svg>
      <div style={{ position: 'absolute', inset: 0, display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center' }}>
        <span style={{ color: '#fff', fontWeight: 800, fontSize: 20 }}>{value}</span>
        <span style={{ color: 'rgba(255,255,255,0.85)', fontSize: 10 }}>{label}</span>
      </div>
    </div>
  );
}

// rounded saffron top banner behind status bar / title
function TopBanner({ children, h = 150 }) {
  return (
    <div style={{ position: 'relative', background: 'linear-gradient(165deg,#ffd35e 0%, #f59000 60%, #e07700 100%)',
      borderRadius: '0 0 28px 28px', paddingTop: 56, paddingBottom: 18, color: '#fff', minHeight: h }}>
      {children}
    </div>
  );
}

// ════════ BODHI TREE GROWTH ════════
// Visualizes accumulated Lá Bồ Đề as a growing bodhi tree.
// Ngưỡng cấp (cấp 1..6): 0 / 200 / 600 / 1200 / 2000 / 3000 Lá.
const TREE_STAGES = [
  { min: 0,    key: 'Hạt giống',     leaves: 0,   trunk: 0,   desc: 'Hành trình bắt đầu từ một hạt giống thiện tâm. Hãy gieo thiện hành đầu tiên.' },
  { min: 200,  key: 'Nảy mầm',       leaves: 3,   trunk: 28,  desc: 'Mầm xanh đã nhú. Mỗi thiện hành là một giọt nước lành nuôi cây lớn lên.' },
  { min: 600,  key: 'Cây non',       leaves: 9,   trunk: 54,  desc: 'Cây non vươn mình. Bạn đang đi đúng hướng trên con đường tỉnh thức.' },
  { min: 1200, key: 'Cây vững',      leaves: 18,  trunk: 78,  desc: 'Thân cây đã vững. Tán lá ngày một sum suê theo công đức của bạn.' },
  // trunk cấp 5–6 giữ ≤ 86 để tán còn headroom trong viewport vuông (xem clamp
  // spread trong BodhiTree) — trunk 96/110 cũ đẩy tâm tán lên sát mép, lá bị cắt.
  { min: 2000, key: 'Tỏa bóng',      leaves: 30,  trunk: 80,  desc: 'Cây bắt đầu tỏa bóng mát, che chở và lan tỏa thiện lành đến mọi người.' },
  { min: 3000, key: 'Cây Bồ Đề',     leaves: 46,  trunk: 86,  desc: 'Cây Bồ Đề sum suê — biểu tượng cho hành trình bền bỉ vun bồi từ bi và trí tuệ.' },
];
function treeStage(leaf) {
  let s = 0;
  for (let i = 0; i < TREE_STAGES.length; i++) if (leaf >= TREE_STAGES[i].min) s = i;
  return s;
}
function BodhiTree({ leaf = 0, size = 150 }) {
  const si = treeStage(leaf);
  const st = TREE_STAGES[si];
  const cx = size / 2, groundY = size * 0.86;
  // deterministic leaf positions around a canopy center
  const canopyY = groundY - st.trunk * (size / 150) - size * 0.06;
  // clamp độ xòe tán theo headroom còn lại phía trên tâm tán — thân càng cao
  // (cấp 5–6) tán càng phải gọn lại, để lá (kể cả bán kính hình lá) không văng
  // khỏi viewport (ly < 0).
  const spread = Math.min(1, (canopyY - size * 0.06) / (size * 0.30));
  const leaves = [];
  const n = st.leaves;
  for (let i = 0; i < n; i++) {
    const ang = (i * 137.5) * Math.PI / 180;          // golden-angle phyllotaxis
    const rad = ((size * 0.05) + Math.sqrt(i / Math.max(n, 1)) * size * 0.28) * spread;
    const lx = cx + Math.cos(ang) * rad;
    const ly = canopyY + Math.sin(ang) * rad * 0.82;
    const rot = (ang * 180 / Math.PI) + 90;
    leaves.push({ lx, ly, rot, s: 0.42 + (i % 3) * 0.06 });
  }
  const sc = size / 150;
  return (
    <svg width={size} height={size} viewBox={`0 0 ${size} ${size}`}>
      <defs>
        <radialGradient id="bgGlow" cx="50%" cy="42%" r="60%"><stop offset="0" stopColor="#fff3d6"/><stop offset="1" stopColor="#ffffff" stopOpacity="0"/></radialGradient>
        <linearGradient id="leafGrad" x1="0" y1="0" x2="1" y2="1"><stop offset="0" stopColor="#ffd35e"/><stop offset="1" stopColor="#f59000"/></linearGradient>
        <linearGradient id="trunkGrad" x1="0" y1="0" x2="0" y2="1"><stop offset="0" stopColor="#b06a1c"/><stop offset="1" stopColor="#7c440e"/></linearGradient>
      </defs>
      <circle cx={cx} cy={size*0.42} r={size*0.46} fill="url(#bgGlow)"/>
      {/* ground */}
      <ellipse cx={cx} cy={groundY+4*sc} rx={size*0.32} ry={size*0.05} fill="#f0e2bd"/>
      <path d={`M${cx-size*0.32} ${groundY} Q ${cx} ${groundY-6*sc} ${cx+size*0.32} ${groundY}`} stroke="#e6cd8f" strokeWidth={2*sc} fill="none"/>
      {si === 0 ? (
        // seed
        <g>
          <ellipse cx={cx} cy={groundY-7*sc} rx={9*sc} ry={11*sc} fill="url(#leafGrad)" transform={`rotate(8 ${cx} ${groundY-7*sc})`}/>
          <path d={`M${cx} ${groundY-14*sc} q ${5*sc} ${-7*sc} ${1*sc} ${-13*sc}`} stroke="#7c440e" strokeWidth={2*sc} fill="none" strokeLinecap="round"/>
        </g>
      ) : (
        <g>
          {/* trunk */}
          <path d={`M${cx-5*sc} ${groundY} Q ${cx-3*sc} ${groundY-st.trunk*sc*0.5} ${cx-2*sc} ${groundY-st.trunk*sc} L ${cx+2*sc} ${groundY-st.trunk*sc} Q ${cx+3*sc} ${groundY-st.trunk*sc*0.5} ${cx+5*sc} ${groundY} Z`} fill="url(#trunkGrad)"/>
          {/* a couple of branches for bigger stages */}
          {si >= 3 && <path d={`M${cx} ${groundY-st.trunk*sc*0.7} q ${-14*sc} ${-6*sc} ${-20*sc} ${-18*sc}`} stroke="url(#trunkGrad)" strokeWidth={3.4*sc} fill="none" strokeLinecap="round"/>}
          {si >= 3 && <path d={`M${cx} ${groundY-st.trunk*sc*0.55} q ${14*sc} ${-6*sc} ${20*sc} ${-16*sc}`} stroke="url(#trunkGrad)" strokeWidth={3.4*sc} fill="none" strokeLinecap="round"/>}
          {/* leaves — each a bodhi-leaf heart-drop shape */}
          {leaves.map((lf, i) => (
            <g key={i} transform={`translate(${lf.lx} ${lf.ly}) rotate(${lf.rot}) scale(${lf.s*sc})`}>
              <path d="M0 -16 C 11 -10 12 4 0 16 C -12 4 -11 -10 0 -16 Z" fill="url(#leafGrad)" stroke="#e07700" strokeWidth="0.7"/>
              <path d="M0 -12 L0 12" stroke="#e07700" strokeWidth="0.8" opacity="0.5"/>
            </g>
          ))}
        </g>
      )}
    </svg>
  );
}

/* ════════════════════════════════════════════════════════════════
   STATE CORE — module store (pub/sub) + persist localStorage
   Key: 'sdtd_app_v1'. SSR/private-mode an toàn (try/catch → memory).
   Số chuẩn toàn dự án (KHÔNG phá): 1.248 Lá · 310/500 (62%) ·
   #214 (GHIM — demo) · Top-3 Gala: Minh Tuệ 4.820 / Diệu Tâm 4.510 /
   Nguyên Hạnh 4.205 · Top 8%.
   ════════════════════════════════════════════════════════════════ */
const STORE_KEY = 'sdtd_app_v1';
const MONTH_CAP = 500;          // trần Lá/tháng — cơ chế Phòng Ác
// Giai đoạn Khởi Động (T3–T9/2026) — đếm ngược tính live từ ngày hiện tại, không hardcode
const PHASE_START = new Date(2026, 2, 1);   // 01/3/2026
const PHASE_END   = new Date(2026, 8, 30);  // đóng sổ 30/9/2026
// Mốc dự án Cầu Nối: mỗi mốc mang Lá riêng (15–50) — đồng bộ roadmap Webapp.html
const uid = () => 'x' + Date.now().toString(36) + Math.random().toString(36).slice(2, 7);
const fmt = n => String(n).replace(/\B(?=(\d{3})+(?!\d))/g, '.');
const nowTime = () => { const d = new Date(); return String(d.getHours()).padStart(2, '0') + ':' + String(d.getMinutes()).padStart(2, '0'); };
const todayKey = () => { const d = new Date(); return d.getFullYear() + '-' + (d.getMonth() + 1) + '-' + d.getDate(); };

// 11 loại thiện hành (khớp 11 lĩnh vực hệ thống) — bảng điểm 15–80 Lá/loại.
// Số Lá ĐỒNG BỘ với các record đã chốt toàn dự án:
//   khóa thiền/khóa tu 50 (seed h1, notification n1, Webapp 'Khóa thiền 3 ngày · +50')
//   giảng pháp 40 (seed h3, Webapp) · hiến máu 30 (seed h4, TEMPLE_INFO Chùa Hương Sắc, Webapp)
//   xuất bản ISBN 80 (Webapp 'Xuất bản tập thơ ISBN · +80') — các loại còn lại scale ×3 tương ứng.
const DEED_TYPES = [
  ['hands',    'Thiện nguyện cộng đồng',     '≥ 10 người hưởng lợi',              60],
  ['meditate', 'Khóa thiền / khóa tu',       '≥ 3 ngày tập trung',                50],
  ['book',     'Xuất bản tác phẩm',          'Có mã ISBN',                        80],
  ['person',   'Giảng pháp công cộng',       'Buổi giảng đại chúng',              40],
  ['drop',     'Hiến máu nhân đạo',          'Mỗi lần hiến hợp lệ',               30],
  ['star',     'Giáo dục — lớp học 0 đồng',  'Mỗi lớp/khóa hoàn thành',           45],
  ['leaf',     'Bảo vệ môi trường',          'Trồng cây / dọn rác có minh chứng', 30],
  ['sparkle',  'Bảo tồn di sản',             'Tham gia trùng tu / số hóa',        45],
  ['connect',  'Truyền thông Phật pháp số',  'Nội dung được duyệt đăng',          30],
  ['gift',     'Công quả tại chùa',          'Mỗi buổi công quả',                 15],
  ['temple',   'Hộ trì sự kiện Phật giáo',   'Mỗi sự kiện phục vụ',               30],
];

// Top-3 chuẩn (đồng bộ Portal & Webapp) — không đổi thứ tự/số liệu
const GALA_TOP = [['Thầy Minh Tuệ', '4.820', 1], ['Sư cô Diệu Tâm', '4.510', 2], ['Cư sĩ Nguyên Hạnh', '4.205', 3]];
const GALA_REST = [['Cư sĩ Thiện Đức', '3.980'], ['Ni sư Hương Trang', '3.760'], ['Nhóm Hương Sắc Bồ Đề', '3.540']];

const TEMPLE_INFO = {
  'Chùa Quán Sứ': { place: 'Hà Nội', dist: '0.4 km', founded: '1934', address: '73 Quán Sứ, Hoàn Kiếm', members: '24.100',
    desc: 'Trụ sở Trung ương Giáo hội Phật giáo Việt Nam — trung tâm Phật giáo lớn của miền Bắc.',
    acts: [
      // việc con (đợt tuyển trợ giảng tháng 7) của dự án Cầu Nối p1 'Lớp tiếng Anh
      // miễn phí cho trẻ em' — đặt tên riêng để 2 thực thể không bị đọc nhầm là trùng lặp
      { t: 'Trợ giảng lớp tiếng Anh — đợt T7', req: 'Tình nguyện viên dạy / trợ giảng (T7, CN)', due: '30/06/2026', leaf: 80, type: 'Giáo dục', ic: 'book', status: 'open' },
      { t: 'Khóa tu Bát Quan Trai', req: 'Đăng ký tham dự trọn một ngày', due: '15/06/2026', leaf: 50, type: 'Tu học', ic: 'meditate', status: 'open' },
      { t: 'Phát quà Trung thu cho trẻ vùng cao', req: 'Đóng góp / đồng hành chuyến đi', due: '20/09/2026', leaf: 40, type: 'Thiện nguyện', ic: 'hands', status: 'soon' },
    ] },
  'Chùa Trấn Quốc': { place: 'Tây Hồ', dist: '1.2 km', founded: '541', address: 'Thanh Niên, Tây Hồ', members: '18.700',
    desc: 'Ngôi chùa cổ nhất Hà Nội, hơn 1.500 năm tuổi bên Hồ Tây.',
    acts: [
      { t: 'Khóa thiền cuối tuần', req: 'Tham dự ≥ 2 buổi', due: '10/06/2026', leaf: 45, type: 'Tu học', ic: 'meditate', status: 'open' },
      { t: 'Trùng tu vườn tháp cổ', req: 'Đóng góp công đức tu bổ', due: '31/07/2026', leaf: 70, type: 'Di sản', ic: 'sparkle', status: 'soon' },
    ] },
  'Chùa Hương Sắc': { place: 'Hà Đông', dist: '3.8 km', founded: '1998', address: 'Phú Lương, Hà Đông', members: '9.400',
    desc: 'Trung tâm sinh hoạt Phật pháp và truyền thông Hương Sắc Bồ Đề.',
    acts: [
      { t: 'Sản xuất nội dung Phật pháp số', req: 'Cộng tác viết / dựng video', due: '25/06/2026', leaf: 90, type: 'Truyền thông', ic: 'connect', status: 'open' },
      { t: 'Bếp chay 0 đồng cuối tháng', req: 'Tình nguyện viên nấu / phục vụ', due: '28/06/2026', leaf: 60, type: 'Thiện nguyện', ic: 'hands', status: 'open' },
      { t: 'Hiến máu nhân đạo', req: 'Mỗi lần hiến hợp lệ', due: '12/07/2026', leaf: 30, type: 'Cộng đồng', ic: 'drop', status: 'soon' },
    ] },
};

// ── Thiện Tri Thức: flows + keyword matching (mượn matchFlow của thien-tri-thuc.html)
// Trích dẫn dùng PLACEHOLDER (chờ Ban Văn hóa kiểm định) — TUYỆT ĐỐI không chèn bản dịch kinh thật.
const CHAT_FLOWS = [
  { q: 'Con đang giận anh trai…', ctx: 'sân hận · gia đình', cites: [
    { src: 'Kinh Pháp Cú · Phẩm Song Yếu · câu 5', tags: ['Sân hận', 'Gia đình', 'Buông xả'] },
    { src: 'Kinh Pháp Cú · Phẩm Phẫn Nộ · câu 223', tags: ['Sân hận', 'Từ bi'] } ] },
  { q: 'Mất việc khiến con hoang mang', ctx: 'công việc · vô thường', cites: [
    { src: 'Kinh Pháp Cú · Phẩm Vô Thường · câu 277', tags: ['Vô thường', 'Công việc'] },
    { src: 'Kinh Pháp Cú · Phẩm An Lạc · câu 204', tags: ['An lạc', 'Tri túc'] } ] },
  { q: 'Làm sao buông được lo âu?', ctx: 'lo âu · điều tâm', cites: [
    { src: 'Kinh Pháp Cú · Phẩm Tâm · câu 35', tags: ['Lo âu', 'Điều tâm'] },
    { src: 'Kinh Pháp Cú · Phẩm Hiền Trí · câu 81', tags: ['Vững chãi', 'Buông xả'] } ] },
  { q: 'Con vừa mất người thân, lòng trống rỗng quá', ctx: 'mất mát · vô thường', cites: [
    { src: 'Kinh Pháp Cú · Phẩm Già · câu 148', tags: ['Vô thường', 'Khổ đau'] },
    { src: 'Kinh Từ Bi (Metta Sutta) · Tiểu Bộ · kệ 7–8', tags: ['Từ bi', 'Thương yêu'] } ] },
  { q: 'Vợ chồng con cãi nhau mãi, mệt mỏi quá', ctx: 'gia đình · hòa hợp', cites: [
    { src: 'Kinh Phước Đức (Mangala Sutta) · Tiểu Bộ · kệ 4', tags: ['Gia đình', 'Hòa hợp'] },
    { src: 'Kinh Pháp Cú · Phẩm Phẫn Nộ · câu 223', tags: ['Từ bi', 'Nhẫn nhịn'] } ] },
];
const CHAT_FALLBACK = { ctx: 'đời thường', cites: [
  { src: 'Kinh Pháp Cú · Phẩm Tâm · câu 35', tags: ['Điều tâm', 'Tỉnh thức'] },
  { src: 'Kinh Pháp Cú · Phẩm Vô Thường · câu 277', tags: ['Vô thường', 'Quán chiếu'] } ] };
const CHAT_KEYWORDS = [
  { re: /giận|sân|tức|hận|ghét/i, flow: 0 },
  { re: /việc|nghề|thất nghiệp|sa thải|công ty|sự nghiệp/i, flow: 1 },
  { re: /lo|sợ|bất an|căng thẳng|áp lực|stress/i, flow: 2 },
  { re: /mất|tang|qua đời|ra đi|người thân|trống rỗng/i, flow: 3 },
  { re: /vợ|chồng|cãi|hôn nhân|ly hôn|gia đình/i, flow: 4 },
];
function matchChatFlow(q) {
  const exact = CHAT_FLOWS.findIndex(f => f.q === q);
  if (exact >= 0) return exact;
  for (const k of CHAT_KEYWORDS) if (k.re.test(q)) return k.flow;
  return -1; // không khớp → bộ trích dẫn tổng quát
}

function seedState() {
  return {
    v: 3, // BUMP mỗi khi đổi schema (v3: seed p3 joined:true khớp Webapp; v2: milestones mang leaf riêng)
    name: 'Trần Minh An',
    dharma: 'Minh An',
    leaves: 1248,
    monthLeaves: 310,
    rank: 214, // GHIM — không đổi khi tương tác (demo)
    history: [
      { id: 'h1', t: 'Khóa thiền 3 ngày — chùa Hoằng Pháp', date: 'Hôm qua', leaf: 50, ic: 'meditate' },
      { id: 'h2', t: 'Phát cơm từ thiện · 40 suất', date: '12/05', leaf: 100, ic: 'hands' },
      { id: 'h3', t: 'Giảng pháp công cộng tại đạo tràng', date: '08/05', leaf: 40, ic: 'book' },
      { id: 'h4', t: 'Hiến máu nhân đạo', date: '02/05', leaf: 30, ic: 'drop' },
      { id: 'h5', t: 'Check-in Chùa Hoằng Pháp', date: '28/05', leaf: 2, ic: 'temple' },
    ],
    notifications: [
      { id: 'n1', ic: 'check', tone: 'ok', t: 'Thiện hành được chùa xác thực', d: 'Khóa thiền 3 ngày · +50 Lá Bồ Đề', time: '09:41', day: 'Hôm nay', unread: true },
      { id: 'n2', ic: 'connect', tone: 'gold', t: 'Dự án mới phù hợp với bạn', d: 'Lớp tiếng Anh miễn phí — Chùa Quán Sứ', time: '08:02', day: 'Hôm nay', unread: true },
      { id: 'n3', ic: 'chat', tone: 'gold', t: 'Thiện Tri Thức', d: '2 trích dẫn mới cho câu hỏi bạn lưu.', time: '07:15', day: 'Hôm nay', unread: true },
      { id: 'n4', ic: 'award', tone: 'gold', t: 'Bạn thăng hạng lên #214', d: 'Tăng 12 bậc trong bảng vinh danh tháng', time: '19:20', day: 'Hôm qua', unread: false },
      { id: 'n5', ic: 'calendar', tone: 'gold', t: 'Sắp tới hạn nộp hồ sơ', d: 'Giai đoạn Khởi Động đóng sổ 30/9/2026', time: '14:05', day: 'Hôm qua', unread: false },
      { id: 'n6', ic: 'gift', tone: 'gold', t: 'Nhà bảo trợ mới đồng hành', d: 'Mảnh Đồng Vàng được trao cho dự án bạn theo dõi', time: '11:30', day: 'Hôm qua', unread: false },
    ],
    deeds: [],          // {id, typeIdx, t, leaf, ic, approver, evidence, status:'pending'|'approved', granted?, time}
    checkins: [{ id: 'ck-seed', name: 'Chùa Hoằng Pháp', place: 'TP.HCM', date: '28/05/2026 · 08:10', day: '2026-5-28' }],
    connectTasks: [],   // việc nhận từ check-in chùa (thay MY_CONNECT cũ)
    // Mốc & Lá/mốc PORT NGUYÊN VĂN từ roadmap Webapp.html (cùng persona Minh An):
    // p1 đã tham gia + 2 mốc đầu đã duyệt, p2 đã tham gia + 1 mốc đã duyệt,
    // p3 đã tham gia, mốc 1 đang mở — Webapp: mốc 1 'current', chưa mốc nào approved
    // — 2 demo khớp trạng thái.
    projects: [
      { id: 'p1', t: 'Lớp tiếng Anh miễn phí cho trẻ em', org: 'Chùa Quán Sứ · Hà Nội', cat: 'Giáo dục', need: 'Cần 4 tình nguyện viên', ic: 'book', joined: true, completed: false,
        milestones: [
          { t: 'Khảo sát & lập danh sách lớp', leaf: 20, done: true },
          { t: 'Soạn giáo trình 8 buổi', leaf: 30, done: true },
          { t: 'Giảng dạy 8 buổi học', leaf: 40, done: false },
          { t: 'Tổng kết & báo cáo kết quả', leaf: 30, done: false },
        ] },
      { id: 'p2', t: 'Bếp ăn 0 đồng tại bệnh viện', org: 'Đạo Tràng Từ Tâm · Đà Nẵng', cat: 'Xã hội', need: 'Cần 15 tình nguyện viên', ic: 'hands', joined: true, completed: false,
        milestones: [
          { t: 'Tập huấn an toàn thực phẩm', leaf: 15, done: true },
          { t: 'Phục vụ 4 ca nấu ăn', leaf: 40, done: false },
          { t: 'Vận động thêm nhà hảo tâm', leaf: 25, done: false },
        ] },
      { id: 'p3', t: 'Khóa tu mùa hè cho thanh thiếu niên', org: 'Chùa Ba Vàng · Quảng Ninh', cat: 'Phật pháp', need: 'Cần 8 điều phối viên', ic: 'meditate', joined: true, completed: false,
        milestones: [
          { t: 'Chuẩn bị nội dung sinh hoạt', leaf: 20, done: false },
          { t: 'Trợ giảng 3 ngày khóa tu', leaf: 50, done: false },
          { t: 'Thu hoạch & chia sẻ', leaf: 20, done: false },
        ] },
    ],
    votes: [186, 142, 117],
    voted: null,
    chatLog: [{ id: 'c-seed', q: 'Con đang giận anh trai…', flow: 0 }],
  };
}

function loadState() {
  try {
    const raw = localStorage.getItem(STORE_KEY);
    // Merge đè lên defaults mới: field thêm sau (cùng version) vẫn có giá trị seed,
    // tránh undefined.filter/map cho khách quay lại. Đổi schema sâu hơn → bump v.
    if (raw) { const s = JSON.parse(raw); if (s && s.v === 3 && s.notifications) return Object.assign({}, seedState(), s); }
  } catch (e) {}
  return seedState();
}
let STATE = loadState();
const LISTENERS = new Set();
function saveState() { try { localStorage.setItem(STORE_KEY, JSON.stringify(STATE)); } catch (e) {} }
function setState(patch) {
  STATE = Object.assign({}, STATE, patch);
  saveState();
  LISTENERS.forEach(fn => { try { fn(STATE); } catch (e) {} });
}
// hook — mọi screen subscribe store; SSR-safe (useEffect không chạy khi renderToString)
function useStore() {
  const [s, setS] = useState(STATE);
  useEffect(() => {
    const fn = ns => setS(ns);
    LISTENERS.add(fn);
    setS(STATE); // sync nếu store đổi giữa render & effect
    return () => LISTENERS.delete(fn);
  }, []);
  return s;
}

// derived helpers
const unreadCount = s => s.notifications.filter(n => n.unread).length;
const approvedDeeds = s => s.deeds.filter(d => d.status === 'approved').length;
const anyMilestoneDone = s => s.projects.some(p => p.milestones.some(m => m.done));

// DEED_TIMERS: CHỦ ĐÍCH để module-level, KHÔNG clear khi screen unmount — đây là
// sai khác có cân nhắc so với câu chữ đặc tả mục 3 ("clear timeout khi unmount"):
//   • Ý ĐỒ AN TOÀN của đặc tả vẫn được thỏa: timer chỉ mutate module store (không setState
//     trực tiếp); component unmount đã gỡ listener trong useStore → không có
//     setState-after-unmount.
//   • Nếu clear theo nghĩa đen khi unmount: deed vừa gửi rồi chuyển tab trong 4s sẽ kẹt
//     'pending' vĩnh viễn trong phiên — bug thật. Deed pending còn được re-arm khi reload
//     (xem rescheduler cuối phần actions). KHÔNG clear nếu không re-arm lại.
const DEED_TIMERS = {};
const actions = {
  notify(ic, tone, t, d) {
    setState({ notifications: [{ id: uid(), ic, tone, t, d, time: nowTime(), day: 'Hôm nay', unread: true }, ...STATE.notifications] });
  },
  markRead(id) {
    setState({ notifications: STATE.notifications.map(n => n.id === id ? Object.assign({}, n, { unread: false }) : n) });
  },
  markAllRead() {
    setState({ notifications: STATE.notifications.map(n => n.unread ? Object.assign({}, n, { unread: false }) : n) });
  },
  // cộng Lá có trần tháng (Phòng Ác) — điểm demo đắt giá
  addLeaves(n, label, ic) {
    const room = Math.max(0, MONTH_CAP - STATE.monthLeaves);
    const granted = Math.min(n, room);
    const clipped = granted < n;
    setState({
      leaves: STATE.leaves + granted,
      monthLeaves: STATE.monthLeaves + granted,
      history: granted > 0 ? [{ id: uid(), t: label, date: 'Hôm nay', leaf: granted, ic: ic || 'leaf' }, ...STATE.history] : STATE.history,
    });
    if (clipped) actions.notify('shield', 'gold', 'Đã chạm trần 500 Lá/tháng — cơ chế Phòng Ác',
      granted > 0
        ? `Chỉ cộng +${granted}/${n} Lá cho “${label}”. Phần vượt trần không tích lũy — giữ thiện hành thuần vì tâm.`
        : `“${label}” không được cộng Lá trong tháng này. Trần tháng giúp thiện hành thuần vì tâm, không chạy đua điểm.`);
    return { granted, clipped };
  },
  checkIn(name) {
    const day = todayKey();
    if (STATE.checkins.some(c => c.name === name && c.day === day)) return { ok: false, dup: true };
    const info = TEMPLE_INFO[name] || { place: '' };
    setState({ checkins: [{ id: uid(), name, place: info.place, date: 'Hôm nay · ' + nowTime(), day }, ...STATE.checkins] });
    const r = actions.addLeaves(2, 'Check-in ' + name, 'temple');
    actions.notify('temple', 'ok', 'Check-in thành công', name + (r.granted > 0 ? ` · +${r.granted} Lá Bồ Đề` : ' · đã chạm trần tháng'));
    return { ok: true, granted: r.granted };
  },
  addConnectTask(name, a) {
    if (STATE.connectTasks.some(x => x.t === a.t)) return;
    setState({ connectTasks: [{ id: uid(), t: a.t, org: name + ' · ' + (TEMPLE_INFO[name] || {}).place, cat: a.type, leaf: a.leaf, need: a.req, due: a.due, ic: a.ic, fromTemple: true }, ...STATE.connectTasks] });
  },
  removeConnectTask(t) {
    setState({ connectTasks: STATE.connectTasks.filter(x => x.t !== t) });
  },
  submitDeed({ typeIdx, approver, evidence }) {
    const ty = DEED_TYPES[typeIdx];
    const deed = { id: uid(), typeIdx, t: ty[1], leaf: ty[3], ic: ty[0], approver, evidence: !!evidence, status: 'pending', time: nowTime() };
    setState({ deeds: [deed, ...STATE.deeds] });
    actions.scheduleApproval(deed.id);
    return deed.id;
  },
  scheduleApproval(id) { // auto-demo: 4s sau Trụ trì xác thực
    if (DEED_TIMERS[id]) return;
    DEED_TIMERS[id] = setTimeout(() => { delete DEED_TIMERS[id]; actions.approveDeed(id); }, 4000);
  },
  approveDeed(id) {
    const d = STATE.deeds.find(x => x.id === id);
    if (!d || d.status !== 'pending') return;
    const r = actions.addLeaves(d.leaf, d.t + ' — đã xác thực', d.ic);
    setState({ deeds: STATE.deeds.map(x => x.id === id ? Object.assign({}, x, { status: 'approved', granted: r.granted }) : x) });
    // granted=0 (trần tháng đã cạn): KHÔNG hiện '+0 Lá' — addLeaves đã tự bắn
    // notification trần Phòng Ác riêng, ở đây chỉ báo kết quả xác thực.
    actions.notify('check', 'ok', 'Trụ trì đã xác thực ✓',
      r.granted === 0
        ? `${d.t} · Trụ trì đã xác thực — đã chạm trần tháng, Lá sẽ tính sang tháng sau`
        : `${d.t} · +${r.granted} Lá Bồ Đề` + (r.clipped ? ' (đã chạm trần tháng)' : ''));
  },
  joinProject(id) {
    const p = STATE.projects.find(x => x.id === id);
    if (!p || p.joined) return;
    setState({ projects: STATE.projects.map(x => x.id === id ? Object.assign({}, x, { joined: true }) : x) });
    const idx = Math.max(0, p.milestones.findIndex(m => !m.done));
    actions.notify('connect', 'gold', 'Đã tham gia dự án', `${p.t} — mốc ${idx + 1} đã mở, hoàn thành để nhận +${p.milestones[idx].leaf} Lá.`);
  },
  leaveProject(id) {
    const p = STATE.projects.find(x => x.id === id);
    if (!p || !p.joined) return;
    setState({ projects: STATE.projects.map(x => x.id === id ? Object.assign({}, x, { joined: false }) : x) });
    actions.notify('connect', 'gold', 'Đã rời dự án', `${p.t} — tiến độ mốc được giữ lại, bạn có thể quay lại bất cứ lúc nào.`);
  },
  completeMilestone(pid) {
    const p = STATE.projects.find(x => x.id === pid);
    if (!p || !p.joined || p.completed) return;
    const idx = p.milestones.findIndex(m => !m.done);
    if (idx < 0) return;
    const ms = p.milestones.map((m, i) => i === idx ? Object.assign({}, m, { done: true }) : m);
    const completed = ms.every(m => m.done);
    setState({ projects: STATE.projects.map(x => x.id === pid ? Object.assign({}, x, { milestones: ms, completed }) : x) });
    const r = actions.addLeaves(p.milestones[idx].leaf, `Mốc “${p.milestones[idx].t}” — ${p.t}`, 'check');
    if (completed) actions.notify('sparkle', 'ok', 'Hoàn thành dự án', `${p.t} — bạn đã đi trọn ${ms.length} mốc. Lành thay!`);
    else actions.notify('connect', 'ok', `Hoàn thành mốc ${idx + 1}`, `${p.t} · +${r.granted} Lá — mốc ${idx + 2} đã mở.`);
  },
  vote(i) {
    if (STATE.voted === i) return;
    const prev = STATE.voted;
    setState({ votes: STATE.votes.map((n, j) => j === i ? n + 1 : j === prev ? n - 1 : n), voted: i });
    actions.notify('award', 'gold', 'Đã ghi nhận phiếu bình chọn', `Bạn bình chọn cho ${GALA_TOP[i][0]} — mỗi người 1 phiếu (demo).`);
  },
  askChat(q) {
    const t = (q || '').trim();
    if (!t) return;
    setState({ chatLog: [...STATE.chatLog, { id: uid(), q: t, flow: matchChatFlow(t) }] });
  },
  setProfile(name, dharma) {
    setState({ name: (name || '').trim() || STATE.name, dharma: (dharma || '').trim() || STATE.dharma });
  },
  resetDemo() {
    Object.keys(DEED_TIMERS).forEach(k => { clearTimeout(DEED_TIMERS[k]); delete DEED_TIMERS[k]; });
    try { localStorage.removeItem('sdtd_cover'); localStorage.removeItem('sdtd_avatar'); } catch (e) {}
    STATE = seedState();
    saveState();
    LISTENERS.forEach(fn => { try { fn(STATE); } catch (e) {} });
    actions.notify('sparkle', 'gold', 'Chào mừng đến với demo Cây Bồ Đề', 'Dữ liệu demo đã được đặt lại về trạng thái ban đầu.');
  },
};
// reload trang khi còn deed chờ duyệt (persist) → lên lịch duyệt lại
try { STATE.deeds.filter(d => d.status === 'pending').forEach(d => actions.scheduleApproval(d.id)); } catch (e) {}

// ════════ HOME ════════
function HomeScreen({ nav }) {
  const s = useStore();
  const unread = unreadCount(s);
  const monthPct = Math.min(1, s.monthLeaves / MONTH_CAP);
  const capped = s.monthLeaves >= MONTH_CAP;
  const si = treeStage(s.leaves);
  const st = TREE_STAGES[si];
  const next = TREE_STAGES[si + 1];
  const treePct = next ? Math.min(1, (s.leaves - st.min) / (next.min - st.min)) : 1;
  const latestApproved = s.deeds.find(d => d.status === 'approved');
  const openProjects = s.projects.filter(p => !p.completed).slice(0, 2);
  // đếm ngược Giai đoạn Khởi Động — tính live, không hardcode số ngày/% (số này KHÔNG thuộc bộ số GHIM)
  const phaseLeft = Math.max(0, Math.ceil((PHASE_END - Date.now()) / 86400000));
  const phasePct = Math.max(0, Math.min(100, Math.round((Date.now() - PHASE_START) / (PHASE_END - PHASE_START) * 100)));
  return (
    <div style={{ paddingBottom: 110 }}>
      <TopBanner h={250}>
        <div style={{ padding: '0 22px' }}>
          <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
            <div>
              <p style={{ margin: 0, color: '#5a2a08', fontSize: 12.5, fontWeight: 700, whiteSpace: 'nowrap' }}>Nam mô A Di Đà Phật</p>
              <h1 style={{ margin: '3px 0 0', color: '#fff', fontSize: 26, fontWeight: 800 }}>{s.dharma}</h1>
            </div>
            <div onClick={() => nav && nav('notifications')} style={{ position: 'relative', width: 40, height: 40, borderRadius: 100, background: 'rgba(255,255,255,0.2)', display: 'flex', alignItems: 'center', justifyContent: 'center', cursor: 'pointer' }}>
              <Icon name="bell" size={20} color="#fff"/>
              {unread > 0 && <span style={{ position: 'absolute', top: 3, right: 3, minWidth: 16, height: 16, borderRadius: 100, background: '#e23b2e', color: '#fff', fontSize: 9.5, fontWeight: 800, display: 'flex', alignItems: 'center', justifyContent: 'center', padding: '0 4px', boxShadow: '0 0 0 2px #f59000' }}>{unread > 9 ? '9+' : unread}</span>}
            </div>
          </div>
          {/* balance — đọc store, cập nhật live */}
          <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginTop: 18 }}>
            <div>
              <p style={{ margin: 0, color: 'rgba(255,255,255,0.9)', fontSize: 13, fontWeight: 600 }}>Tổng Lá Bồ Đề</p>
              <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginTop: 4 }}>
                <span style={{ color: '#fff', fontSize: 44, fontWeight: 800, letterSpacing: '-0.03em' }}>{fmt(s.leaves)}</span>
                <Icon name="leaf" size={26} color="#fff" fill />
              </div>
            </div>
            <Ring pct={monthPct} value={String(s.monthLeaves)} label="tháng này" />
          </div>
        </div>
      </TopBanner>

      {/* pills overlapping — #214 GHIM (demo), 2 pill kia đọc store */}
      <div style={{ padding: '16px 22px 0', display: 'flex', gap: 10 }}>
        <Card onClick={() => nav && nav('gala')} style={{ flex: 1, textAlign: 'center', padding: '12px 0' }}><p style={{ margin: 0, color: C.faint, fontSize: 12 }}>Xếp hạng</p><p style={{ margin: '2px 0 0', color: C.saffronD, fontWeight: 800, fontSize: 18 }}>#{s.rank}</p></Card>
        <Card onClick={() => nav && nav('record')} style={{ flex: 1, textAlign: 'center', padding: '12px 0' }}><p style={{ margin: 0, color: C.faint, fontSize: 12 }}>Trần còn lại</p><p style={{ margin: '2px 0 0', color: C.saffronD, fontWeight: 800, fontSize: 18 }}>{Math.max(0, MONTH_CAP - s.monthLeaves)}</p></Card>
        <Card onClick={() => nav && nav('record')} style={{ flex: 1, textAlign: 'center', padding: '12px 0' }}><p style={{ margin: 0, color: C.faint, fontSize: 12 }}>Tháng này</p><p style={{ margin: '2px 0 0', color: C.saffronD, fontWeight: 800, fontSize: 18 }}>+{s.monthLeaves}</p></Card>
      </div>

      {/* trần Lá/tháng — cơ chế Phòng Ác (live từ store; nổi bật khi chạm trần) */}
      <div style={{ padding: '12px 22px 0' }}>
        <Card style={{ padding: '13px 16px', borderColor: capped ? C.saffron : C.line, background: capped ? '#fff6e6' : C.card }}>
          <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
            <span style={{ color: C.ink, fontSize: 12.5, fontWeight: 700, display: 'inline-flex', alignItems: 'center', gap: 6 }}><Icon name="shield" size={15} color={C.saffronD}/>{s.monthLeaves} / {MONTH_CAP} Lá tháng này</span>
            <span style={{ color: C.saffronD, fontSize: 12, fontWeight: 800 }}>{Math.round(monthPct * 100)}%</span>
          </div>
          <div style={{ marginTop: 9, height: 6, borderRadius: 100, background: 'rgba(245,144,0,0.14)', overflow: 'hidden' }}>
            <div style={{ width: `${Math.round(monthPct * 100)}%`, height: '100%', background: 'linear-gradient(90deg,#fbc117,#f59000)', transition: 'width .6s' }}/>
          </div>
          <p style={{ margin: '7px 0 0', fontSize: 11, color: capped ? C.saffronD : C.faint, fontWeight: capped ? 800 : 400 }}>
            {capped ? 'Đã chạm trần tháng — cơ chế Phòng Ác đang giữ thiện hành thuần vì tâm' : `Trần ${MONTH_CAP} Lá/tháng — cơ chế Phòng Ác`}
          </p>
        </Card>
      </div>

      {/* Thiện Tri Thức — hỏi chuyện đời, nhận lời kinh (mở ChatScreen — xem ghi chú điều hướng ở TabBar) */}
      <div style={{ padding: '14px 22px 0' }}>
        <Card onClick={() => nav && nav('chat')} style={{ display: 'flex', alignItems: 'center', gap: 12, padding: 15, background: 'linear-gradient(135deg,#fff6e3,#ffe9bf)', borderColor: 'rgba(245,144,0,0.3)' }}>
          <div style={{ width: 42, height: 42, borderRadius: 12, background: 'rgba(245,144,0,0.14)', display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 22, flexShrink: 0 }}>🪷</div>
          <div style={{ flex: 1, minWidth: 0 }}>
            <p style={{ margin: 0, color: C.ink, fontSize: 14.5, fontWeight: 800 }}>Thiện Tri Thức</p>
            <p style={{ margin: '2px 0 0', color: C.soft, fontSize: 12, lineHeight: 1.45 }}>Hỏi chuyện đời, nhận lời kinh — bạn tự đọc, tự chiêm nghiệm</p>
          </div>
          <span style={{ color: C.saffron }}><Icon name="chevron" size={18}/></span>
        </Card>
      </div>

      {/* cây bồ đề — đổi hình theo cấp (6 mức), nhãn cấp + tiến độ lên cấp kế */}
      <div style={{ padding: '14px 22px 0' }}>
        <Card style={{ padding: 0, overflow: 'hidden' }}>
          <div style={{ display: 'flex', gap: 8, alignItems: 'stretch' }}>
            <div style={{ width: 150, flexShrink: 0, background: 'linear-gradient(180deg,#fffaf0,#fff3d6)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
              <BodhiTree leaf={s.leaves} size={150} />
            </div>
            <div style={{ flex: 1, padding: '16px 16px 16px 4px', display: 'flex', flexDirection: 'column', justifyContent: 'center' }}>
              <p style={{ margin: 0, color: C.faint, fontSize: 11.5, fontWeight: 700, textTransform: 'uppercase', letterSpacing: '.05em' }}>Cây Bồ Đề của bạn</p>
              <p style={{ margin: '3px 0 0', color: C.ink, fontSize: 18, fontWeight: 800 }}>Cấp {si + 1}/6 · {st.key}</p>
              <p style={{ margin: '6px 0 0', color: C.soft, fontSize: 12, lineHeight: 1.5 }}>{st.desc}</p>
              <div style={{ marginTop: 10, height: 6, borderRadius: 100, background: 'rgba(245,144,0,0.14)', overflow: 'hidden' }}>
                <div style={{ width: `${Math.round(treePct * 100)}%`, height: '100%', background: 'linear-gradient(90deg,#fbc117,#f59000)', transition: 'width .6s' }}/>
              </div>
              <p style={{ margin: '7px 0 0', fontSize: 11, color: C.faint }}>
                {next ? <span>Còn <b style={{ color: C.saffronD }}>{fmt(next.min - s.leaves)} Lá</b> để lên cấp {si + 2} · {next.key}</span> : <span><b style={{ color: C.saffronD }}>Cây đã viên mãn</b> — lành thay!</span>}
              </p>
            </div>
          </div>
        </Card>
      </div>

      {/* campaign phase */}
      <div style={{ padding: '14px 22px 0' }}>
        <Card style={{ padding: 16, background: 'linear-gradient(135deg,#fff6e3,#ffe9bf)', borderColor: 'rgba(245,144,0,0.28)' }}>
          <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
            <span style={{ display: 'inline-flex', alignItems: 'center', gap: 6, color: C.saffronD, fontWeight: 800, fontSize: 13 }}><Icon name="calendar" size={16}/> Giai đoạn: Khởi Động</span>
            <span style={{ fontSize: 11.5, color: C.faint, fontWeight: 700 }}>T3 – T9 / 2026</span>
          </div>
          <p style={{ margin: '8px 0 0', color: C.soft, fontSize: 12.5, lineHeight: 1.5 }}>Đang nhận hồ sơ & ghi nhận tiến độ dự án. Điểm tiếp tục tích lũy.</p>
          <div style={{ marginTop: 10, height: 6, borderRadius: 100, background: 'rgba(245,144,0,0.16)', overflow: 'hidden' }}><div style={{ width: `${phasePct}%`, height: '100%', background: 'linear-gradient(90deg,#fbc117,#f59000)' }}/></div>
          <p style={{ margin: '8px 0 0', fontSize: 11.5, color: C.faint }}>Đóng sổ <b style={{ color: C.saffronD }}>30/9/2026</b> · {phaseLeft > 0 ? <span>còn <b style={{ color: C.saffronD }}>{phaseLeft} ngày</b></span> : <b style={{ color: C.saffronD }}>đã đóng sổ</b>}</p>
        </Card>
      </div>

      {/* quick actions */}
      <div style={{ padding: '12px 22px 0', display: 'flex', gap: 10 }}>
        <Card onClick={() => nav && nav('checkin')} style={{ flex: 1, display: 'flex', alignItems: 'center', gap: 11, padding: 14 }}>
          <div style={{ width: 38, height: 38, borderRadius: 11, background: 'rgba(245,144,0,0.12)', display: 'flex', alignItems: 'center', justifyContent: 'center', color: C.saffronD }}><Icon name="temple" size={20}/></div>
          <div><p style={{ margin: 0, color: C.ink, fontSize: 13.5, fontWeight: 700 }}>Check-in</p><p style={{ margin: 0, color: C.faint, fontSize: 11.5 }}>Tích lũy Lá</p></div>
        </Card>
        <Card onClick={() => nav && nav('connect')} style={{ flex: 1, display: 'flex', alignItems: 'center', gap: 11, padding: 14 }}>
          <div style={{ width: 38, height: 38, borderRadius: 11, background: 'rgba(245,144,0,0.12)', display: 'flex', alignItems: 'center', justifyContent: 'center', color: C.saffronD }}><Icon name="connect" size={20}/></div>
          <div><p style={{ margin: 0, color: C.ink, fontSize: 13.5, fontWeight: 700 }}>Cầu Nối</p><p style={{ margin: 0, color: C.faint, fontSize: 11.5 }}>Gieo duyên lành</p></div>
        </Card>
      </div>

      {/* đang cần hỗ trợ — đọc projects từ store */}
      <div style={{ padding: '22px 22px 0' }}>
        <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 12 }}>
          <p style={{ margin: 0, color: C.ink, fontSize: 16, fontWeight: 800 }}>Đang cần hỗ trợ</p>
          <span onClick={() => nav && nav('connect')} style={{ color: C.saffronD, fontSize: 13, fontWeight: 700, cursor: 'pointer' }}>Xem tất cả ›</span>
        </div>
        <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
          {openProjects.map(p => (
            <Card key={p.id} onClick={() => nav && nav('connect')} style={{ display: 'flex', alignItems: 'center', gap: 12, padding: 14 }}>
              <div style={{ width: 38, height: 38, borderRadius: 11, background: C.card2, display: 'flex', alignItems: 'center', justifyContent: 'center', color: C.saffronD }}><Icon name={p.ic} size={19}/></div>
              <div style={{ flex: 1, minWidth: 0 }}>
                <p style={{ margin: 0, color: C.ink, fontSize: 13.5, fontWeight: 600, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{p.t}</p>
                <p style={{ margin: 0, color: C.faint, fontSize: 11.5 }}>{p.joined ? `Đang tham gia · ${p.milestones.filter(m => m.done).length}/${p.milestones.length} mốc` : p.org}</p>
              </div>
              <span style={{ color: C.saffronD, fontWeight: 800, fontSize: 13, whiteSpace: 'nowrap', display: 'inline-flex', alignItems: 'center', gap: 3 }}>~{p.milestones.filter(m => !m.done).reduce((a, m) => a + m.leaf, 0)}<Icon name="leaf" size={13} color={C.saffron} fill/></span>
            </Card>
          ))}
        </div>
      </div>

      {/* verify chip — hiện xác thực mới nhất từ store (fallback seed) */}
      <div style={{ padding: '12px 22px 0' }}>
        <Card onClick={() => nav && nav('record')} style={{ display: 'flex', alignItems: 'center', gap: 12, padding: 14, borderColor: 'rgba(245,144,0,0.3)' }}>
          <div style={{ width: 38, height: 38, borderRadius: 12, background: 'rgba(245,144,0,0.12)', display: 'flex', alignItems: 'center', justifyContent: 'center', color: C.saffron }}><Icon name="check" size={20}/></div>
          <div style={{ flex: 1 }}>
            <p style={{ margin: 0, color: C.ink, fontSize: 14, fontWeight: 700 }}>Đã được chùa xác thực</p>
            <p style={{ margin: 0, color: C.faint, fontSize: 12 }}>{latestApproved ? `${latestApproved.t} · hôm nay` : 'Chùa Hoằng Pháp · 09:41 hôm nay'}</p>
          </div>
          <span style={{ color: C.saffron }}><Icon name="chevron" size={18}/></span>
        </Card>
      </div>

      {/* recent — lịch sử Lá từ store */}
      <div style={{ padding: '22px 22px 0' }}>
        <p style={{ margin: '0 0 12px', color: C.ink, fontSize: 16, fontWeight: 800 }}>Thiện hành gần đây</p>
        <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
          {s.history.slice(0, 4).map(a => (
            <Card key={a.id} style={{ display: 'flex', alignItems: 'center', gap: 12, padding: 14 }}>
              <div style={{ width: 38, height: 38, borderRadius: 11, background: C.card2, display: 'flex', alignItems: 'center', justifyContent: 'center', color: C.saffronD }}><Icon name={a.ic} size={19}/></div>
              <div style={{ flex: 1, minWidth: 0 }}>
                <p style={{ margin: 0, color: C.ink, fontSize: 13.5, fontWeight: 600, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{a.t}</p>
                <p style={{ margin: 0, color: C.faint, fontSize: 11.5 }}>{a.date}</p>
              </div>
              <span style={{ color: C.saffronD, fontWeight: 800, fontSize: 14, whiteSpace: 'nowrap', display: 'inline-flex', alignItems: 'center', gap: 3 }}>+{a.leaf}<Icon name="leaf" size={13} color={C.saffron} fill/></span>
            </Card>
          ))}
        </div>
      </div>
    </div>
  );
}

// ════════ CHECK-IN ════════
const NEARBY_TEMPLES = [['Chùa Quán Sứ', '0.4 km', 'Hà Nội'], ['Chùa Trấn Quốc', '1.2 km', 'Tây Hồ'], ['Chùa Hương Sắc', '3.8 km', 'Hà Đông']];

function CheckInScreen({ nav }) {
  const s = useStore();
  const [active, setActive] = useState(null);     // temple name → view chi tiết
  const [phase, setPhase] = useState('idle');     // idle | qr | gps
  const [gpsDone, setGpsDone] = useState(false);
  const [success, setSuccess] = useState(null);   // { name, granted }
  const [toast, setToast] = useState(null);
  const timers = useRef([]);
  useEffect(() => () => { timers.current.forEach(clearTimeout); }, []); // clear mọi timer khi unmount
  const later = (fn, ms) => { timers.current.push(setTimeout(fn, ms)); };
  const showToast = msg => { setToast(msg); later(() => setToast(null), 2800); };

  function tryCheckIn(name) {
    const r = actions.checkIn(name);
    if (!r.ok) { showToast('Hôm nay bạn đã check-in chùa này — hẹn ngày mai nhé.'); return false; }
    setSuccess({ name, granted: r.granted });
    return true;
  }
  function startQR() {
    if (phase !== 'idle') return;
    setSuccess(null);
    setPhase('qr');
    later(() => {
      setPhase('idle');
      const day = todayKey();
      const pick = NEARBY_TEMPLES.find(t => !STATE.checkins.some(c => c.name === t[0] && c.day === day));
      if (!pick) { showToast('Hôm nay bạn đã check-in cả 3 chùa lân cận.'); return; }
      tryCheckIn(pick[0]);
    }, 1500); // demo quét 1.5s
  }
  function startGPS() {
    if (phase !== 'idle') return;
    setSuccess(null);
    setPhase('gps');
    later(() => { setPhase('idle'); setGpsDone(true); }, 1300); // demo định vị 1.3s
  }

  // ── temple detail (sau check-in / từ lịch sử) ──
  if (active) {
    const info = TEMPLE_INFO[active];
    return (
      <div style={{ paddingBottom: 110 }}>
        <div style={{ position: 'relative', background: 'linear-gradient(165deg,#ffd35e 0%, #f59000 60%, #e07700 100%)', borderRadius: '0 0 26px 26px', paddingTop: 54, paddingBottom: 20, color: '#fff' }}>
          <div style={{ padding: '0 22px' }}>
            <button onClick={() => setActive(null)} style={{ background: 'rgba(255,255,255,0.2)', border: 0, color: '#fff', borderRadius: 100, padding: '6px 14px', fontSize: 12.5, fontWeight: 700, cursor: 'pointer', fontFamily: F, display: 'inline-flex', alignItems: 'center', gap: 5 }}>‹ Chùa lân cận</button>
            <div style={{ display: 'inline-flex', alignItems: 'center', gap: 6, background: 'rgba(255,255,255,0.22)', borderRadius: 100, padding: '5px 12px', marginLeft: 8, fontSize: 12, fontWeight: 700 }}><Icon name="check" size={14} color="#fff"/> Đã check-in</div>
            <h1 style={{ margin: '14px 0 0', color: '#fff', fontSize: 25, fontWeight: 800 }}>{active}</h1>
            <p style={{ margin: '4px 0 0', color: 'rgba(255,255,255,0.92)', fontSize: 13, display: 'inline-flex', alignItems: 'center', gap: 5 }}><Icon name="pin" size={14}/>{info.address} · {info.place}</p>
            <p style={{ margin: '3px 0 0', color: 'rgba(255,255,255,0.85)', fontSize: 11.5 }}>Check-in để tìm hiểu chùa và nhận việc Cầu Nối</p>
          </div>
        </div>

        {/* temple info */}
        <div style={{ padding: '16px 22px 0' }}>
          <Card style={{ padding: 16 }}>
            <p style={{ margin: 0, color: C.soft, fontSize: 13, lineHeight: 1.55 }}>{info.desc}</p>
            <div style={{ display: 'flex', gap: 10, marginTop: 14 }}>
              <div style={{ flex: 1, textAlign: 'center', background: C.card2, borderRadius: 12, padding: '10px 4px' }}><p style={{ margin: 0, color: C.saffronD, fontWeight: 800, fontSize: 15 }}>{info.founded}</p><p style={{ margin: 0, color: C.faint, fontSize: 11 }}>Năm dựng</p></div>
              <div style={{ flex: 1, textAlign: 'center', background: C.card2, borderRadius: 12, padding: '10px 4px' }}><p style={{ margin: 0, color: C.saffronD, fontWeight: 800, fontSize: 15 }}>{info.members}</p><p style={{ margin: 0, color: C.faint, fontSize: 11 }}>Phật tử</p></div>
              <div style={{ flex: 1, textAlign: 'center', background: C.card2, borderRadius: 12, padding: '10px 4px' }}><p style={{ margin: 0, color: C.saffronD, fontWeight: 800, fontSize: 15 }}>{info.acts.length}</p><p style={{ margin: 0, color: C.faint, fontSize: 11 }}>Dự án / sự kiện</p></div>
            </div>
          </Card>
        </div>

        {/* activities — "Thêm Cầu Nối" ghi vào store.connectTasks */}
        <div style={{ padding: '20px 22px 0' }}>
          <p style={{ margin: '0 0 4px', color: C.ink, fontSize: 16, fontWeight: 800 }}>Dự án &amp; sự kiện đang &amp; sắp mở</p>
          <p style={{ margin: '0 0 14px', color: C.faint, fontSize: 12.5 }}>Thêm vào danh sách Cầu Nối để nhận việc và đóng góp</p>
          <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
            {info.acts.map(a => {
              const isJoined = s.connectTasks.some(x => x.t === a.t);
              return (
                <Card key={a.t} style={{ padding: 15 }}>
                  <div style={{ display: 'flex', gap: 12 }}>
                    <div style={{ width: 40, height: 40, borderRadius: 11, background: C.card2, display: 'flex', alignItems: 'center', justifyContent: 'center', color: C.saffronD, flexShrink: 0 }}><Icon name={a.ic} size={20}/></div>
                    <div style={{ flex: 1, minWidth: 0 }}>
                      <p style={{ margin: 0, color: C.ink, fontSize: 14.5, fontWeight: 700, lineHeight: 1.3 }}>{a.t}</p>
                      <div style={{ display: 'flex', gap: 6, marginTop: 5, flexWrap: 'wrap' }}>
                        <span style={{ fontSize: 10.5, fontWeight: 700, color: C.saffronD, background: 'rgba(245,144,0,0.12)', padding: '3px 9px', borderRadius: 100 }}>{a.type}</span>
                        <span style={{ fontSize: 10.5, fontWeight: 700, color: a.status === 'open' ? '#3f8a3f' : '#9a7c52', background: a.status === 'open' ? 'rgba(63,138,63,0.12)' : 'rgba(154,124,82,0.12)', padding: '3px 9px', borderRadius: 100 }}>{a.status === 'open' ? '● Đang mở' : '○ Sắp mở'}</span>
                      </div>
                    </div>
                  </div>
                  <div style={{ marginTop: 12, display: 'flex', flexDirection: 'column', gap: 7 }}>
                    <p style={{ margin: 0, color: C.soft, fontSize: 12.5, display: 'flex', alignItems: 'flex-start', gap: 7 }}><span style={{ color: C.saffronD, flexShrink: 0, marginTop: 1 }}><Icon name="check" size={14}/></span>Yêu cầu: {a.req}</p>
                    <p style={{ margin: 0, color: C.soft, fontSize: 12.5, display: 'flex', alignItems: 'center', gap: 7 }}><span style={{ color: C.saffronD }}><Icon name="clock" size={14}/></span>Hạn: <b style={{ color: C.ink }}>{a.due}</b></p>
                  </div>
                  <div style={{ marginTop: 13, display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
                    <span style={{ color: C.saffronD, fontWeight: 800, fontSize: 14, display: 'inline-flex', alignItems: 'center', gap: 3 }}>+{a.leaf}<Icon name="leaf" size={14} color={C.saffron} fill/></span>
                    <button onClick={() => { isJoined ? actions.removeConnectTask(a.t) : actions.addConnectTask(active, a); }}
                      style={{ border: isJoined ? `1px solid ${C.saffron}` : 0, background: isJoined ? '#fff6e6' : 'linear-gradient(135deg,#fbc117,#f59000)', color: isJoined ? C.saffronD : '#5a2a08', fontWeight: 800, fontSize: 12.5, padding: '9px 16px', borderRadius: 100, cursor: 'pointer', fontFamily: F }}>
                      {isJoined ? '✓ Đã thêm Cầu Nối' : '+ Thêm Cầu Nối'}
                    </button>
                  </div>
                </Card>
              );
            })}
          </div>
        </div>
      </div>
    );
  }

  // ── default: scanner + GPS + nearby + lịch sử ──
  return (
    <div style={{ paddingBottom: 110 }}>
      <Header sub="Tìm hiểu chùa & nhận việc Cầu Nối" title="Check-in" back={() => nav && nav('home')} />
      <div style={{ padding: '0 22px 4px' }}>
        <Card style={{ padding: 13, background: 'linear-gradient(135deg,#fff6e3,#ffe9bf)', borderColor: 'rgba(245,144,0,0.28)' }}>
          <p style={{ margin: 0, color: C.soft, fontSize: 12.5, lineHeight: 1.55 }}>Check-in tại chùa để <b style={{ color: C.saffronD }}>tìm hiểu thông tin chùa</b>, nhận <b style={{ color: C.saffronD }}>+2 Lá Bồ Đề</b> và xem các dự án chùa đang &amp; sắp mở — thêm vào <b style={{ color: C.saffronD }}>Cầu Nối</b> để nhận việc.</p>
        </Card>
      </div>

      {/* toast nhẹ (chặn check-in trùng trong ngày) */}
      {toast && (
        <div style={{ padding: '10px 22px 0' }}>
          <Card style={{ padding: '11px 14px', borderColor: C.saffron, background: '#fff6e6', display: 'flex', alignItems: 'center', gap: 9 }}>
            <span style={{ color: C.saffronD, flexShrink: 0 }}><Icon name="bell" size={16}/></span>
            <p style={{ margin: 0, color: C.saffronD, fontSize: 12.5, fontWeight: 700 }}>{toast}</p>
          </Card>
        </div>
      )}

      {/* thành công */}
      {success && (
        <div style={{ padding: '10px 22px 0' }}>
          <Card style={{ padding: 18, textAlign: 'center', borderColor: 'rgba(63,138,63,0.4)' }}>
            <div style={{ width: 52, height: 52, borderRadius: 100, margin: '0 auto 10px', background: 'rgba(63,138,63,0.12)', display: 'flex', alignItems: 'center', justifyContent: 'center', color: '#3f8a3f' }}><Icon name="check" size={26}/></div>
            <p style={{ margin: 0, color: C.ink, fontSize: 16, fontWeight: 800 }}>Check-in thành công · {success.name}</p>
            <p style={{ margin: '5px 0 0', color: C.soft, fontSize: 13 }}>{success.granted > 0 ? <span>Bạn nhận <b style={{ color: C.saffronD }}>+{success.granted} Lá Bồ Đề</b></span> : 'Đã chạm trần tháng — Lá không cộng thêm (Phòng Ác)'}</p>
            <div style={{ marginTop: 14, display: 'flex', gap: 8, justifyContent: 'center' }}>
              <button onClick={() => { const n = success.name; setSuccess(null); setActive(n); }} style={{ border: 'none', background: 'linear-gradient(135deg,#fbc117,#f59000)', color: '#5a2a08', fontWeight: 800, fontSize: 12.5, padding: '10px 18px', borderRadius: 100, cursor: 'pointer', fontFamily: F, boxShadow: '0 8px 20px rgba(245,144,0,0.3)' }}>Khám phá chùa ›</button>
              <button onClick={() => setSuccess(null)} style={{ border: `1px solid ${C.line}`, background: C.card, color: C.soft, fontWeight: 700, fontSize: 12.5, padding: '10px 16px', borderRadius: 100, cursor: 'pointer', fontFamily: F }}>Đóng</button>
            </div>
          </Card>
        </div>
      )}

      {/* QR scanner — bấm "Quét QR" để chạy demo 1.5s */}
      <div style={{ padding: '12px 22px 0' }}>
        <Card style={{ padding: 0, overflow: 'hidden', borderColor: phase === 'qr' ? C.saffron : 'rgba(245,144,0,0.3)' }}>
          <div style={{ height: 210, position: 'relative', background: 'linear-gradient(165deg,#fff3d6,#ffe1a8)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
            <div style={{ width: 140, height: 140, borderRadius: 18, position: 'relative' }}>
              {[[0,0],[0,1],[1,0],[1,1]].map((p,i) => (
                <span key={i} style={{ position: 'absolute', width: 26, height: 26, borderColor: C.saffron, borderStyle: 'solid',
                  borderWidth: `${p[0]?0:3}px ${p[1]?3:0}px ${p[0]?3:0}px ${p[1]?0:3}px`,
                  top: p[0]?'auto':0, bottom: p[0]?0:'auto', left: p[1]?'auto':0, right: p[1]?0:'auto', borderRadius: 6 }}/>
              ))}
              <div style={{ position: 'absolute', inset: 0, display: 'flex', alignItems: 'center', justifyContent: 'center', color: 'rgba(245,144,0,0.4)', opacity: phase === 'qr' ? 0.45 : 1, transition: 'opacity .3s' }}><Icon name="qr" size={60} color={C.saffron}/></div>
              {phase === 'qr' && <div style={{ position: 'absolute', left: 8, right: 8, top: '50%', height: 2, background: C.saffron, boxShadow: '0 0 12px #f59000', borderRadius: 2 }}/>}
            </div>
            <span style={{ position: 'absolute', bottom: 12, color: C.soft, fontSize: 12, fontWeight: 600 }}>{phase === 'qr' ? 'Đang quét mã QR của chùa…' : 'Quét mã QR đặt tại cổng chùa để check-in'}</span>
          </div>
          <div style={{ padding: '12px 14px 14px', display: 'flex', gap: 9 }}>
            <button onClick={startQR} disabled={phase !== 'idle'} style={{ flex: 1, border: 'none', background: phase === 'qr' ? '#fff6e6' : 'linear-gradient(135deg,#fbc117,#f59000)', color: phase === 'qr' ? C.saffronD : '#5a2a08', fontWeight: 800, fontSize: 13.5, padding: '12px 0', borderRadius: 100, cursor: phase === 'idle' ? 'pointer' : 'default', fontFamily: F, boxShadow: phase === 'qr' ? 'none' : '0 8px 20px rgba(245,144,0,0.3)', display: 'inline-flex', alignItems: 'center', justifyContent: 'center', gap: 7 }}>
              <Icon name="qr" size={16} color={phase === 'qr' ? C.saffronD : '#5a2a08'}/>{phase === 'qr' ? 'Đang quét…' : 'Quét QR'}
            </button>
            <button onClick={startGPS} disabled={phase !== 'idle'} style={{ flex: 1, border: `1px solid ${C.saffron}`, background: '#fff6e6', color: C.saffronD, fontWeight: 800, fontSize: 13.5, padding: '12px 0', borderRadius: 100, cursor: phase === 'idle' ? 'pointer' : 'default', fontFamily: F, display: 'inline-flex', alignItems: 'center', justifyContent: 'center', gap: 7 }}>
              <Icon name="pin" size={16} color={C.saffronD}/>{phase === 'gps' ? 'Đang định vị…' : 'Check-in GPS'}
            </button>
          </div>
        </Card>
      </div>

      {/* nearby — chọn 1 chùa để check-in (chặn trùng trong ngày) */}
      <div style={{ padding: '20px 22px 0' }}>
        <p style={{ margin: '0 0 12px', color: C.ink, fontSize: 16, fontWeight: 800, display: 'flex', alignItems: 'center', gap: 8 }}>
          Chùa lân cận
          {gpsDone && <span style={{ display: 'inline-flex', alignItems: 'center', gap: 4, fontSize: 10.5, fontWeight: 700, color: '#3f8a3f', background: 'rgba(63,138,63,0.12)', padding: '3px 9px', borderRadius: 100 }}><Icon name="pin" size={12}/>Đã định vị GPS</span>}
        </p>
        <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
          {NEARBY_TEMPLES.map(t => {
            const doneToday = s.checkins.some(c => c.name === t[0] && c.day === todayKey());
            return (
              <Card key={t[0]} onClick={() => doneToday ? setActive(t[0]) : tryCheckIn(t[0])} style={{ display: 'flex', alignItems: 'center', gap: 12, padding: 14, cursor: 'pointer' }}>
                <div style={{ width: 40, height: 40, borderRadius: 12, background: C.card2, display: 'flex', alignItems: 'center', justifyContent: 'center', color: C.saffronD }}><Icon name="temple" size={20}/></div>
                <div style={{ flex: 1 }}>
                  <p style={{ margin: 0, color: C.ink, fontSize: 14, fontWeight: 700 }}>{t[0]}</p>
                  <p style={{ margin: 0, color: C.faint, fontSize: 12 }}>{t[2]} · {t[1]}</p>
                </div>
                {doneToday
                  ? <span style={{ display: 'inline-flex', alignItems: 'center', gap: 4, color: '#3f8a3f', background: 'rgba(63,138,63,0.12)', fontWeight: 700, fontSize: 11.5, padding: '7px 13px', borderRadius: 100 }}><Icon name="check" size={13}/>Hôm nay ✓</span>
                  : <span style={{ background: 'linear-gradient(135deg,#fbc117,#f59000)', padding: '8px 16px', borderRadius: 100, fontSize: 12.5, fontWeight: 800, color: '#5a2a08' }}>Check-in</span>}
              </Card>
            );
          })}
        </div>
      </div>

      {/* lịch sử check-in — từ store */}
      <div style={{ padding: '20px 22px 0' }}>
        <p style={{ margin: '0 0 12px', color: C.ink, fontSize: 16, fontWeight: 800 }}>Lịch sử check-in</p>
        <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
          {s.checkins.map(c => (
            <Card key={c.id} onClick={() => TEMPLE_INFO[c.name] ? setActive(c.name) : null} style={{ display: 'flex', alignItems: 'center', gap: 12, padding: 13 }}>
              <div style={{ width: 38, height: 38, borderRadius: 11, background: C.card2, display: 'flex', alignItems: 'center', justifyContent: 'center', color: C.saffronD }}><Icon name="temple" size={18}/></div>
              <div style={{ flex: 1, minWidth: 0 }}>
                <p style={{ margin: 0, color: C.ink, fontSize: 13.5, fontWeight: 700 }}>{c.name}</p>
                <p style={{ margin: 0, color: C.faint, fontSize: 11.5 }}>{c.place} · {c.date}</p>
              </div>
              <span style={{ display: 'inline-flex', alignItems: 'center', gap: 4, color: '#3f8a3f', background: 'rgba(63,138,63,0.12)', fontWeight: 700, fontSize: 11.5, padding: '5px 11px', borderRadius: 100 }}><Icon name="check" size={13}/>Đã đến</span>
            </Card>
          ))}
        </div>
      </div>
    </div>
  );
}

// ════════ RECORD ════════
// 11 loại thiện hành — gửi → "Đang chờ xác thực" → auto-demo 4s sau
// Trụ trì xác thực ✓ + cộng Lá (qua trần tháng nếu chạm Phòng Ác).
function RecordScreen() {
  const s = useStore();
  const [sel, setSel] = useState(0);
  const [approver, setApprover] = useState('temple');
  const [evidence, setEvidence] = useState(false);   // demo: đính kèm minh chứng
  const [sentId, setSentId] = useState(null);        // id deed vừa gửi → view xác nhận live
  const remaining = Math.max(0, MONTH_CAP - s.monthLeaves);
  const approvers = [
    { key: 'temple', ic: 'temple', t: 'Trụ trì chùa xác nhận', d: 'Phù hợp hoạt động tại chùa bạn sinh hoạt' },
    { key: 'council', ic: 'shield', t: 'Hội đồng Ban Văn hóa TƯ xét duyệt', d: 'Cho tác phẩm, dự án quy mô lớn' },
  ];

  const deedList = s.deeds.length > 0 && (
    <div style={{ padding: '22px 22px 0' }}>
      <p style={{ margin: '0 0 4px', color: C.ink, fontSize: 15, fontWeight: 800 }}>Ghi nhận của bạn</p>
      <p style={{ margin: '0 0 12px', color: C.faint, fontSize: 12 }}>Demo: chùa xác thực tự động sau vài giây</p>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
        {s.deeds.map(d => (
          <Card key={d.id} style={{ display: 'flex', alignItems: 'center', gap: 12, padding: 13 }}>
            <div style={{ width: 38, height: 38, borderRadius: 11, background: C.card2, display: 'flex', alignItems: 'center', justifyContent: 'center', color: C.saffronD, flexShrink: 0 }}><Icon name={d.ic} size={18}/></div>
            <div style={{ flex: 1, minWidth: 0 }}>
              <p style={{ margin: 0, color: C.ink, fontSize: 13, fontWeight: 700, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{d.t}</p>
              <p style={{ margin: '2px 0 0', color: C.faint, fontSize: 11 }}>{d.time} hôm nay{d.evidence ? ' · có minh chứng' : ''}</p>
            </div>
            {d.status === 'pending'
              ? <span style={{ display: 'inline-flex', alignItems: 'center', gap: 4, color: C.saffronD, background: 'rgba(245,144,0,0.12)', fontWeight: 700, fontSize: 11, padding: '5px 10px', borderRadius: 100, whiteSpace: 'nowrap' }}><Icon name="clock" size={12}/>Chờ xác thực</span>
              : <span style={{ display: 'inline-flex', alignItems: 'center', gap: 4, color: '#3f8a3f', background: 'rgba(63,138,63,0.12)', fontWeight: 700, fontSize: 11, padding: '5px 10px', borderRadius: 100, whiteSpace: 'nowrap' }}><Icon name="check" size={12}/>{d.granted > 0 ? `Đã duyệt +${d.granted}` : 'Đã duyệt · trần tháng'}</span>}
          </Card>
        ))}
      </div>
    </div>
  );

  if (sentId) {
    const deed = s.deeds.find(d => d.id === sentId);
    const approved = deed && deed.status === 'approved';
    const ap = approvers.find(a => a.key === approver);
    return (
      <div style={{ paddingBottom: 120 }}>
        <Header sub="Ghi nhận công khai — minh bạch" title="Thiện hành" />
        <div style={{ padding: '8px 22px 0' }}>
          <Card style={{ padding: 24, textAlign: 'center' }}>
            <div style={{ width: 64, height: 64, borderRadius: 100, margin: '0 auto 14px', background: approved ? 'rgba(63,138,63,0.12)' : 'rgba(245,144,0,0.14)', display: 'flex', alignItems: 'center', justifyContent: 'center', color: approved ? '#3f8a3f' : C.saffronD, transition: 'all .4s' }}><Icon name={approved ? 'check' : 'clock'} size={32}/></div>
            <p style={{ margin: 0, color: C.ink, fontSize: 18, fontWeight: 800 }}>{approved ? 'Trụ trì đã xác thực ✓' : 'Đã gửi ghi nhận'}</p>
            <p style={{ margin: '8px 0 0', color: C.soft, fontSize: 13.5, lineHeight: 1.55 }}>
              {approved
                ? (deed.granted > 0
                    ? <span>Thiện hành <b>{deed.t}</b> đã được duyệt — bạn nhận <b style={{ color: C.saffronD }}>+{deed.granted} Lá Bồ Đề</b>.</span>
                    : <span>Thiện hành <b>{deed.t}</b> đã được duyệt — <b style={{ color: C.saffronD }}>đã chạm trần tháng, Lá sẽ tính sang tháng sau</b>.</span>)
                : <span>Thiện hành <b>{deed ? deed.t : ''}</b> của bạn đang chờ <b style={{ color: C.saffronD }}>{ap.t.replace(' xác nhận', '').replace(' xét duyệt', '')}</b> {approver === 'temple' ? 'xác nhận' : 'xét duyệt'}.</span>}
            </p>
            <div style={{ marginTop: 16, padding: '12px 14px', background: approved ? 'rgba(63,138,63,0.08)' : C.card2, borderRadius: 12, display: 'flex', alignItems: 'center', gap: 10, textAlign: 'left' }}>
              <span style={{ width: 34, height: 34, borderRadius: 9, background: approved ? 'rgba(63,138,63,0.14)' : 'rgba(245,144,0,0.14)', display: 'flex', alignItems: 'center', justifyContent: 'center', color: approved ? '#3f8a3f' : C.saffronD, flexShrink: 0 }}><Icon name={approved ? 'check' : 'clock'} size={18}/></span>
              <div>
                <p style={{ margin: 0, color: C.ink, fontSize: 13, fontWeight: 700 }}>Trạng thái: {approved ? (deed.granted > 0 ? 'Đã xác thực — Lá đã cộng' : 'Đã xác thực — đã chạm trần tháng') : 'Chờ chùa xác thực minh chứng'}</p>
                <p style={{ margin: 0, color: C.faint, fontSize: 11.5 }}>{deed && deed.evidence ? 'Đã đính kèm demo_minhchung.jpg · ' : ''}{approved ? (deed.granted > 0 ? 'Xem Trang chủ & Hồ sơ để thấy Lá cập nhật' : 'Trần 500 Lá/tháng (Phòng Ác) — Lá sẽ tính sang tháng sau') : 'Lá Bồ Đề được cộng sau khi được duyệt (demo: ~4 giây)'}</p>
              </div>
            </div>
            <button onClick={() => { setSentId(null); setEvidence(false); }} style={{ marginTop: 18, border: `1px solid ${C.saffron}`, background: '#fff6e6', color: C.saffronD, fontWeight: 800, fontSize: 14, padding: '12px 24px', borderRadius: 100, cursor: 'pointer', fontFamily: F }}>Ghi nhận hoạt động khác</button>
          </Card>
        </div>
        {deedList}
      </div>
    );
  }

  return (
    <div style={{ paddingBottom: 130 }}>
      <Header sub="Ghi nhận công khai — minh bạch" title="Thiện hành" />

      {/* trần tháng còn lại — Phòng Ác */}
      <div style={{ padding: '0 22px 12px' }}>
        <Card style={{ padding: '11px 15px', display: 'flex', alignItems: 'center', gap: 9, borderColor: remaining === 0 ? C.saffron : C.line, background: remaining === 0 ? '#fff6e6' : C.card }}>
          <span style={{ color: C.saffronD, flexShrink: 0 }}><Icon name="shield" size={17}/></span>
          <p style={{ margin: 0, color: remaining === 0 ? C.saffronD : C.soft, fontSize: 12.5, fontWeight: 700 }}>
            {remaining === 0 ? 'Đã chạm trần 500 Lá/tháng — Lá mới không cộng thêm (Phòng Ác)' : <span>Còn <b style={{ color: C.saffronD }}>{remaining} Lá</b> trong trần {MONTH_CAP} Lá/tháng (Phòng Ác)</span>}
          </p>
        </Card>
      </div>

      {/* 11 loại thiện hành (khớp 11 lĩnh vực hệ thống) */}
      <div style={{ padding: '0 22px', display: 'flex', flexDirection: 'column', gap: 10 }}>
        {DEED_TYPES.map((t, i) => (
          <Card key={t[1]} onClick={() => setSel(i)} style={{
            display: 'flex', alignItems: 'center', gap: 13, padding: 15,
            borderColor: sel === i ? C.saffron : C.line,
            background: sel === i ? '#fff6e6' : C.card,
          }}>
            <div style={{ width: 42, height: 42, borderRadius: 12, background: sel===i?'rgba(245,144,0,0.14)':C.card2, display: 'flex', alignItems: 'center', justifyContent: 'center', color: C.saffronD }}><Icon name={t[0]} size={21}/></div>
            <div style={{ flex: 1 }}>
              <p style={{ margin: 0, color: C.ink, fontSize: 14.5, fontWeight: 700 }}>{t[1]}</p>
              <p style={{ margin: 0, color: C.faint, fontSize: 12 }}>{t[2]}</p>
            </div>
            <span style={{ color: C.saffronD, fontWeight: 800, fontSize: 15, display: 'inline-flex', alignItems: 'center', gap: 3 }}>+{t[3]}<Icon name="leaf" size={14} color={C.saffron} fill/></span>
            <span style={{ width: 20, height: 20, borderRadius: 100, border: `2px solid ${sel===i?C.saffron:'#e3d3a8'}`, background: sel===i?C.saffron:'transparent', flexShrink: 0, display:'flex', alignItems:'center', justifyContent:'center' }}>{sel===i && <Icon name="check" size={12} color="#fff"/>}</span>
          </Card>
        ))}
      </div>

      {/* đơn vị xác nhận */}
      <div style={{ padding: '20px 22px 0' }}>
        <p style={{ margin: '0 0 4px', color: C.ink, fontSize: 15, fontWeight: 800 }}>Đơn vị xác nhận</p>
        <p style={{ margin: '0 0 12px', color: C.faint, fontSize: 12.5 }}>Mọi thiện hành cần được xác nhận trước khi cộng Lá Bồ Đề</p>
        <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
          {approvers.map(a => (
            <Card key={a.key} onClick={() => setApprover(a.key)} style={{ display: 'flex', alignItems: 'center', gap: 12, padding: 14, cursor: 'pointer',
              borderColor: approver === a.key ? C.saffron : C.line, background: approver === a.key ? '#fff6e6' : C.card }}>
              <div style={{ width: 40, height: 40, borderRadius: 11, background: approver===a.key?'rgba(245,144,0,0.14)':C.card2, display: 'flex', alignItems: 'center', justifyContent: 'center', color: C.saffronD, flexShrink: 0 }}><Icon name={a.ic} size={20}/></div>
              <div style={{ flex: 1, minWidth: 0 }}>
                <p style={{ margin: 0, color: C.ink, fontSize: 14, fontWeight: 700 }}>{a.t}</p>
                <p style={{ margin: 0, color: C.faint, fontSize: 11.5 }}>{a.d}</p>
              </div>
              <span style={{ width: 20, height: 20, borderRadius: 100, border: `2px solid ${approver===a.key?C.saffron:'#e3d3a8'}`, background: approver===a.key?C.saffron:'transparent', flexShrink: 0, display:'flex', alignItems:'center', justifyContent:'center' }}>{approver===a.key && <Icon name="check" size={12} color="#fff"/>}</span>
            </Card>
          ))}
        </div>
      </div>

      {/* minh chứng — demo (Webapp có trạng thái "Chờ minh chứng") */}
      <div style={{ padding: '20px 22px 0' }}>
        <p style={{ margin: '0 0 4px', color: C.ink, fontSize: 15, fontWeight: 800 }}>Đính kèm minh chứng</p>
        <p style={{ margin: '0 0 12px', color: C.faint, fontSize: 12.5 }}>Ảnh/video minh chứng giúp chùa xác thực nhanh hơn</p>
        <Card onClick={() => setEvidence(e => !e)} style={{ display: 'flex', alignItems: 'center', gap: 12, padding: 14, cursor: 'pointer',
          borderColor: evidence ? C.saffron : C.line, background: evidence ? '#fff6e6' : C.card }}>
          <div style={{ width: 40, height: 40, borderRadius: 11, background: evidence ? 'rgba(245,144,0,0.14)' : C.card2, display: 'flex', alignItems: 'center', justifyContent: 'center', color: C.saffronD, flexShrink: 0 }}><Icon name="camera" size={20}/></div>
          <div style={{ flex: 1, minWidth: 0 }}>
            <p style={{ margin: 0, color: C.ink, fontSize: 14, fontWeight: 700 }}>{evidence ? 'Đã đính kèm minh chứng' : 'Chụp ảnh / chọn từ thư viện'}</p>
            <p style={{ margin: 0, color: C.faint, fontSize: 11.5 }}>{evidence ? 'Chạm để gỡ tệp đính kèm' : 'Ảnh hoặc video về thiện hành của bạn'}</p>
          </div>
          {evidence
            ? <span style={{ display: 'inline-flex', alignItems: 'center', gap: 4, color: '#3f8a3f', background: 'rgba(63,138,63,0.12)', fontWeight: 700, fontSize: 11.5, padding: '5px 11px', borderRadius: 100, whiteSpace: 'nowrap' }}><Icon name="check" size={13}/>demo_minhchung.jpg ✓</span>
            : <span style={{ color: C.saffron }}><Icon name="plus" size={18}/></span>}
        </Card>
      </div>

      <div style={{ padding: '22px 22px 0' }}>
        <button onClick={() => { const id = actions.submitDeed({ typeIdx: sel, approver, evidence }); setSentId(id); }} style={{ width: '100%', border: 'none', background: 'linear-gradient(135deg,#fbc117,#f59000)', color: '#5a2a08', fontWeight: 800, fontSize: 16, padding: '15px 0', borderRadius: 100, fontFamily: F, cursor: 'pointer', boxShadow: '0 10px 30px rgba(245,144,0,0.34)' }}>
          Gửi để xác nhận · +{DEED_TYPES[sel][3]} Lá
        </button>
      </div>

      {deedList}
    </div>
  );
}

// ════════ GALA ════════
function GalaScreen({ nav }) {
  // Top-3 chuẩn (đồng bộ Portal & Webapp): Minh Tuệ #1 · Diệu Tâm #2 · Nguyên Hạnh #3
  // Bình chọn nối vào store — phiếu persist; 1 phiếu/người, đổi ứng viên = chuyển phiếu.
  const s = useStore();
  const medalColor = ['#f5b800', '#bcae97', '#d08a3e'];
  const voted = s.voted, votes = s.votes;
  return (
    <div style={{ paddingBottom: 110 }}>
      <Header sub="Gala Vinh danh 2026 · 11 lĩnh vực" title="Vinh danh" back={() => nav && nav('home')} />
      <div style={{ padding: '0 22px' }}>
        <Card style={{ background: 'linear-gradient(160deg,#fff3d6,#ffe6b0)', borderColor: 'rgba(245,144,0,0.3)', padding: 18 }}>
          <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
            {GALA_TOP.map((p, i) => (
              <div key={p[0]} style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
                <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
                  <span style={{ width: 26, height: 26, borderRadius: 100, background: medalColor[i], color: '#fff', display: 'flex', alignItems: 'center', justifyContent: 'center', fontWeight: 800, fontSize: 13 }}>{p[2]}</span>
                  <Avatar size={36} icon="person" />
                  <span style={{ flex: 1, color: C.ink, fontSize: 14.5, fontWeight: 700 }}>{p[0]}</span>
                  <span style={{ color: C.saffronD, fontWeight: 800, fontSize: 15, display: 'inline-flex', alignItems: 'center', gap: 3 }}>{p[1]}<Icon name="leaf" size={13} color={C.saffron} fill/></span>
                </div>
                <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', paddingLeft: 38 }}>
                  <span style={{ color: C.faint, fontSize: 11.5, fontWeight: 700 }}>{votes[i]} phiếu bình chọn</span>
                  <button onClick={() => actions.vote(i)} disabled={voted === i}
                    style={{ border: voted === i ? `1px solid ${C.saffron}` : 0,
                      background: voted === i ? '#fff6e6' : 'linear-gradient(135deg,#fbc117,#f59000)',
                      color: voted === i ? C.saffronD : '#5a2a08', fontWeight: 800, fontSize: 11.5,
                      padding: '7px 14px', borderRadius: 100, cursor: voted === i ? 'default' : 'pointer', fontFamily: F }}>
                    {voted === i ? '✓ Đã bình chọn' : 'Bình chọn'}
                  </button>
                </div>
              </div>
            ))}
          </div>
          {/* phiếu của bạn — tóm tắt từ store */}
          <div style={{ marginTop: 14, paddingTop: 12, borderTop: '1px dashed rgba(245,144,0,0.35)' }}>
            <p style={{ margin: 0, color: C.saffronD, fontSize: 12, fontWeight: 800, display: 'flex', alignItems: 'center', gap: 6 }}>
              <Icon name="award" size={14}/>{voted != null ? `Phiếu của bạn: ${GALA_TOP[voted][0]}` : 'Bạn chưa bình chọn — chọn 1 trong Top 3 phía trên'}
            </p>
            <p style={{ margin: '6px 0 0', color: C.faint, fontSize: 11, fontStyle: 'italic' }}>Mỗi Phật tử 1 phiếu / hạng mục — demo. Bình chọn ứng viên khác sẽ chuyển phiếu của bạn.</p>
          </div>
        </Card>
      </div>
      <div style={{ padding: '14px 22px 0', display: 'flex', flexDirection: 'column', gap: 9 }}>
        {GALA_REST.map((p, i) => (
          <Card key={p[0]} style={{ display: 'flex', alignItems: 'center', gap: 12, padding: 13 }}>
            <span style={{ color: C.faint, fontSize: 13, fontWeight: 700, width: 22, textAlign: 'center' }}>{i + 4}</span>
            <span style={{ flex: 1, color: C.ink, fontSize: 14, fontWeight: 600 }}>{p[0]}</span>
            <span style={{ color: C.soft, fontWeight: 700, fontSize: 13.5, display: 'inline-flex', alignItems: 'center', gap: 3 }}>{p[1]}<Icon name="leaf" size={12} color={C.saffron} fill/></span>
          </Card>
        ))}
        {/* vị trí của bạn — ghim cuối bảng, hạng #214 GHIM demo (đồng bộ Trang chủ & Hồ sơ) */}
        <Card style={{ display: 'flex', alignItems: 'center', gap: 12, padding: 13, borderColor: C.saffron, background: '#fff6e6' }}>
          <span style={{ color: C.saffronD, fontSize: 12, fontWeight: 800, width: 34, textAlign: 'center' }}>#{s.rank}</span>
          <span style={{ flex: 1, color: C.saffronD, fontSize: 14, fontWeight: 800 }}>Bạn — {s.dharma}</span>
          <span style={{ color: C.soft, fontWeight: 700, fontSize: 13.5, display: 'inline-flex', alignItems: 'center', gap: 3 }}>{fmt(s.leaves)}<Icon name="leaf" size={12} color={C.saffron} fill/></span>
        </Card>
        <p style={{ margin: '2px 0 0', color: C.faint, fontSize: 10.5, fontStyle: 'italic', textAlign: 'center' }}>Hạng #214 được ghim cố định trong demo — không đổi khi tương tác.</p>
      </div>
    </div>
  );
}

// ════════ PROFILE ════════
// Huy hiệu ĐỘNG — unlock theo điều kiện đọc từ store; khóa = mờ + điều kiện.
const BADGE_DEFS = [
  { ic: 'temple',  t: 'Bước chân đầu',   req: 'Check-in 1 chùa',            cond: s => s.checkins.length >= 1 },
  { ic: 'check',   t: 'Tam thiện hạnh',  req: '3 thiện hành được duyệt',    cond: s => approvedDeeds(s) >= 3 },
  { ic: 'connect', t: 'Người gieo duyên',req: 'Hoàn thành 1 mốc dự án',     cond: s => anyMilestoneDone(s) },
  { ic: 'award',   t: 'Một phiếu tín tâm',req: 'Bình chọn tại Gala',        cond: s => s.voted != null },
  { ic: 'leaf',    t: 'Cây tỏa bóng',    req: 'Chạm cấp cây 5 (2.000 Lá)',  cond: s => treeStage(s.leaves) >= 4 },
  { ic: 'star',    t: 'Top 8%',          req: '',                            cond: () => true },
];

function ProfileScreen({ nav }) {
  const s = useStore();
  const [cover, setCover] = useState(() => { try { return localStorage.getItem('sdtd_cover') || ''; } catch(e){ return ''; } });
  const [avatar, setAvatar] = useState(() => { try { return localStorage.getItem('sdtd_avatar') || ''; } catch(e){ return ''; } });
  const [editing, setEditing] = useState(false);
  const [nm, setNm] = useState('');
  const [dh, setDh] = useState('');
  const [confirmReset, setConfirmReset] = useState(false);
  const timers = useRef([]);
  const mounted = useRef(true);
  useEffect(() => () => { mounted.current = false; timers.current.forEach(clearTimeout); }, []);
  // đồng bộ ảnh bìa/avatar với localStorage mỗi khi store đổi — để resetDemo()
  // (đã removeItem 'sdtd_cover'/'sdtd_avatar') xóa được ảnh đang hiển thị.
  useEffect(() => {
    try {
      setCover(localStorage.getItem('sdtd_cover') || '');
      setAvatar(localStorage.getItem('sdtd_avatar') || '');
    } catch (e) {}
  }, [s]);
  const later = (fn, ms) => { timers.current.push(setTimeout(fn, ms)); };
  function pick(setter, key) {
    const inp = document.createElement('input');
    inp.type = 'file'; inp.accept = 'image/*';
    inp.onchange = () => {
      const f = inp.files[0]; if (!f) return;
      const r = new FileReader();
      // lưu localStorage vô điều kiện; setState chỉ khi còn mounted (đổi tab giữa chừng)
      r.onload = () => { try { localStorage.setItem(key, r.result); } catch(e){} if (mounted.current) setter(r.result); };
      r.readAsDataURL(f);
    };
    inp.click();
  }
  function startEdit() { setNm(s.name); setDh(s.dharma); setEditing(true); }
  function askReset() {
    if (confirmReset) { setConfirmReset(false); setEditing(false); actions.resetDemo(); return; }
    setConfirmReset(true);
    later(() => setConfirmReset(false), 3000);
  }
  const inpStyle = { width: '100%', boxSizing: 'border-box', border: `1px solid ${C.line}`, borderRadius: 12, padding: '10px 13px', fontFamily: F, fontSize: 13.5, color: C.ink, background: C.card, outline: 'none' };
  const monthPct = Math.min(1, s.monthLeaves / MONTH_CAP);
  return (
    <div style={{ paddingBottom: 110 }}>
      <div style={{ position: 'relative' }}>
        {/* cover */}
        <div onClick={() => pick(setCover, 'sdtd_cover')} style={{ height: 150, paddingTop: 0, cursor: 'pointer',
          background: cover ? `center/cover no-repeat url(${cover})` : 'linear-gradient(165deg,#ffd35e 0%, #f59000 60%, #e07700 100%)',
          borderRadius: '0 0 24px 24px', position: 'relative' }}>
          <span style={{ position: 'absolute', right: 16, top: 52, background: 'rgba(255,255,255,0.92)', borderRadius: 100, padding: '6px 12px', fontSize: 11.5, fontWeight: 800, color: C.saffronD, display: 'inline-flex', alignItems: 'center', gap: 5 }}><Icon name="plus" size={13}/> Ảnh bìa</span>
        </div>
        {/* avatar + name (sửa được — lưu store) */}
        <div style={{ textAlign: 'center', marginTop: -46 }}>
          <div onClick={() => pick(setAvatar, 'sdtd_avatar')} style={{ width: 92, height: 92, borderRadius: 100, margin: '0 auto', border: '4px solid #fff', position: 'relative', cursor: 'pointer', overflow: 'hidden',
            background: avatar ? `center/cover no-repeat url(${avatar})` : 'linear-gradient(150deg,#ffd35e,#f59000)', boxShadow: '0 6px 18px rgba(245,144,0,0.25)' }}>
            {!avatar && <div style={{ width: '100%', height: '100%', display: 'flex', alignItems: 'center', justifyContent: 'center' }}><Icon name="meditate" size={42} color="#fff"/></div>}
            <span style={{ position: 'absolute', right: 2, bottom: 2, width: 26, height: 26, borderRadius: 100, background: C.saffron, border: '2px solid #fff', display: 'flex', alignItems: 'center', justifyContent: 'center', color: '#fff' }}><Icon name="plus" size={13}/></span>
          </div>
          {editing ? (
            <div style={{ maxWidth: 250, margin: '12px auto 0', display: 'flex', flexDirection: 'column', gap: 8, textAlign: 'left' }}>
              <input value={dh} onChange={e => setDh(e.target.value)} placeholder="Pháp danh" style={inpStyle}/>
              <input value={nm} onChange={e => setNm(e.target.value)} placeholder="Họ tên" style={inpStyle}/>
              <div style={{ display: 'flex', gap: 8, justifyContent: 'center' }}>
                <button onClick={() => { actions.setProfile(nm, dh); setEditing(false); }} style={{ border: 'none', background: 'linear-gradient(135deg,#fbc117,#f59000)', color: '#5a2a08', fontWeight: 800, fontSize: 12.5, padding: '9px 20px', borderRadius: 100, cursor: 'pointer', fontFamily: F }}>Lưu</button>
                <button onClick={() => setEditing(false)} style={{ border: `1px solid ${C.line}`, background: C.card, color: C.soft, fontWeight: 700, fontSize: 12.5, padding: '9px 16px', borderRadius: 100, cursor: 'pointer', fontFamily: F }}>Hủy</button>
              </div>
            </div>
          ) : (
            <div>
              <h1 style={{ margin: '10px 0 2px', color: C.ink, fontSize: 23, fontWeight: 800, display: 'inline-flex', alignItems: 'center', gap: 8 }}>
                {s.dharma}
                <span onClick={startEdit} style={{ display: 'inline-flex', alignItems: 'center', gap: 4, color: C.saffronD, background: 'rgba(245,144,0,0.12)', borderRadius: 100, padding: '4px 11px', fontSize: 11, fontWeight: 800, cursor: 'pointer' }}><Icon name="edit" size={12}/>Sửa</span>
              </h1>
              <p style={{ margin: 0, color: C.faint, fontSize: 13 }}>{s.name} · Phật tử · Tham gia từ 05/2026</p>
            </div>
          )}
        </div>
      </div>
      <div style={{ padding: '16px 22px 0', display: 'flex', gap: 10 }}>
        {[[fmt(s.leaves), 'Lá Bồ Đề'], [String(18 + approvedDeeds(s)), 'Thiện hành'], ['#' + s.rank, 'Xếp hạng']].map(st2 => (
          <Card key={st2[1]} style={{ flex: 1, textAlign: 'center', padding: '14px 6px' }}>
            <p style={{ margin: 0, color: C.saffronD, fontWeight: 800, fontSize: 20 }}>{st2[0]}</p>
            <p style={{ margin: 0, color: C.faint, fontSize: 11.5 }}>{st2[1]}</p>
          </Card>
        ))}
      </div>
      {/* trần Lá/tháng — cơ chế Phòng Ác (live từ store, khớp Trang chủ) */}
      <div style={{ padding: '12px 22px 0' }}>
        <Card style={{ padding: '13px 16px' }}>
          <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
            <span style={{ color: C.ink, fontSize: 12.5, fontWeight: 700, display: 'inline-flex', alignItems: 'center', gap: 6 }}><Icon name="shield" size={15} color={C.saffronD}/>{s.monthLeaves} / {MONTH_CAP} Lá tháng này</span>
            <span style={{ color: C.saffronD, fontSize: 12, fontWeight: 800 }}>{Math.round(monthPct * 100)}%</span>
          </div>
          <div style={{ marginTop: 9, height: 6, borderRadius: 100, background: 'rgba(245,144,0,0.14)', overflow: 'hidden' }}>
            <div style={{ width: `${Math.round(monthPct * 100)}%`, height: '100%', background: 'linear-gradient(90deg,#fbc117,#f59000)', transition: 'width .6s' }}/>
          </div>
          <p style={{ margin: '7px 0 0', fontSize: 11, color: C.faint }}>Trần {MONTH_CAP} Lá/tháng — cơ chế Phòng Ác</p>
        </Card>
      </div>
      <div style={{ padding: '20px 22px 0' }}>
        <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 12 }}>
          <p style={{ margin: 0, color: C.ink, fontSize: 16, fontWeight: 800 }}>Chùa đã check-in</p>
          <span onClick={() => nav && nav('checkin')} style={{ color: C.saffronD, fontSize: 13, fontWeight: 700, cursor: 'pointer' }}>+ Check-in ›</span>
        </div>
        <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
          {s.checkins.map(c => (
            <Card key={c.id} onClick={() => nav && nav('checkin')} style={{ display: 'flex', alignItems: 'center', gap: 12, padding: 14, cursor: 'pointer' }}>
              <div style={{ width: 40, height: 40, borderRadius: 12, background: C.card2, display: 'flex', alignItems: 'center', justifyContent: 'center', color: C.saffronD }}><Icon name="temple" size={20}/></div>
              <div style={{ flex: 1, minWidth: 0 }}>
                <p style={{ margin: 0, color: C.ink, fontSize: 14, fontWeight: 700 }}>{c.name}</p>
                <p style={{ margin: 0, color: C.faint, fontSize: 12 }}>{c.place} · {c.date}</p>
              </div>
              <span style={{ display: 'inline-flex', alignItems: 'center', gap: 4, color: '#3f8a3f', background: 'rgba(63,138,63,0.12)', fontWeight: 700, fontSize: 11.5, padding: '5px 11px', borderRadius: 100 }}><Icon name="check" size={13}/>Đã đến</span>
            </Card>
          ))}
        </div>
      </div>
      {/* thành tựu — huy hiệu động, khóa hiện mờ + điều kiện */}
      <div style={{ padding: '20px 22px 0' }}>
        <p style={{ margin: '0 0 12px', color: C.ink, fontSize: 16, fontWeight: 800 }}>Thành tựu tu tập</p>
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3,1fr)', gap: 10 }}>
          {BADGE_DEFS.map(b => {
            const on = b.cond(s);
            return (
              <Card key={b.t} style={{ textAlign: 'center', padding: '16px 6px', opacity: on ? 1 : 0.5, background: on ? C.card : C.card2 }}>
                <div style={{ color: on ? C.saffronD : C.faint, display: 'flex', justifyContent: 'center' }}><Icon name={on ? b.ic : 'lock'} size={26}/></div>
                <p style={{ margin: '8px 0 0', color: on ? C.soft : C.faint, fontSize: 11.5, fontWeight: 600 }}>{b.t}</p>
                {!on && <p style={{ margin: '3px 0 0', color: C.faint, fontSize: 9.5, lineHeight: 1.35 }}>{b.req}</p>}
              </Card>
            );
          })}
        </div>
      </div>
      {/* lịch sử Lá Bồ Đề — từ store */}
      <div style={{ padding: '20px 22px 0' }}>
        <p style={{ margin: '0 0 12px', color: C.ink, fontSize: 16, fontWeight: 800 }}>Lịch sử Lá Bồ Đề</p>
        <div style={{ display: 'flex', flexDirection: 'column', gap: 9 }}>
          {s.history.slice(0, 6).map(a => (
            <Card key={a.id} style={{ display: 'flex', alignItems: 'center', gap: 12, padding: 12 }}>
              <div style={{ width: 34, height: 34, borderRadius: 10, background: C.card2, display: 'flex', alignItems: 'center', justifyContent: 'center', color: C.saffronD, flexShrink: 0 }}><Icon name={a.ic} size={16}/></div>
              <div style={{ flex: 1, minWidth: 0 }}>
                <p style={{ margin: 0, color: C.ink, fontSize: 12.5, fontWeight: 600, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{a.t}</p>
                <p style={{ margin: 0, color: C.faint, fontSize: 11 }}>{a.date}</p>
              </div>
              <span style={{ color: C.saffronD, fontWeight: 800, fontSize: 13, whiteSpace: 'nowrap', display: 'inline-flex', alignItems: 'center', gap: 3 }}>+{a.leaf}<Icon name="leaf" size={12} color={C.saffron} fill/></span>
            </Card>
          ))}
        </div>
      </div>
      <div style={{ padding: '20px 22px 0' }}>
        <Card style={{ display: 'flex', alignItems: 'center', gap: 12, padding: 16, borderColor: 'rgba(245,144,0,0.3)' }}>
          <div style={{ width: 40, height: 40, borderRadius: 12, background: 'rgba(245,144,0,0.12)', display: 'flex', alignItems: 'center', justifyContent: 'center', color: C.saffronD }}><Icon name="shield" size={20}/></div>
          <div style={{ flex: 1 }}>
            <p style={{ margin: 0, color: C.ink, fontSize: 14, fontWeight: 700 }}>Hồ sơ công khai</p>
            <p style={{ margin: 0, color: C.faint, fontSize: 12 }}>sangdaotrongdoi.net/u/minhan</p>
          </div>
          <span style={{ color: C.saffron }}><Icon name="chevron" size={18}/></span>
        </Card>
      </div>
      {/* đặt lại dữ liệu demo — confirm 2 chạm */}
      <div style={{ padding: '14px 22px 0' }}>
        <button onClick={askReset} style={{ width: '100%', border: `1px solid ${confirmReset ? '#e23b2e' : C.line}`, background: confirmReset ? 'rgba(226,59,46,0.08)' : C.card, color: confirmReset ? '#e23b2e' : C.soft, fontWeight: 800, fontSize: 13.5, padding: '13px 0', borderRadius: 100, cursor: 'pointer', fontFamily: F, display: 'inline-flex', alignItems: 'center', justifyContent: 'center', gap: 7 }}>
          <Icon name="refresh" size={16}/>{confirmReset ? 'Chạm lần nữa để xác nhận đặt lại' : 'Đặt lại dữ liệu demo'}
        </button>
      </div>
    </div>
  );
}

// ════════ CẦU NỐI (Connect) ════════
// 3 dự án từ store với mốc tuần tự: Tham gia → mốc 1 mở → hoàn thành mốc
// (+15–50 Lá theo từng mốc, đồng bộ Webapp; confirm 2 chạm) → mở mốc kế → đủ mốc = hoàn thành.
function ConnectScreen() {
  const s = useStore();
  const [cat, setCat] = useState('Tất cả');
  const [confirmId, setConfirmId] = useState(null); // confirm nhẹ cho "Hoàn thành mốc"
  const timers = useRef([]);
  useEffect(() => () => { timers.current.forEach(clearTimeout); }, []);
  const later = (fn, ms) => { timers.current.push(setTimeout(fn, ms)); };
  function askComplete(pid) {
    if (confirmId === pid) { setConfirmId(null); actions.completeMilestone(pid); return; }
    setConfirmId(pid);
    later(() => setConfirmId(c => c === pid ? null : c), 2600);
  }
  // chip lọc suy ra từ thực tế dữ liệu — phủ cả cat của việc nhận từ check-in chùa
  // ('Tu học', 'Thiện nguyện', 'Di sản', 'Truyền thông', 'Cộng đồng'…), không hardcode 3 nhóm.
  const cats = ['Tất cả', ...new Set([...s.connectTasks, ...s.projects].map(x => x.cat))];
  const tasks = s.connectTasks.filter(p => cat === 'Tất cả' || p.cat === cat);
  const projects = s.projects.filter(p => cat === 'Tất cả' || p.cat === cat);
  const total = tasks.length + projects.length;
  return (
    <div style={{ paddingBottom: 110 }}>
      <Header sub="Gieo duyên lành — kết nối dự án" title="Cầu Nối" />
      <div style={{ padding: '0 22px 4px' }}>
        <Card style={{ padding: 15, background: 'linear-gradient(135deg,#fff6e3,#ffe9bf)', borderColor: 'rgba(245,144,0,0.28)' }}>
          <div style={{ display: 'flex', gap: 11, alignItems: 'flex-start' }}>
            <div style={{ width: 34, height: 34, borderRadius: 10, background: 'rgba(245,144,0,0.16)', display: 'flex', alignItems: 'center', justifyContent: 'center', color: C.saffronD, flexShrink: 0 }}><Icon name="connect" size={19}/></div>
            <div>
              <p style={{ margin: 0, color: C.ink, fontSize: 13.5, fontWeight: 800 }}>Cầu Nối là gì?</p>
              <p style={{ margin: '5px 0 0', color: C.soft, fontSize: 12.5, lineHeight: 1.55 }}>Nơi <b style={{ color: C.saffronD }}>chùa &amp; đạo tràng đăng dự án thiện nguyện</b> đang cần người chung tay. Bạn <b style={{ color: C.saffronD }}>“gieo duyên”</b> tham gia, hoàn thành từng mốc và được ghi nhận <b style={{ color: C.saffronD }}>+15–50 Lá Bồ Đề mỗi mốc</b>.</p>
            </div>
          </div>
        </Card>
      </div>
      <div style={{ padding: '12px 22px 4px', display: 'flex', gap: 8, overflowX: 'auto', paddingBottom: 4 }}>
        {cats.map(c => (
          <button key={c} onClick={() => setCat(c)} style={{ flexShrink: 0, border: 0, cursor: 'pointer', fontFamily: F, fontSize: 13, fontWeight: 700,
            padding: '8px 15px', borderRadius: 100,
            background: cat === c ? 'linear-gradient(135deg,#fbc117,#f59000)' : '#fff',
            color: cat === c ? '#5a2a08' : C.soft, boxShadow: cat === c ? '0 6px 16px rgba(245,144,0,0.3)' : `inset 0 0 0 1px ${C.line}` }}>{c}</button>
        ))}
      </div>
      <div style={{ padding: '8px 22px 0' }}>
        <p style={{ margin: '8px 0 12px', color: C.faint, fontSize: 13 }}>{total} dự án cần hỗ trợ</p>
        <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
          {/* việc nhận từ check-in chùa */}
          {tasks.map(p => (
            <Card key={p.id} style={{ padding: 16 }}>
              <div style={{ display: 'flex', gap: 12 }}>
                <div style={{ width: 44, height: 44, borderRadius: 12, background: C.card2, display: 'flex', alignItems: 'center', justifyContent: 'center', color: C.saffronD, flexShrink: 0 }}><Icon name={p.ic} size={22}/></div>
                <div style={{ flex: 1, minWidth: 0 }}>
                  <p style={{ margin: 0, color: C.ink, fontSize: 14.5, fontWeight: 700, lineHeight: 1.3 }}>{p.t}</p>
                  <p style={{ margin: '4px 0 0', color: C.faint, fontSize: 12, display: 'inline-flex', alignItems: 'center', gap: 4 }}><Icon name="pin" size={13}/>{p.org}</p>
                  <span style={{ display: 'inline-flex', alignItems: 'center', gap: 4, marginTop: 6, fontSize: 10.5, fontWeight: 700, color: '#3f8a3f', background: 'rgba(63,138,63,0.12)', padding: '3px 9px', borderRadius: 100 }}><Icon name="check" size={12}/>Đã nhận từ check-in</span>
                </div>
              </div>
              <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginTop: 12 }}>
                <span style={{ fontSize: 12, color: C.soft, fontWeight: 600 }}>{p.need}{p.due ? ` · hạn ${p.due}` : ''}</span>
                <span style={{ display: 'inline-flex', alignItems: 'center', gap: 8 }}>
                  <span style={{ color: C.saffronD, fontWeight: 800, fontSize: 13, display: 'inline-flex', alignItems: 'center', gap: 3 }}>~{p.leaf}<Icon name="leaf" size={13} color={C.saffron} fill/></span>
                  <button onClick={() => actions.removeConnectTask(p.t)} style={{ border: `1px solid ${C.line}`, background: C.card, color: C.soft, fontWeight: 700, fontSize: 11.5, padding: '7px 13px', borderRadius: 100, cursor: 'pointer', fontFamily: F }}>Bỏ nhận</button>
                </span>
              </div>
            </Card>
          ))}

          {/* dự án Cầu Nối — vòng đời đầy đủ */}
          {projects.map(p => {
            const doneCount = p.milestones.filter(m => m.done).length;
            const openIdx = p.milestones.findIndex(m => !m.done);
            return (
              <Card key={p.id} style={{ padding: 16, borderColor: p.completed ? 'rgba(63,138,63,0.45)' : (p.joined ? C.saffron : C.line) }}>
                <div style={{ display: 'flex', gap: 12 }}>
                  <div style={{ width: 44, height: 44, borderRadius: 12, background: C.card2, display: 'flex', alignItems: 'center', justifyContent: 'center', color: C.saffronD, flexShrink: 0 }}><Icon name={p.ic} size={22}/></div>
                  <div style={{ flex: 1, minWidth: 0 }}>
                    <p style={{ margin: 0, color: C.ink, fontSize: 14.5, fontWeight: 700, lineHeight: 1.3 }}>{p.t}</p>
                    <p style={{ margin: '4px 0 0', color: C.faint, fontSize: 12, display: 'inline-flex', alignItems: 'center', gap: 4 }}><Icon name="pin" size={13}/>{p.org}</p>
                    <div style={{ display: 'flex', gap: 6, marginTop: 6, flexWrap: 'wrap' }}>
                      <span style={{ fontSize: 10.5, fontWeight: 700, color: C.saffronD, background: 'rgba(245,144,0,0.12)', padding: '3px 9px', borderRadius: 100 }}>{p.cat}</span>
                      {p.completed && <span style={{ display: 'inline-flex', alignItems: 'center', gap: 4, fontSize: 10.5, fontWeight: 700, color: '#3f8a3f', background: 'rgba(63,138,63,0.12)', padding: '3px 9px', borderRadius: 100 }}><Icon name="check" size={12}/>Dự án hoàn thành</span>}
                      {p.joined && !p.completed && <span style={{ fontSize: 10.5, fontWeight: 700, color: '#3f8a3f', background: 'rgba(63,138,63,0.12)', padding: '3px 9px', borderRadius: 100 }}>● Đang tham gia · {doneCount}/{p.milestones.length} mốc</span>}
                    </div>
                  </div>
                </div>

                {!p.joined && !p.completed && (
                  <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginTop: 12 }}>
                    <span style={{ fontSize: 12, color: C.soft, fontWeight: 600 }}>{p.need}</span>
                    <span style={{ display: 'inline-flex', alignItems: 'center', gap: 8 }}>
                      <span style={{ color: C.saffronD, fontWeight: 800, fontSize: 13, display: 'inline-flex', alignItems: 'center', gap: 3 }}>~{p.milestones.reduce((a, m) => a + m.leaf, 0)}<Icon name="leaf" size={13} color={C.saffron} fill/></span>
                      <button onClick={() => actions.joinProject(p.id)} style={{ border: 'none', background: 'linear-gradient(135deg,#fbc117,#f59000)', color: '#5a2a08', fontWeight: 800, fontSize: 12.5, padding: '8px 16px', borderRadius: 100, cursor: 'pointer', fontFamily: F, boxShadow: '0 6px 16px rgba(245,144,0,0.3)' }}>Gieo duyên</button>
                    </span>
                  </div>
                )}

                {/* panel mốc — mốc 1 mở, còn lại khóa tuần tự */}
                {(p.joined || p.completed) && (
                  <div style={{ marginTop: 13, borderTop: `1px dashed ${C.line}`, paddingTop: 12, display: 'flex', flexDirection: 'column', gap: 9 }}>
                    {p.milestones.map((m, i) => {
                      const stt = m.done ? 'done' : (p.joined && i === openIdx ? 'open' : 'locked');
                      return (
                        <div key={m.t} style={{ display: 'flex', alignItems: 'center', gap: 10, opacity: stt === 'locked' ? 0.5 : 1 }}>
                          <span style={{ width: 24, height: 24, borderRadius: 100, flexShrink: 0, display: 'flex', alignItems: 'center', justifyContent: 'center',
                            background: stt === 'done' ? 'rgba(63,138,63,0.14)' : stt === 'open' ? 'rgba(245,144,0,0.14)' : C.card2,
                            color: stt === 'done' ? '#3f8a3f' : stt === 'open' ? C.saffronD : C.faint, fontSize: 11, fontWeight: 800 }}>
                            {stt === 'done' ? <Icon name="check" size={13}/> : stt === 'locked' ? <Icon name="lock" size={12}/> : i + 1}
                          </span>
                          <span style={{ flex: 1, color: stt === 'done' ? C.faint : C.ink, fontSize: 12.5, fontWeight: 600, textDecoration: stt === 'done' ? 'line-through' : 'none' }}>{m.t}</span>
                          {stt === 'open' && (
                            <button onClick={() => askComplete(p.id)} style={{ flexShrink: 0, border: confirmId === p.id ? `1px solid ${C.saffron}` : 'none',
                              background: confirmId === p.id ? '#fff6e6' : 'linear-gradient(135deg,#fbc117,#f59000)',
                              color: confirmId === p.id ? C.saffronD : '#5a2a08', fontWeight: 800, fontSize: 11, padding: '7px 12px', borderRadius: 100, cursor: 'pointer', fontFamily: F }}>
                              {confirmId === p.id ? 'Chạm để xác nhận ✓' : `Hoàn thành mốc +${m.leaf}`}
                            </button>
                          )}
                          {stt === 'done' && <span style={{ flexShrink: 0, color: '#3f8a3f', fontSize: 11, fontWeight: 800, display: 'inline-flex', alignItems: 'center', gap: 3 }}>+{m.leaf}<Icon name="leaf" size={11} color="#3f8a3f" fill/></span>}
                        </div>
                      );
                    })}
                    {p.joined && !p.completed && (
                      <span onClick={() => actions.leaveProject(p.id)} style={{ alignSelf: 'flex-end', color: C.faint, fontSize: 11.5, fontWeight: 700, cursor: 'pointer', textDecoration: 'underline' }}>Rời dự án</span>
                    )}
                    {p.completed && (
                      <p style={{ margin: 0, color: '#3f8a3f', fontSize: 11.5, fontWeight: 700, display: 'flex', alignItems: 'center', gap: 5 }}><Icon name="sparkle" size={13}/>Bạn đã đi trọn {p.milestones.length} mốc của dự án này. Lành thay!</p>
                    )}
                  </div>
                )}
              </Card>
            );
          })}
        </div>
      </div>
    </div>
  );
}

// ════════ THÔNG BÁO (Notifications) ════════
// Render từ store (mới nhất trên đầu) — tap để đánh dấu đã đọc, nút "Đọc tất cả".
function NotificationScreen() {
  const s = useStore();
  const unread = unreadCount(s);
  const groups = [
    { day: 'Hôm nay', items: s.notifications.filter(n => n.day === 'Hôm nay') },
    { day: 'Trước đó', items: s.notifications.filter(n => n.day !== 'Hôm nay') },
  ].filter(g => g.items.length > 0);
  const toneColor = { ok: '#3f8a3f', gold: C.saffronD };
  const toneBg = { ok: 'rgba(63,138,63,0.12)', gold: 'rgba(245,144,0,0.12)' };
  return (
    <div style={{ paddingBottom: 110 }}>
      <Header sub="Cập nhật hành trình của bạn" title="Thông báo" />
      <div style={{ padding: '0 22px 10px', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
        <span style={{ color: C.faint, fontSize: 12.5, fontWeight: 700 }}>{unread > 0 ? `${unread} thông báo chưa đọc` : 'Bạn đã đọc tất cả'}</span>
        <button onClick={() => actions.markAllRead()} disabled={unread === 0}
          style={{ border: `1px solid ${unread > 0 ? C.saffron : C.line}`, background: unread > 0 ? '#fff6e6' : C.card, color: unread > 0 ? C.saffronD : C.faint, fontWeight: 800, fontSize: 11.5, padding: '7px 14px', borderRadius: 100, cursor: unread > 0 ? 'pointer' : 'default', fontFamily: F }}>
          Đọc tất cả
        </button>
      </div>
      {groups.map(g => (
        <div key={g.day} style={{ padding: '0 22px', marginBottom: 6 }}>
          <p style={{ margin: '6px 0 10px', color: C.faint, fontSize: 12, fontWeight: 700, textTransform: 'uppercase', letterSpacing: '.06em' }}>{g.day}</p>
          <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
            {g.items.map(n => (
              <Card key={n.id} onClick={() => n.unread && actions.markRead(n.id)} style={{ display: 'flex', gap: 12, padding: 14, borderColor: n.unread ? 'rgba(245,144,0,0.3)' : C.line, background: n.unread ? '#fffaf0' : C.card, cursor: n.unread ? 'pointer' : 'default' }}>
                <div style={{ width: 38, height: 38, borderRadius: 11, background: toneBg[n.tone], display: 'flex', alignItems: 'center', justifyContent: 'center', color: toneColor[n.tone], flexShrink: 0 }}><Icon name={n.ic} size={19}/></div>
                <div style={{ flex: 1, minWidth: 0 }}>
                  <p style={{ margin: 0, color: C.ink, fontSize: 13.5, fontWeight: n.unread ? 800 : 700 }}>{n.t}</p>
                  <p style={{ margin: '2px 0 0', color: C.faint, fontSize: 12, lineHeight: 1.45 }}>{n.d}</p>
                </div>
                <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'flex-end', gap: 6 }}>
                  <span style={{ color: C.faint, fontSize: 11 }}>{n.time}</span>
                  {n.unread && <span style={{ width: 8, height: 8, borderRadius: 100, background: C.saffron }}/>}
                </div>
              </Card>
            ))}
          </div>
        </div>
      ))}
    </div>
  );
}

// ════════ THIỆN TRI THỨC (Chat) ════════
// Demo không backend. Input TỰ DO → keyword matching (mượn matchFlow của
// thien-tri-thuc.html). Trích dẫn kinh văn dùng PLACEHOLDER (chờ Ban Văn hóa
// kiểm định bản dịch) — tuyệt đối không chèn bản dịch kinh thật vào demo.
function CiteCard({ src, tags }) {
  return (
    <div style={{ background: C.card2, border: `1px solid ${C.line}`, borderRadius: 14, padding: '11px 13px', marginTop: 8 }}>
      <p style={{ margin: 0, color: C.faint, fontSize: 12, fontStyle: 'italic', lineHeight: 1.5 }}>[Trích dẫn kinh văn — chờ Ban Văn hóa kiểm định]</p>
      <p style={{ margin: '7px 0 0', color: C.saffronD, fontSize: 11.5, fontWeight: 800, display: 'flex', alignItems: 'center', gap: 5 }}><Icon name="book" size={13}/>{src}</p>
      <div style={{ display: 'flex', gap: 5, marginTop: 7, flexWrap: 'wrap' }}>
        {tags.map(t => <span key={t} style={{ fontSize: 10, fontWeight: 700, color: C.soft, background: 'rgba(245,144,0,0.1)', border: '1px solid rgba(245,144,0,0.2)', padding: '2px 8px', borderRadius: 100 }}>{t}</span>)}
      </div>
    </div>
  );
}

function ChatScreen({ nav }) {
  const s = useStore();
  const [text, setText] = useState('');
  const askedQs = s.chatLog.map(e => e.q);
  const remaining = CHAT_FLOWS.map(f => f.q).filter(q => !askedQs.includes(q));
  function send() {
    const t = text.trim();
    if (!t) return;
    actions.askChat(t);
    setText('');
  }
  return (
    <div style={{ minHeight: '100%', display: 'flex', flexDirection: 'column' }}>
      {/* header */}
      <div style={{ background: 'linear-gradient(165deg,#ffd35e 0%, #f59000 60%, #e07700 100%)', borderRadius: '0 0 26px 26px', paddingTop: 54, paddingBottom: 16, color: '#fff' }}>
        <div style={{ padding: '0 22px' }}>
          <button onClick={() => nav && nav('home')} style={{ background: 'rgba(255,255,255,0.2)', border: 0, color: '#fff', borderRadius: 100, padding: '6px 14px', fontSize: 12.5, fontWeight: 700, cursor: 'pointer', fontFamily: F, display: 'inline-flex', alignItems: 'center', gap: 5 }}>‹ Trang chủ</button>
          <div style={{ display: 'flex', alignItems: 'center', gap: 11, marginTop: 13 }}>
            <span style={{ width: 46, height: 46, borderRadius: 100, background: 'rgba(255,255,255,0.22)', display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 25, flexShrink: 0 }}>🪷</span>
            <div>
              <h1 style={{ margin: 0, color: '#fff', fontSize: 22, fontWeight: 800 }}>Thiện Tri Thức</h1>
              <p style={{ margin: '2px 0 0', color: 'rgba(255,255,255,0.9)', fontSize: 11.5 }}>Không trả lời thay — chỉ gửi trích dẫn nguyên văn kèm nguồn</p>
            </div>
          </div>
        </div>
      </div>

      {/* messages — log persist trong store */}
      <div style={{ flex: 1, padding: '16px 18px 0', display: 'flex', flexDirection: 'column', gap: 14 }}>
        {s.chatLog.map(entry => {
          const flow = entry.flow >= 0 ? CHAT_FLOWS[entry.flow] : null;
          const cites = flow ? flow.cites : CHAT_FALLBACK.cites;
          const ctx = flow ? flow.ctx : CHAT_FALLBACK.ctx;
          return (
            <React.Fragment key={entry.id}>
              {/* user bubble */}
              <div style={{ alignSelf: 'flex-end', maxWidth: '82%', background: 'linear-gradient(135deg,#fbc117,#f59000)', color: '#5a2a08', borderRadius: '18px 18px 4px 18px', padding: '11px 15px', fontSize: 13.5, fontWeight: 600, lineHeight: 1.5, boxShadow: '0 6px 16px rgba(245,144,0,0.22)' }}>{entry.q}</div>
              {/* bot bubble */}
              <div style={{ alignSelf: 'flex-start', maxWidth: '92%', background: C.card, border: `1px solid ${C.line}`, borderRadius: '18px 18px 18px 4px', padding: '13px 15px', boxShadow: '0 1px 2px rgba(151,86,26,0.04), 0 8px 24px rgba(245,144,0,0.06)' }}>
                <p style={{ margin: 0, color: C.soft, fontSize: 12.5, lineHeight: 1.55 }}>Bạn đang chạm tới chủ đề <b style={{ color: C.saffronD }}>{ctx}</b>. Trong kho kinh sách đã kiểm định có <b style={{ color: C.saffronD }}>{cites.length} trích dẫn</b> liên quan đến điều bạn chia sẻ:</p>
                {cites.map(c => <CiteCard key={c.src + c.tags.join('')} src={c.src} tags={c.tags}/>)}
                <div style={{ marginTop: 11, paddingTop: 11, borderTop: `1px dashed ${C.line}`, display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 8 }}>
                  <p style={{ margin: 0, color: C.faint, fontSize: 11.5, fontStyle: 'italic' }}>Mời bạn tự đọc và chiêm nghiệm</p>
                  {remaining.length > 0 && <button onClick={() => actions.askChat(remaining[0])} style={{ flexShrink: 0, border: `1px solid ${C.saffron}`, background: '#fff6e6', color: C.saffronD, fontWeight: 800, fontSize: 11.5, padding: '7px 13px', borderRadius: 100, cursor: 'pointer', fontFamily: F }}>Hỏi sâu thêm</button>}
                </div>
              </div>
            </React.Fragment>
          );
        })}
      </div>

      {/* suggestion chips + input bar (gõ tự do → keyword matching) */}
      <div style={{ padding: '14px 18px 110px' }}>
        {remaining.length > 0 && (
          <div style={{ display: 'flex', gap: 8, overflowX: 'auto', paddingBottom: 10 }}>
            {remaining.map(q => (
              <button key={q} onClick={() => actions.askChat(q)} style={{ flexShrink: 0, border: `1px solid ${C.line}`, background: C.card, color: C.soft, fontWeight: 700, fontSize: 12, padding: '8px 14px', borderRadius: 100, cursor: 'pointer', fontFamily: F }}>{q}</button>
            ))}
          </div>
        )}
        <div style={{ display: 'flex', alignItems: 'center', gap: 9 }}>
          <input value={text} onChange={e => setText(e.target.value)} onKeyDown={e => { if (e.key === 'Enter') send(); }}
            placeholder="Chia sẻ điều bạn đang trăn trở…"
            style={{ flex: 1, minWidth: 0, background: C.card, border: `1px solid ${C.line}`, borderRadius: 100, padding: '12px 17px', color: C.ink, fontSize: 13, fontFamily: F, outline: 'none' }}/>
          <button onClick={send} style={{ width: 44, height: 44, borderRadius: 100, flexShrink: 0, border: 'none', cursor: 'pointer', background: 'linear-gradient(135deg,#fbc117,#f59000)', display: 'flex', alignItems: 'center', justifyContent: 'center', boxShadow: '0 8px 20px rgba(245,144,0,0.34)' }}><Icon name="send" size={20} color="#5a2a08"/></button>
        </div>
      </div>
    </div>
  );
}

// ════════ TAB BAR ════════
// LƯU Ý ĐIỀU HƯỚNG (đặc tả Đợt 2 — mục 5.4): KHÔNG thêm tab thứ 6 cho Thiện Tri Thức.
// TabBar giữ nguyên 5 vị trí (4 tab + nút Ghi nhận ở giữa); ChatScreen chỉ được mở
// từ card "🪷 Thiện Tri Thức" trên Trang chủ (HomeScreen).
// Badge thông báo: subscribe store — hiện SỐ chưa đọc, ẩn khi 0.
function TabBar({ tab, setTab }) {
  const s = useStore();
  const unread = unreadCount(s);
  const tabs = [['home','Trang chủ','home'],['connect','Cầu Nối','connect'],['record','',''],['notifications','Thông báo','bell'],['profile','Hồ sơ','person']];
  return (
    <div style={{ position: 'absolute', left: 0, right: 0, bottom: 0, zIndex: 40,
      background: 'rgba(255,255,255,0.92)', backdropFilter: 'blur(18px)', borderTop: `1px solid ${C.line}`,
      paddingBottom: 26, paddingTop: 10, display: 'flex', justifyContent: 'space-around', alignItems: 'center' }}>
      {tabs.map((t) => {
        if (t[0] === 'record') return (
          <button key="record" onClick={() => setTab('record')} style={{ background: 'none', border: 'none', cursor: 'pointer', transform: 'translateY(-8px)' }}>
            <span style={{ width: 50, height: 50, borderRadius: 100, background: 'linear-gradient(135deg,#fbc117,#f59000)', display: 'flex', alignItems: 'center', justifyContent: 'center', boxShadow: '0 8px 22px rgba(245,144,0,0.42)' }}><Icon name="plus" size={26} color="#5a2a08" sw={2.4}/></span>
          </button>
        );
        const active = tab === t[0];
        return (
          <button key={t[0]} onClick={() => setTab(t[0])} style={{ position: 'relative', background: 'none', border: 'none', cursor: 'pointer', display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 4, color: active ? C.saffron : '#b49a6f' }}>
            <Icon name={t[2]} size={22} fill={active} color={active ? C.saffron : '#b49a6f'}/>
            {t[0] === 'notifications' && unread > 0 && <span style={{ position: 'absolute', top: -4, right: 'calc(50% - 18px)', minWidth: 15, height: 15, borderRadius: 100, background: '#e23b2e', color: '#fff', fontSize: 9, fontWeight: 800, display: 'flex', alignItems: 'center', justifyContent: 'center', padding: '0 4px', boxShadow: '0 0 0 2px rgba(255,255,255,0.92)' }}>{unread > 9 ? '9+' : unread}</span>}
            <span style={{ fontSize: 10.5, fontWeight: active ? 800 : 600 }}>{t[1]}</span>
          </button>
        );
      })}
    </div>
  );
}

Object.assign(window, { HomeScreen, CheckInScreen, RecordScreen, GalaScreen, ProfileScreen, ConnectScreen, NotificationScreen, ChatScreen, TabBar, Icon });
