// lifetime.jsx — "Samvega": a sense of urgency. Age + duties → realistic practice
// time left in this life, sittings remaining, and a mirror of the path ahead.

const MT_LIFE_KEY = 'mt_life_v1';
const MT_LIFE_DEFAULT = { configured: false, age: 35, lifespan: 83, sleep: 7.5, work: 8, family: 3, practiceMin: 20, targetHours: 2000 };
function mtLoadLife() {
  try { const r = localStorage.getItem(MT_LIFE_KEY); if (r) return { ...MT_LIFE_DEFAULT, ...JSON.parse(r) }; } catch (e) {}
  return { ...MT_LIFE_DEFAULT };
}
function mtSaveLife(c) { try { localStorage.setItem(MT_LIFE_KEY, JSON.stringify(c)); } catch (e) {} }

function computeLife(c, sessions) {
  const yearsLeft = Math.max(0, c.lifespan - c.age);
  const daysLeft = Math.round(yearsLeft * 365.25);
  const daysLeftExact = yearsLeft * 365.25;
  const weeksTotal = Math.round(c.lifespan * 52);
  const weeksLived = Math.round(c.age * 52);
  const deathTs = Date.now() + daysLeft * 864e5;
  const upkeep = 3; // meals, hygiene, transit
  const freeHours = Math.max(0, 24 - c.sleep - c.work - c.family - upkeep);
  const sittingsLeft = daysLeft; // one sit a day
  const hoursDone = (sessions || []).reduce((n, s) => n + (s.duration || 0), 0) / 60;
  const practiceHoursLeft = daysLeft * (c.practiceMin / 60);
  const lifetimePractice = hoursDone + practiceHoursLeft;
  const pctOfTarget = c.targetHours > 0 ? lifetimePractice / c.targetHours : 0;
  const minNeededPerDay = daysLeft > 0 ? (c.targetHours * 60) / daysLeft : Infinity;
  const yearsToTarget = c.practiceMin > 0 ? c.targetHours / ((c.practiceMin / 60) * 365.25) : Infinity;
  // the number that actually matters: real time spent meditating, as a continuous span
  const practiceYears = practiceHoursLeft / (24 * 365.25); // years of UNBROKEN sitting
  const practiceDays = practiceHoursLeft / 24;             // days of unbroken sitting
  const wakingYears = practiceHoursLeft / (16 * 365.25);   // in waking-life-equivalent years
  const freeYearsLeft = (freeHours * daysLeft) / (24 * 365.25); // free time, as continuous years
  return { yearsLeft, daysLeft, daysLeftExact, weeksTotal, weeksLived, deathTs, freeHours, sittingsLeft, hoursDone,
    practiceHoursLeft, lifetimePractice, pctOfTarget, minNeededPerDay, yearsToTarget,
    practiceYears, practiceDays, wakingYears, freeYearsLeft };
}

function useNow(active, fast) {
  const [now, setNow] = React.useState(Date.now());
  React.useEffect(() => {
    if (!active) return;
    let id = null;
    const start = () => { if (id == null) id = setInterval(() => setNow(Date.now()), fast ? 50 : 1000); };
    const stop = () => { if (id != null) { clearInterval(id); id = null; } };
    const onVis = () => (document.hidden ? stop() : start());   // don't burn battery in background tabs
    start();
    document.addEventListener('visibilitychange', onVis);
    return () => { stop(); document.removeEventListener('visibilitychange', onVis); };
  }, [active, fast]);
  return now;
}
function nf(n) { return Math.round(n).toLocaleString(); }

// ── animated hourglass — sand drains by `drained` (0..1); always trickling ──
function Hourglass({ drained = 0.5, hue = '#FF9E6B', size = 92, running = true }) {
  const remaining = Math.max(0, Math.min(1, 1 - drained));
  const fill = Math.max(0, Math.min(1, drained));
  // top bulb: downward triangle (10,12)-(50,12)-(30,42); sand rests at neck
  const ySurfTop = 42 - remaining * 30;          // surface line in top bulb
  const hwTop = ((42 - ySurfTop) / 30) * 20;     // half-width at surface
  // bottom bulb: upward triangle apex (30,44) to (10,74)-(50,74); pile grows up
  const ySurfBot = 74 - fill * 30;
  const hwBot = ((74 - ySurfBot) / 30) * 20;
  return (
    <div style={{ position: 'relative', width: size, height: size * 1.28 }}>
      {/* glow */}
      <div style={{ position: 'absolute', inset: '8% 14%', borderRadius: '50%', background: `radial-gradient(circle, ${hexA(hue, 0.28)}, transparent 70%)`,
        animation: running ? 'mtGlowPulse 3.6s ease-in-out infinite' : 'none' }} />
      <svg viewBox="0 0 60 86" style={{ position: 'relative', width: '100%', height: '100%', overflow: 'visible' }}>
        <defs>
          <clipPath id={`hgTop${hue.slice(1)}`}><path d="M10 12 L50 12 L30 43 Z" /></clipPath>
          <clipPath id={`hgBot${hue.slice(1)}`}><path d="M30 43 L50 74 L10 74 Z" /></clipPath>
        </defs>
        {/* frame */}
        <g stroke={hexA(hue, 0.55)} strokeWidth="1.6" fill="none" strokeLinejoin="round" strokeLinecap="round">
          <line x1="8" y1="9" x2="52" y2="9" /><line x1="8" y1="77" x2="52" y2="77" />
          <path d="M12 11 L48 11 L31.5 43 L48 75 L12 75 L28.5 43 Z" fill={hexA(hue, 0.05)} />
        </g>
        {/* top sand (a downward triangle shrinking toward the neck) */}
        {remaining > 0.01 && (
          <path d={`M${30 - hwTop} ${ySurfTop} L${30 + hwTop} ${ySurfTop} L30 43 Z`} fill={hexA(hue, 0.85)} clipPath={`url(#hgTop${hue.slice(1)})`} />
        )}
        {/* bottom pile */}
        {fill > 0.01 && (
          <path d={`M${30 - hwBot} ${ySurfBot} L${30 + hwBot} ${ySurfBot} L50 74 L10 74 Z`} fill={hexA(hue, 0.85)} clipPath={`url(#hgBot${hue.slice(1)})`} />
        )}
        {/* falling stream */}
        {running && remaining > 0.01 && (
          <g>
            <line x1="30" y1="43" x2="30" y2={ySurfBot} stroke={hexA(hue, 0.5)} strokeWidth="1" />
            {[0, 0.45, 0.9, 1.35].map((d, i) => (
              <circle key={i} cx="30" cy="44" r="1.5" fill={hue}
                style={{ '--fall': `${(ySurfBot - 44)}px`, animation: `mtSandFall 1.8s linear ${d}s infinite` }} />
            ))}
          </g>
        )}
      </svg>
    </div>
  );
}

// ── one big timer with hourglass + live value ──
function BigTimer({ hue, drained, label, value, unit, sub, sublive, subms, urgent }) {
  const C = MT_COLORS;
  return (
    <div style={{ position: 'relative', flex: 1, minWidth: 0, borderRadius: 20, padding: '18px 14px 16px',
      border: `1px solid ${hexA(hue, 0.34)}`, background: `radial-gradient(120% 120% at 50% 0%, ${hexA(hue, 0.1)}, rgba(7,16,24,0.5))`,
      display: 'flex', flexDirection: 'column', alignItems: 'center', textAlign: 'center', overflow: 'hidden' }}>
      {urgent && <div style={{ position: 'absolute', inset: 0, background: `radial-gradient(circle at 50% 40%, ${hexA(hue, 0.16)}, transparent 65%)`, animation: 'mtGlowPulse 2.4s ease-in-out infinite', pointerEvents: 'none' }} />}
      <div style={{ position: 'relative' }}>
        <Hourglass hue={hue} drained={drained} size={78} />
      </div>
      <div style={{ position: 'relative', marginTop: 6 }}>
        <MTEyebrow color={hue}>{label}</MTEyebrow>
        <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'center', gap: 5, marginTop: 8 }}>
          <span style={{ fontFamily: 'var(--mono)', fontSize: 32, color: C.ink, lineHeight: 0.95, fontVariantNumeric: 'tabular-nums' }}>{value}</span>
          <span style={{ fontSize: 13, color: C.inkDim }}>{unit}</span>
        </div>
        {sublive && (
          <div style={{ fontFamily: 'var(--mono)', fontSize: 14, color: hue, letterSpacing: 1, marginTop: 6, fontVariantNumeric: 'tabular-nums' }}>
            {sublive}{subms != null && <span style={{ opacity: 0.55, fontSize: 12 }}>.{String(subms).padStart(2, '0')}</span>}
          </div>
        )}
        <div style={{ fontSize: 11, color: C.inkFaint, marginTop: 7, lineHeight: 1.4, maxWidth: 150 }}>{sub}</div>
      </div>
    </div>
  );
}

// breakdown of remaining time into d / h / m / s / ms
function splitRemain(ms) {
  const totalMs = Math.max(0, ms);
  const s = Math.floor(totalMs / 1000);
  return { d: Math.floor(s / 86400), h: Math.floor((s % 86400) / 3600), m: Math.floor((s % 3600) / 60), s: s % 60,
    cs: Math.floor((totalMs % 1000) / 10), ms: Math.floor(totalMs % 1000) };
}

// live meditation-remaining: each real day holds only `practiceMin` minutes of practice,
// so meditation drains in proportion to life. Returns total hours + ticking m/s/cs remainder.
function splitMed(lifeRemainMs, practiceMin) {
  const medMs = Math.max(0, lifeRemainMs * (practiceMin / 1440));
  const hours = Math.floor(medMs / 3.6e6);
  const rem = medMs - hours * 3.6e6;
  return { hours, m: Math.floor(rem / 60000), s: Math.floor((rem % 60000) / 1000), cs: Math.floor((rem % 1000) / 10) };
}

// ── Today card ────────────────────────────────────────────────────
function LifeCard({ cfg, sessions, onOpen }) {
  const C = MT_COLORS;
  const now = useNow(true, true);
  const anchorRef = React.useRef(Date.now());
  React.useEffect(() => { anchorRef.current = Date.now(); }, [cfg.age, cfg.lifespan, cfg.practiceMin]);   // re-anchor on adjust, no countdown jumps
  // timers render immediately with the default life config; Adjust
  // (or tapping through) personalizes it
  const d = computeLife(cfg, sessions);
  const lifeRemainMs = anchorRef.current + d.daysLeftExact * 864e5 - now;
  const r = splitRemain(lifeRemainMs);
  const med = splitMed(lifeRemainMs, cfg.practiceMin);
  return (
    <div style={{ position: 'relative', borderRadius: 24, overflow: 'hidden', marginBottom: 16,
      border: `1px solid ${C.stroke}`, background: 'radial-gradient(130% 120% at 50% -10%, rgba(28,16,14,0.6), rgba(7,16,24,0.65))', padding: '16px 16px 18px' }}>
      <ParticleField count={18} />
      <div style={{ position: 'relative', display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 14 }}>
        <MTEyebrow color="#FF7A6B">Time is the practice</MTEyebrow>
        <button onClick={onOpen} title="Adjust your life & duties" style={{ appearance: 'none', cursor: 'pointer',
          display: 'flex', alignItems: 'center', gap: 6, background: 'rgba(255,255,255,0.04)', border: `1px solid ${C.inkGhost}`,
          borderRadius: 999, padding: '6px 12px', color: C.inkDim, fontSize: 12, fontFamily: 'var(--mono)', letterSpacing: 0.5 }}>
          <MTIcon name="gear" size={14} color={C.inkDim} /> Adjust
        </button>
      </div>
      <div style={{ position: 'relative', display: 'flex', gap: 11 }}>
        <BigTimer hue="#FF7A6B" urgent
          drained={Math.min(1, cfg.age / cfg.lifespan)}
          label="Life remaining"
          value={nf(r.d)} unit="days"
          sublive={`${String(r.h).padStart(2, '0')}:${String(r.m).padStart(2, '0')}:${String(r.s).padStart(2, '0')}`}
          subms={r.cs}
          sub="until this body returns to the earth" />
        <BigTimer hue={C.teal}
          drained={Math.min(1, cfg.age / cfg.lifespan)}
          label="Meditation left"
          value={d.practiceYears >= 1 ? d.practiceYears.toFixed(1) : nf(d.practiceDays)}
          unit={d.practiceYears >= 1 ? 'years' : 'days'}
          sublive={`${nf(med.hours)}h ${String(med.m).padStart(2, '0')}:${String(med.s).padStart(2, '0')}`}
          subms={med.cs}
          sub={`of presence · at ${cfg.practiceMin} min a day`} />
      </div>
      <div onClick={onOpen} style={{ position: 'relative', cursor: 'pointer', textAlign: 'center', marginTop: 14, fontSize: 12, color: C.inkFaint, fontFamily: 'var(--mono)', letterSpacing: 1 }}>
        ≈ {d.yearsLeft} YEARS · {nf(d.sittingsLeft)} SITTINGS LEFT
      </div>
    </div>
  );
}

// ── full screen ───────────────────────────────────────────────────
function LifeWeeks({ cfg }) {
  const ref = React.useRef(null);
  React.useEffect(() => {
    const cv = ref.current; if (!cv) return;
    const parent = cv.parentElement; const W = parent.clientWidth;
    const cols = 52, cell = Math.max(5, Math.floor(W / cols)), rows = cfg.lifespan;
    const H = rows * cell;
    const dpr = window.devicePixelRatio || 1;
    cv.width = W * dpr; cv.height = H * dpr; cv.style.width = W + 'px'; cv.style.height = H + 'px';
    const ctx = cv.getContext('2d'); ctx.scale(dpr, dpr); ctx.clearRect(0, 0, W, H);
    const lived = Math.round(cfg.age * 52), total = rows * cols;
    const rad = Math.max(1.3, cell * 0.32);
    for (let i = 0; i < total; i++) {
      const col = i % cols, row = Math.floor(i / cols);
      const cx = col * cell + cell / 2, cy = row * cell + cell / 2;
      ctx.beginPath(); ctx.arc(cx, cy, rad, 0, 7);
      if (i < lived) { ctx.fillStyle = 'rgba(206,233,230,0.16)'; }
      else if (i === lived) { ctx.fillStyle = '#FF9E6B'; }
      else { ctx.fillStyle = 'rgba(54,232,210,0.5)'; }
      ctx.fill();
    }
  }, [cfg.age, cfg.lifespan]);
  return <canvas ref={ref} style={{ display: 'block', width: '100%' }} />;
}

function LifeSlider({ label, value, min, max, step, fmt, onChange, hue }) {
  const C = MT_COLORS; const c = hue || C.teal;
  const pct = ((value - min) / (max - min)) * 100;
  return (
    <div style={{ marginBottom: 18 }}>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', marginBottom: 9 }}>
        <span style={{ fontSize: 14, color: C.inkDim }}>{label}</span>
        <span style={{ fontFamily: 'var(--mono)', fontSize: 14, color: C.ink }}>{fmt ? fmt(value) : value}</span>
      </div>
      <input type="range" min={min} max={max} step={step} value={value} onChange={e => onChange(parseFloat(e.target.value))}
        style={{ width: '100%', height: 4, appearance: 'none', WebkitAppearance: 'none', borderRadius: 4, outline: 'none', margin: 0,
          background: `linear-gradient(90deg, ${c} ${pct}%, rgba(255,255,255,0.08) ${pct}%)` }} />
    </div>
  );
}

function LifePresets({ cfg, set }) {
  const C = MT_COLORS;
  // additive duties — select all that apply; hours sum into cfg.family
  const presets = [
    ['Living solo', 0.5], ['Partner', 1], ['Young children', 4],
    ['Teenagers', 2], ['Caring for elders', 3], ['Home & pets', 1],
  ];
  const sel = cfg.familySel || [];
  const toggle = (lab) => {
    const next = sel.includes(lab) ? sel.filter(x => x !== lab) : [...sel, lab];
    const sum = Math.min(12, presets.filter(p => next.includes(p[0])).reduce((a, p) => a + p[1], 0));
    set({ familySel: next, family: sum });
  };
  return (
    <div style={{ display: 'flex', flexWrap: 'wrap', gap: 7, marginBottom: 14 }}>
      {presets.map(([lab, h]) => (
        <MTChip key={lab} label={lab} sub active={sel.includes(lab)} onClick={() => toggle(lab)} />
      ))}
    </div>
  );
}

function LifetimeScreen({ cfg, setCfg, sessions, onExit, vp }) {
  const C = MT_COLORS;
  const now = useNow(true, true);
  const anchorRef = React.useRef(Date.now());
  React.useEffect(() => { anchorRef.current = Date.now(); }, [cfg.age, cfg.lifespan, cfg.practiceMin]);   // re-anchor on adjust, no countdown jumps
  const set = (patch) => setCfg({ ...cfg, ...patch, configured: true });
  const d = computeLife(cfg, sessions);
  const lifeRemainMs = anchorRef.current + d.daysLeftExact * 864e5 - now;
  const r = splitRemain(lifeRemainMs);
  const med = splitMed(lifeRemainMs, cfg.practiceMin);
  const onTrack = d.pctOfTarget >= 1;
  const wide = vp.isWide;

  const stat = (val, label, sub, hue) => (
    <MTPanel style={{ padding: '16px 16px', flex: 1, minWidth: 130 }}>
      <div style={{ fontFamily: 'var(--mono)', fontSize: 24, color: hue || C.teal, lineHeight: 1 }}>{val}</div>
      <div style={{ fontSize: 13, color: C.inkDim, marginTop: 6 }}>{label}</div>
      {sub && <div style={{ fontSize: 11.5, color: C.inkFaint, marginTop: 3 }}>{sub}</div>}
    </MTPanel>
  );

  const leftCol = (
    <React.Fragment>
      {/* two timers — the whole point: mortality, and the meditation within it */}
      <div style={{ display: 'flex', gap: 12, marginBottom: 16 }}>
        <BigTimer hue="#FF7A6B" urgent
          drained={Math.min(1, cfg.age / cfg.lifespan)}
          label="Life remaining"
          value={nf(r.d)} unit="days"
          sublive={`${String(r.h).padStart(2, '0')}:${String(r.m).padStart(2, '0')}:${String(r.s).padStart(2, '0')}`}
          subms={r.cs}
          sub="until this body returns to the earth" />
        <BigTimer hue={C.teal}
          drained={Math.min(1, cfg.age / cfg.lifespan)}
          label="Meditation remaining"
          value={d.practiceYears >= 1 ? d.practiceYears.toFixed(1) : nf(d.practiceDays)}
          unit={d.practiceYears >= 1 ? 'years' : 'days'}
          sublive={`${nf(med.hours)}h ${String(med.m).padStart(2, '0')}:${String(med.s).padStart(2, '0')}`}
          subms={med.cs}
          sub={`of actual presence · at ${cfg.practiceMin} min a day`} />
      </div>
      <div style={{ textAlign: 'center', marginBottom: 20, fontSize: 12.5, color: C.inkFaint, fontFamily: 'var(--mono)', letterSpacing: 1 }}>
        ≈ {d.yearsLeft} YEARS · {nf(d.sittingsLeft)} SITTINGS LEFT
      </div>
      {/* life in weeks */}
      <MTPanel style={{ padding: 16, marginBottom: 14 }}>
        <div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 12 }}>
          <MTEyebrow>Your life in weeks</MTEyebrow>
          <span style={{ fontSize: 11, color: C.inkFaint, fontFamily: 'var(--mono)' }}>each dot = 1 week</span>
        </div>
        <LifeWeeks cfg={cfg} />
        <div style={{ display: 'flex', gap: 16, marginTop: 12, flexWrap: 'wrap' }}>
          <span style={{ display: 'flex', alignItems: 'center', gap: 6, fontSize: 11, color: C.inkDim }}><span style={{ width: 8, height: 8, borderRadius: 8, background: 'rgba(206,233,230,0.2)' }} /> lived</span>
          <span style={{ display: 'flex', alignItems: 'center', gap: 6, fontSize: 11, color: C.inkDim }}><span style={{ width: 8, height: 8, borderRadius: 8, background: '#FF9E6B' }} /> this week</span>
          <span style={{ display: 'flex', alignItems: 'center', gap: 6, fontSize: 11, color: C.inkDim }}><span style={{ width: 8, height: 8, borderRadius: 8, background: hexA(C.teal, 0.5) }} /> still yours</span>
        </div>
      </MTPanel>
    </React.Fragment>
  );

  const rightCol = (
    <React.Fragment>
      {/* stats */}
      <div style={{ display: 'flex', gap: 10, marginBottom: 10, flexWrap: 'wrap' }}>
        {stat(nf(d.sittingsLeft), 'sittings left', 'at one a day')}
        {stat(nf(d.practiceHoursLeft), 'practice hours', `at ${cfg.practiceMin} min/day`)}
      </div>
      <div style={{ display: 'flex', gap: 10, marginBottom: 18, flexWrap: 'wrap' }}>
        {stat(d.freeHours.toFixed(1) + 'h', 'free each day', 'after sleep, work, care', '#FF9E6B')}
        {stat(nf(d.hoursDone) + 'h', 'logged so far', `${sessions.length} sittings`)}
      </div>

      {/* path mirror */}
      <MTPanel hi style={{ padding: 18, marginBottom: 18 }}>
        <MTEyebrow color={onTrack ? C.teal : '#FF9E6B'}>The path ahead</MTEyebrow>
        <div style={{ margin: '12px 0 12px' }}>
          <div style={{ height: 8, borderRadius: 8, background: 'rgba(255,255,255,0.06)', overflow: 'hidden' }}>
            <div style={{ width: `${Math.min(100, d.pctOfTarget * 100)}%`, height: '100%', borderRadius: 8, background: onTrack ? `linear-gradient(90deg, ${C.teal}, ${C.blue})` : 'linear-gradient(90deg, #FF9E6B, #FF6B8A)' }} />
          </div>
          <div style={{ display: 'flex', justifyContent: 'space-between', marginTop: 7, fontFamily: 'var(--mono)', fontSize: 11.5, color: C.inkFaint }}>
            <span>{nf(d.lifetimePractice)}h projected</span><span>{nf(cfg.targetHours)}h aspiration</span>
          </div>
        </div>
        <p style={{ fontSize: 14.5, lineHeight: 1.55, color: C.inkDim, margin: 0, textWrap: 'pretty' }}>
          {onTrack
            ? `At ${cfg.practiceMin} minutes a day you'll log about ${nf(d.practiceHoursLeft)} more hours — enough to meet your ${nf(cfg.targetHours)}-hour aspiration with years to spare. Keep the continuity unbroken.`
            : `At ${cfg.practiceMin} minutes a day you'll reach roughly ${nf(d.lifetimePractice)} hours — about ${Math.round(d.pctOfTarget * 100)}% of your ${nf(cfg.targetHours)}-hour aspiration. To close the gap within this life you'd need about ${nf(d.minNeededPerDay)} minutes a day.`}
        </p>
      </MTPanel>

      {/* config */}
      <MTPanel style={{ padding: 18, marginBottom: 18 }}>
        <MTEyebrow>Your life, honestly</MTEyebrow>
        <div style={{ height: 14 }} />
        <LifeSlider label="Your age" value={cfg.age} min={12} max={90} step={1} fmt={v => v + ' yrs'} onChange={v => set({ age: v })} />
        <LifeSlider label="Expected lifespan" value={cfg.lifespan} min={Math.max(cfg.age + 1, 50)} max={105} step={1} fmt={v => v + ' yrs'} onChange={v => set({ lifespan: v })} />
        <LifeSlider label="Sleep" value={cfg.sleep} min={4} max={11} step={0.5} fmt={v => v + ' h/day'} onChange={v => set({ sleep: v })} />
        <LifeSlider label="Work & jobs" value={cfg.work} min={0} max={16} step={0.5} fmt={v => v + ' h/day'} onChange={v => set({ work: v })} hue="#FF9E6B" />
        <div style={{ fontSize: 14, color: C.inkDim, marginBottom: 9 }}>Family &amp; care duties <span style={{ color: C.inkFaint, fontSize: 12 }}>· select all that apply</span></div>
        <LifePresets cfg={cfg} set={set} />
        <LifeSlider label="Fine-tune" value={cfg.family} min={0} max={12} step={0.5} fmt={v => v + ' h/day'} onChange={v => set({ family: v })} hue="#FF9E6B" />
        <div style={{ height: 6 }} />
        <LifeSlider label="Daily practice intention" value={cfg.practiceMin} min={5} max={180} step={5} fmt={v => v + ' min'} onChange={v => set({ practiceMin: v })} />
        <LifeSlider label="Hours toward deep insight" value={cfg.targetHours} min={250} max={5000} step={250} fmt={v => nf(v) + ' h'} onChange={v => set({ targetHours: v })} />
      </MTPanel>

      <QuoteBlock theme="urgency" shuffle align={wide ? 'left' : 'center'} />

      <p style={{ fontSize: 12.5, lineHeight: 1.6, color: C.inkFaint, marginTop: 20, textWrap: 'pretty', textAlign: wide ? 'left' : 'center' }}>
        No one can clock the path to awakening — these numbers are a mirror for your pace and your mortality, not a promise. Dipa Ma reached deep realization as a grieving widow raising a child. The point is not arithmetic. It is to begin, now.
      </p>
    </React.Fragment>
  );

  return (
    <div style={{ position: 'fixed', inset: 0, background: `radial-gradient(120% 70% at 50% 0%, #1a1310 0%, ${C.bg} 55%)`, color: C.ink, overflow: 'auto' }}>
      <ParticleField count={30} />
      <div style={{ position: 'sticky', top: 0, zIndex: 20, display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: 'calc(env(safe-area-inset-top,0px) + 18px) 20px 14px', background: 'linear-gradient(180deg, rgba(8,12,15,0.85), rgba(8,12,15,0))' }}>
        <button onClick={onExit} style={{ appearance: 'none', cursor: 'pointer', background: 'rgba(255,255,255,0.06)', border: `1px solid ${C.inkGhost}`, borderRadius: 999, padding: '8px 16px', color: C.inkDim, fontSize: 13, fontFamily: 'var(--mono)' }}>Close</button>
        <span style={{ fontFamily: 'var(--serif)', fontStyle: 'italic', fontSize: 17, color: C.inkDim }}>Samvega</span>
        <span style={{ width: 60 }} />
      </div>
      <div style={{ maxWidth: wide ? 1000 : 600, margin: '0 auto', width: '100%', boxSizing: 'border-box', padding: '4px 20px 50px', position: 'relative' }}>
        <div style={{ textAlign: 'center', marginBottom: 22 }}>
          <h1 style={{ font: '300 30px/1.15 var(--serif)', margin: '0 0 8px' }}>A sense of urgency</h1>
          <p style={{ fontSize: 14.5, color: C.inkFaint, margin: 0, maxWidth: 440, marginInline: 'auto', textWrap: 'pretty' }}>
            Samvega — the sobering awareness that life is short and the work is real.
          </p>
        </div>
        {wide ? (
          <div style={{ display: 'flex', gap: 28, alignItems: 'flex-start' }}>
            <div style={{ flex: '1 1 46%', minWidth: 0 }}>{leftCol}</div>
            <div style={{ flex: '1 1 54%', minWidth: 0 }}>{rightCol}</div>
          </div>
        ) : (
          <React.Fragment>{leftCol}{rightCol}</React.Fragment>
        )}
      </div>
    </div>
  );
}

Object.assign(window, { mtLoadLife, mtSaveLife, computeLife, LifeCard, LifetimeScreen, useNow });
