// minimal-views.jsx — the 6 tab views for Reisetagebuch

(function () {
  const { useState, useMemo, useEffect } = React;
  const {
    fmtEUR, fmtEURshort, fmtDate, fmtDateLong, fmtWeekday,
    expDate, expTime, expCat, expDesc, expLoc, expAmt,
    tripStart, tripEnd, tripBudget, tripFlag, todayISO,
    dayTotal: _dayTotal, tripDays: _tripDays, tripDayNum: _tripDayNum, tripLength: _tripLength,
    tripSpent: _tripSpent, tripRemaining: _tripRemaining,
    daysPassed: _daysPassed, daysLeft: _daysLeft,
    avgPerDay: _avgPerDay, recommendedPerDay: _recommendedPerDay,
    tripWeeks: _tripWeeks, uniqueLocs: _uniqueLocs, catTotals: _catTotals,
    Icon,
    MinPalette: p, MinF: F,
    useCats, useNav,
    MinEyebrow: Eyebrow, MinHRule: HRule, MinCatMark: CatMark,
    MinMetric: Metric, MinPchip: Pchip, MinListRow: ListRow,
    MinEmptyState: EmptyState,
  } = window;
  const { useData } = window.UKProviders;

  // Mapping: backend-shape (date/time/category_id/amount_cents/...) → mock-shape (d/t/cat/amt/...)
  const toLegacy = (e) => ({
    ...e,
    id: e.id,
    d: expDate(e), t: expTime(e),
    cat: expCat(e), amt: expAmt(e),
    desc: expDesc(e) || '',
    loc: expLoc(e) || '',
  });
  const tripToLegacy = (t) => t ? ({
    ...t,
    id: t.id, name: t.name, flag: tripFlag(t),
    start: tripStart(t), end: tripEnd(t),
    budget: tripBudget(t),
    active: !!t.active,
  }) : null;

  function useViewCtx() {
    const { activeTrip, expenses } = useData();
    const trip = tripToLegacy(activeTrip);
    const tripExpsRaw = activeTrip ? expenses.filter(e => e.trip_id === activeTrip.id) : [];
    const exps = tripExpsRaw.map(toLegacy);
    const today = todayISO();
    return {
      ACTIVE_TRIP: trip,
      EXPENSES: exps,
      TODAY: today,
      dayTotal:          (iso) => _dayTotal(iso, exps),
      tripDays:          ()    => _tripDays(activeTrip),
      tripLength:        ()    => _tripLength(activeTrip),
      tripDayNum:        (iso) => _tripDayNum(iso, activeTrip),
      daysPassed:        ()    => _daysPassed(activeTrip, today),
      daysLeft:          ()    => _daysLeft(activeTrip, today),
      tripSpent:         ()    => _tripSpent(exps),
      tripRemaining:     ()    => _tripRemaining(activeTrip, exps),
      avgPerDay:         ()    => _avgPerDay(activeTrip, exps, today),
      recommendedPerDay: ()    => _recommendedPerDay(activeTrip, exps, today),
      tripWeeks:         ()    => _tripWeeks(activeTrip),
      uniqueLocs:        ()    => _uniqueLocs(exps),
    };
  }

  // Local cat-totals that respect user-added categories
  const makeCatTotalsFor = (exps) => (cats) => {
    const totals = {};
    for (const e of exps) totals[e.cat] = (totals[e.cat] || 0) + e.amt;
    return cats
      .map(c => ({ ...c, total: totals[c.id] || 0 }))
      .filter(c => c.total > 0)
      .sort((a, b) => b.total - a.total);
  };

  const noTripGuard = () => <EmptyState title="Noch keine Reise" hint="Lege in den Einstellungen oder über die Reisen-Übersicht deine erste Reise an."/>;

  // ── Heute (Home) ────────────────────────────────────────────
  function HeuteView() {
    const ctx = useViewCtx();
    if (!ctx.ACTIVE_TRIP) return noTripGuard();
    const { ACTIVE_TRIP, EXPENSES, TODAY, dayTotal, tripSpent, tripRemaining,
            recommendedPerDay, daysLeft, daysPassed, avgPerDay } = ctx;
    const { catById } = useCats();
    const { openExpense } = useNav();
    const today = EXPENSES.filter(e => e.d === TODAY).sort((a,b) => a.t.localeCompare(b.t));
    const total = dayTotal(TODAY);
    const trip = tripSpent();
    const remaining = tripRemaining();
    const rec = recommendedPerDay();

    return (
      <div style={{ padding: '0 0 120px' }}>
        <div style={{ padding: '20px 24px 8px' }}>
          <Eyebrow>{fmtDateLong(TODAY)}</Eyebrow>
          <div style={{ display: 'flex', alignItems: 'baseline', gap: 12, marginTop: 8 }}>
            <div style={{ fontFamily: F, fontSize: 50, color: p.ink, fontWeight: 600, lineHeight: 1, letterSpacing: -2 }}>
              {total.toLocaleString('de-DE', { minimumFractionDigits: 2 })}<span style={{ color: p.muted, fontWeight: 400 }}> €</span>
            </div>
          </div>
          <div style={{ fontFamily: F, fontSize: 13, color: p.muted, marginTop: 4 }}>
            heute ausgegeben · {today.length} Einträge
          </div>
          <div style={{
            background: p.paper2, border: `1px solid ${p.line}`, borderRadius: 8,
            padding: '10px 14px', marginTop: 14, fontFamily: F, fontSize: 12, color: p.muted, lineHeight: 1.5,
          }}>
            Verbleibend für {daysLeft()} Tage: <b style={{ color: p.ink, fontWeight: 600 }}>{fmtEUR(remaining)}</b> ·
            empfohlen <b style={{ color: p.accent, fontWeight: 600 }}>{fmtEUR(rec)}</b> pro Tag.
          </div>
        </div>

        <HRule label="Heutiger Tagesablauf" />

        {today.length === 0 ? (
          <div style={{ padding: '30px 24px', fontFamily: F, fontSize: 14, color: p.muted, textAlign: 'center' }}>
            Noch keine Einträge für heute.
          </div>
        ) : (
          <div style={{ padding: '0 24px' }}>
            {today.map((e, i) => {
              const c = catById[e.cat];
              return (
                <button key={e.id} onClick={() => openExpense(e.id)} style={{
                  width: '100%', display: 'flex', gap: 14, paddingBottom: 14, position: 'relative',
                  border: 0, background: 'transparent', textAlign: 'left', cursor: 'pointer', padding: '0 0 14px',
                }}>
                  <div style={{ width: 44, flexShrink: 0, paddingTop: 4 }}>
                    <div style={{ fontFamily: F, fontSize: 13, color: p.ink, fontWeight: 500 }}>{e.t}</div>
                  </div>
                  <div style={{ width: 12, flexShrink: 0, position: 'relative' }}>
                    <div style={{ position: 'absolute', left: 5, top: 6, bottom: i === today.length - 1 ? 6 : -14,
                      width: 1, background: p.line2 }}/>
                    <div style={{ position: 'absolute', left: 2, top: 6, width: 8, height: 8, borderRadius: 4,
                      background: p.paper, border: `1.5px solid ${c ? c.color : p.accent}` }}/>
                  </div>
                  <div style={{ flex: 1, minWidth: 0, paddingBottom: 2 }}>
                    <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', gap: 10 }}>
                      <div style={{ fontFamily: F, fontSize: 15, color: p.ink, fontWeight: 500, minWidth: 0,
                        whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>
                        {e.desc}
                      </div>
                      <div style={{ fontFamily: F, fontSize: 15, color: p.ink, fontWeight: 600 }}>
                        {fmtEUR(e.amt)}
                      </div>
                    </div>
                    <div style={{ fontFamily: F, fontSize: 11, color: p.muted, marginTop: 1 }}>
                      {c ? c.label : '—'} · {e.loc}
                    </div>
                  </div>
                </button>
              );
            })}
          </div>
        )}

        <HRule label="Bisher auf der Reise" />
        <div style={{ padding: '0 24px', display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 20 }}>
          <Metric label="Gesamt" value={fmtEUR(trip)} sub={`${EXPENSES.length} Einträge`}/>
          <Metric label="Ø pro Tag" value={fmtEUR(avgPerDay())} sub={`über ${daysPassed()} Tage`}/>
        </div>
      </div>
    );
  }

  // ── Woche ───────────────────────────────────────────────────
  function WocheView() {
    const ctx = useViewCtx();
    if (!ctx.ACTIVE_TRIP) return noTripGuard();
    const { TODAY, dayTotal, tripDayNum, tripWeeks, daysPassed } = ctx;
    const { openDay } = useNav();
    const weeks = tripWeeks();
    const [wi, setWi] = useState(0);
    const days = weeks[wi];
    const totals = days.map(d => dayTotal(d));
    const max = Math.max(...totals, 1);
    const total = totals.reduce((s,x)=>s+x,0);

    return (
      <div style={{ padding: '0 0 120px' }}>
        <div style={{ padding: '20px 24px 0' }}>
          <Eyebrow>{`Woche ${wi+1} von ${weeks.length}`}</Eyebrow>
          <div style={{ fontFamily: F, fontSize: 22, color: p.ink, fontWeight: 500, marginTop: 4 }}>
            {fmtDate(days[0])} – {fmtDate(days[days.length-1])}
          </div>
          <div style={{ display: 'flex', alignItems: 'baseline', gap: 12, marginTop: 14 }}>
            <div style={{ fontFamily: F, fontSize: 38, color: p.ink, fontWeight: 600, lineHeight: 1, letterSpacing: -1.5 }}>
              {total.toLocaleString('de-DE', { minimumFractionDigits: 2 })}
              <span style={{ color: p.muted, fontWeight: 400 }}> €</span>
            </div>
            <div style={{ fontFamily: F, fontSize: 13, color: p.muted }}>insgesamt</div>
          </div>
          <div style={{ display: 'flex', gap: 16, marginTop: 12 }}>
            {weeks.map((_, i) => (
              <button key={i} onClick={() => setWi(i)} style={{
                border: 0, background: 'transparent', cursor: 'pointer',
                fontFamily: F, fontSize: 13, fontWeight: 500,
                color: i === wi ? p.ink : p.muted,
                padding: '4px 0', borderBottom: i === wi ? `2px solid ${p.accent}` : `2px solid transparent`,
              }}>Woche {i+1}</button>
            ))}
          </div>
        </div>

        <HRule label="Tagesbilanz" />
        <div style={{ padding: '0 24px' }}>
          {days.map((d, i) => {
            const v = totals[i];
            const future = tripDayNum(d) > daysPassed();
            const today = d === TODAY;
            return (
              <button key={d} onClick={() => !future && openDay(d)} style={{
                width: '100%', border: 0, background: 'transparent', textAlign: 'left',
                cursor: future ? 'default' : 'pointer', padding: '10px 0',
                borderBottom: i === days.length - 1 ? 0 : `1px solid ${p.rule}`,
                opacity: future ? 0.45 : 1,
                display: 'flex', alignItems: 'center', gap: 14,
              }}>
                <div style={{ width: 50 }}>
                  <Eyebrow style={{ fontSize: 9 }}>{fmtWeekday(d)} {today ? '· heute' : ''}</Eyebrow>
                  <div style={{ fontFamily: F, fontSize: 18, color: p.ink, fontWeight: 600, lineHeight: 1 }}>
                    {new Date(d+'T00:00:00').getDate()}
                  </div>
                </div>
                <div style={{ flex: 1, height: 1, background: p.rule, position: 'relative', marginTop: 2 }}>
                  <div style={{
                    position: 'absolute', left: 0, top: -3, height: 6,
                    width: future ? '0%' : `${(v/max)*100}%`,
                    background: today ? p.rust : p.accent,
                    borderRadius: 1,
                  }}/>
                </div>
                <div style={{ width: 80, textAlign: 'right' }}>
                  <div style={{ fontFamily: F, fontSize: 14, color: future ? p.muted : p.ink, fontWeight: 600 }}>
                    {future ? '—' : fmtEUR(v)}
                  </div>
                  <div style={{ fontFamily: F, fontSize: 10, color: p.muted }}>Tag {tripDayNum(d)}</div>
                </div>
              </button>
            );
          })}
        </div>
      </div>
    );
  }

  // ── Donut chart (with tooltip-style legend on hover/tap) ────
  function Donut({ cats, total, size = 200, thickness = 36 }) {
    const [active, setActive] = useState(null);
    const r2 = size / 2 - 4;
    const r1 = r2 - thickness;
    const cx = size / 2, cy = size / 2;
    let cum = -90;
    const polar = (r, a) => [cx + r*Math.cos(a*Math.PI/180), cy + r*Math.sin(a*Math.PI/180)];
    const arc = (s, e) => {
      const [x1,y1] = polar(r2,s);
      const [x2,y2] = polar(r2,e);
      const [x3,y3] = polar(r1,e);
      const [x4,y4] = polar(r1,s);
      const big = e - s > 180 ? 1 : 0;
      return `M ${x1} ${y1} A ${r2} ${r2} 0 ${big} 1 ${x2} ${y2} L ${x3} ${y3} A ${r1} ${r1} 0 ${big} 0 ${x4} ${y4} Z`;
    };
    const segs = cats.map(c => {
      const a = (c.total/total)*360;
      const s = cum, e = cum + a - 0.6; cum += a;
      return { ...c, s, e, a };
    });
    const activeSeg = segs.find(s => s.id === active);

    return (
      <div style={{ display: 'flex', alignItems: 'center', gap: 14 }}>
        <div style={{ position: 'relative', width: size, height: size, flexShrink: 0 }}>
          <svg width={size} height={size} viewBox={`0 0 ${size} ${size}`}>
            {segs.map(s => (
              <path key={s.id} d={arc(s.s, s.e)} fill={s.color}
                onMouseEnter={() => setActive(s.id)}
                onMouseLeave={() => setActive(null)}
                onClick={() => setActive(a => a === s.id ? null : s.id)}
                style={{
                  cursor: 'pointer',
                  opacity: active && active !== s.id ? 0.35 : 1,
                  transformOrigin: 'center', transition: 'opacity 0.18s, transform 0.18s',
                  transform: active === s.id ? 'scale(1.03)' : 'none',
                }}/>
            ))}
          </svg>
          {/* Center */}
          <div style={{
            position: 'absolute', inset: 0, display: 'flex', flexDirection: 'column',
            alignItems: 'center', justifyContent: 'center', pointerEvents: 'none',
            padding: 30, textAlign: 'center',
          }}>
            <Eyebrow style={{ fontSize: 9 }}>
              {activeSeg ? activeSeg.label : 'Gesamt'}
            </Eyebrow>
            <div style={{ fontFamily: F, fontSize: 22, color: p.ink, fontWeight: 600, marginTop: 2, letterSpacing: -0.5 }}>
              {activeSeg ? fmtEURshort(activeSeg.total) : fmtEURshort(total)}
            </div>
            {activeSeg && (
              <div style={{ fontFamily: F, fontSize: 11, color: p.muted, marginTop: 2 }}>
                {Math.round(activeSeg.total/total*100)}%
              </div>
            )}
          </div>
        </div>
        {/* Legend */}
        <div style={{ flex: 1, display: 'flex', flexDirection: 'column', gap: 6, minWidth: 0 }}>
          {segs.slice(0, 6).map(s => (
            <div key={s.id}
              onMouseEnter={() => setActive(s.id)} onMouseLeave={() => setActive(null)}
              style={{
                display: 'flex', alignItems: 'center', gap: 7, fontFamily: F, fontSize: 11,
                opacity: active && active !== s.id ? 0.4 : 1, transition: 'opacity 0.15s',
              }}>
              <span style={{ width: 10, height: 10, borderRadius: 2, background: s.color, flexShrink: 0 }}/>
              <span style={{ flex: 1, color: p.ink, fontWeight: 500, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{s.label}</span>
              <span style={{ color: p.muted, fontFamily: F, fontWeight: 500 }}>{Math.round(s.total/total*100)}%</span>
            </div>
          ))}
        </div>
      </div>
    );
  }

  // ── Reise (Trip overview WITH donut + line chart) ──────────
  function ReiseView() {
    const ctx = useViewCtx();
    if (!ctx.ACTIVE_TRIP) return noTripGuard();
    const { ACTIVE_TRIP, EXPENSES, TODAY, dayTotal, tripSpent, tripDays,
            tripDayNum, tripLength, daysPassed } = ctx;
    const { cats: allCats } = useCats();
    const { openCat } = useNav();
    const spent = tripSpent();
    const budget = ACTIVE_TRIP.budget;
    const cats = makeCatTotalsFor(EXPENSES)(allCats);
    const days = tripDays();
    const maxDay = Math.max(...days.map(d => dayTotal(d)), 1);
    const max = Math.max(...cats.map(c => c.total), 1);

    return (
      <div style={{ padding: '0 0 120px' }}>
        <div style={{ padding: '20px 24px 0' }}>
          <Eyebrow>Gesamte Reise</Eyebrow>
          <div style={{ display: 'flex', alignItems: 'baseline', gap: 16, marginTop: 8 }}>
            <div style={{ fontFamily: F, fontSize: 50, color: p.ink, fontWeight: 600, lineHeight: 1, letterSpacing: -2 }}>
              {spent.toLocaleString('de-DE', { minimumFractionDigits: 0, maximumFractionDigits: 0 })}
              <span style={{ color: p.muted, fontWeight: 400 }}> €</span>
            </div>
            <div style={{ fontFamily: F, fontSize: 13, color: p.muted }}>
              von {budget.toLocaleString('de-DE')} €
            </div>
          </div>
          <div style={{ marginTop: 14, height: 2, background: p.line, position: 'relative' }}>
            <div style={{ position: 'absolute', left: 0, top: 0, height: 2, width: `${spent/budget*100}%`, background: p.accent }}/>
            <div style={{ position: 'absolute', left: `${daysPassed()/tripLength()*100}%`, top: -3, width: 1, height: 8, background: p.rust }}/>
          </div>
          <div style={{ display: 'flex', justifyContent: 'space-between', marginTop: 6, fontFamily: F, fontSize: 11, color: p.muted }}>
            <span><b style={{ color: p.ink, fontWeight: 600 }}>{Math.round(spent/budget*100)}%</b> verbraucht</span>
            <span>zeitlich <b style={{ color: p.rust, fontWeight: 600 }}>{Math.round(daysPassed()/tripLength()*100)}%</b></span>
          </div>
        </div>

        <HRule label="Verteilung nach Rubrik" />
        <div style={{ padding: '0 18px' }}>
          <Donut cats={cats} total={spent} />
        </div>

        <HRule label="Rubriken im Detail" />
        <div style={{ padding: '0 24px' }}>
          {cats.map((c, i) => (
            <button key={c.id} onClick={() => openCat(c.id)} style={{
              width: '100%', border: 0, background: 'transparent', textAlign: 'left',
              padding: '12px 0', borderBottom: i === cats.length - 1 ? 0 : `1px solid ${p.rule}`,
              cursor: 'pointer',
            }}>
              <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', gap: 10 }}>
                <div style={{ display: 'flex', alignItems: 'center', gap: 10, minWidth: 0 }}>
                  <CatMark cat={c} size={26}/>
                  <div>
                    <div style={{ fontFamily: F, fontSize: 14, color: p.ink, fontWeight: 500 }}>{c.label}</div>
                    <div style={{ fontFamily: F, fontSize: 11, color: p.muted }}>
                      {EXPENSES.filter(e => e.cat === c.id).length} Einträge
                    </div>
                  </div>
                </div>
                <div style={{ textAlign: 'right' }}>
                  <div style={{ fontFamily: F, fontSize: 15, color: p.ink, fontWeight: 600 }}>{fmtEUR(c.total)}</div>
                  <div style={{ fontFamily: F, fontSize: 10, color: p.muted }}>{Math.round(c.total/spent*100)}%</div>
                </div>
              </div>
              <div style={{ height: 2, background: p.line, marginTop: 8, position: 'relative' }}>
                <div style={{ position: 'absolute', left: 0, top: 0, height: 2, width: `${c.total/max*100}%`, background: c.color }}/>
              </div>
            </button>
          ))}
        </div>

        <HRule label="Tageskurve" />
        <div style={{ padding: '0 24px' }}>
          <svg viewBox="0 0 380 110" style={{ width: '100%', height: 110 }}>
            {(() => {
              const W = 380, H = 110, n = days.length;
              const xs = days.map((_, i) => 10 + (i/(n-1)) * (W-20));
              const ys = days.map(d => H - 14 - (dayTotal(d)/maxDay) * (H-30));
              const pts = xs.map((x, i) => `${x},${ys[i]}`).join(' ');
              const today = tripDayNum(TODAY) - 1;
              return (
                <>
                  <line x1="10" y1={H-14} x2={W-10} y2={H-14} stroke={p.line} strokeWidth="1"/>
                  <polyline points={pts} fill="none" stroke={p.accent} strokeWidth="1.5"/>
                  {days.map((d, i) => {
                    const past = tripDayNum(d) <= daysPassed();
                    return past ? (
                      <circle key={d} cx={xs[i]} cy={ys[i]} r="2.5" fill={p.paper} stroke={p.accent} strokeWidth="1.5"/>
                    ) : null;
                  })}
                  <line x1={xs[today]} y1="6" x2={xs[today]} y2={H-14} stroke={p.rust} strokeDasharray="2 2" strokeWidth="1"/>
                  <text x={xs[today]} y="14" textAnchor="middle" style={{ fontFamily: F, fontSize: 9, fill: p.rust, fontWeight: 600 }}>Heute</text>
                  {days.map((d, i) => i % 2 === 0 && (
                    <text key={d} x={xs[i]} y={H-2} textAnchor="middle" style={{ fontFamily: F, fontSize: 9, fill: p.muted }}>
                      {fmtDate(d).split(' ')[0]}.
                    </text>
                  ))}
                </>
              );
            })()}
          </svg>
        </div>
      </div>
    );
  }

  // ── Liste (Table view) ──────────────────────────────────────
  function ListeView() {
    const ctx = useViewCtx();
    if (!ctx.ACTIVE_TRIP) return noTripGuard();
    const { EXPENSES } = ctx;
    const { cats: allCats, catById } = useCats();
    const { openExpense } = useNav();
    const [q, setQ] = useState('');
    const [sortBy, setSortBy] = useState('date');
    const [catFilter, setCatFilter] = useState(null);

    const filtered = useMemo(() => {
      let arr = [...EXPENSES];
      if (catFilter) arr = arr.filter(e => e.cat === catFilter);
      if (q) {
        const qq = q.toLowerCase();
        arr = arr.filter(e =>
          (e.desc || '').toLowerCase().includes(qq) ||
          (e.loc || '').toLowerCase().includes(qq) ||
          (catById[e.cat] && catById[e.cat].label.toLowerCase().includes(qq))
        );
      }
      if (sortBy === 'date') arr.sort((a,b) => ((b.d || '')+(b.t || '')).localeCompare((a.d || '')+(a.t || '')));
      if (sortBy === 'amt') arr.sort((a,b) => b.amt - a.amt);
      if (sortBy === 'cat') arr.sort((a,b) => (a.cat || '').localeCompare(b.cat || ''));
      return arr;
    }, [q, sortBy, catFilter, catById, EXPENSES]);

    const grouped = useMemo(() => {
      if (sortBy !== 'date') return null;
      const out = {};
      for (const e of filtered) (out[e.d] = out[e.d] || []).push(e);
      return Object.entries(out);
    }, [filtered, sortBy]);

    const availableCats = allCats.filter(c => EXPENSES.some(e => e.cat === c.id));

    return (
      <div style={{ padding: '0 0 120px' }}>
        <div style={{ padding: '16px 24px 0' }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 8, padding: '8px 12px',
            background: p.paper2, border: `1px solid ${p.line}`, borderRadius: 4, color: p.muted }}>
            <Icon.search/>
            <input value={q} onChange={e=>setQ(e.target.value)} placeholder="Durchsuchen …"
              style={{ border: 0, background: 'transparent', flex: 1, color: p.ink, fontFamily: F, fontSize: 14, outline: 'none' }}/>
            {q && <button onClick={() => setQ('')} style={{ border: 0, background: 'transparent', color: p.muted, cursor: 'pointer' }}>×</button>}
          </div>
        </div>

        <div style={{ padding: '12px 24px 0', display: 'flex', gap: 6, overflowX: 'auto', scrollbarWidth: 'none' }}>
          <Pchip active={!catFilter} onClick={() => setCatFilter(null)}>Alle</Pchip>
          {availableCats.map(c => (
            <Pchip key={c.id} active={catFilter === c.id} onClick={() => setCatFilter(catFilter === c.id ? null : c.id)}>
              {c.emoji} {c.label}
            </Pchip>
          ))}
        </div>

        <div style={{ padding: '10px 24px 4px', display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
          <Eyebrow>{filtered.length} Einträge · {fmtEUR(filtered.reduce((s, e) => s + e.amt, 0))}</Eyebrow>
          <div style={{ display: 'flex', gap: 10 }}>
            {[['date','Datum'],['amt','Betrag'],['cat','Rubrik']].map(([k,l]) => (
              <button key={k} onClick={() => setSortBy(k)} style={{
                border: 0, background: 'transparent', padding: 0,
                fontFamily: F, fontSize: 11, fontWeight: 600,
                color: sortBy === k ? p.accent : p.muted,
                textDecoration: sortBy === k ? 'underline' : 'none',
                textUnderlineOffset: 3, cursor: 'pointer',
              }}>{l}</button>
            ))}
          </div>
        </div>

        <div style={{ padding: '0 24px' }}>
          {grouped ? grouped.map(([d, items]) => (
            <div key={d}>
              <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline',
                padding: '14px 0 6px', borderBottom: `1px solid ${p.line}`, marginBottom: 4 }}>
                <div style={{ fontFamily: F, fontSize: 13, color: p.ink, fontWeight: 600 }}>
                  {fmtDate(d, { year: 'numeric' })}
                </div>
                <div style={{ fontFamily: F, fontSize: 11, color: p.muted }}>
                  {fmtEUR(items.reduce((s, e) => s + e.amt, 0))} · {items.length} Einträge
                </div>
              </div>
              {items.map(e => <ListRow key={e.id} e={e} onClick={() => openExpense(e.id)}/>)}
            </div>
          )) : filtered.map(e => <ListRow key={e.id} e={e} onClick={() => openExpense(e.id)}/>)}
          {filtered.length === 0 && (
            <div style={{ padding: 40, textAlign: 'center', fontFamily: F, color: p.muted, fontSize: 14 }}>
              Nichts gefunden.
            </div>
          )}
        </div>
      </div>
    );
  }

  // ── Rubrik / Kalender ───────────────────────────────────────
  function RubrikView() {
    const ctx = useViewCtx();
    if (!ctx.ACTIVE_TRIP) return noTripGuard();
    const { EXPENSES, TODAY, dayTotal, tripSpent, tripDays, tripDayNum, daysPassed } = ctx;
    const { cats: allCats } = useCats();
    const { openCat, openDay } = useNav();
    const cats = makeCatTotalsFor(EXPENSES)(allCats);
    const total = tripSpent();

    const days = tripDays();
    const start = new Date(days[0]+'T00:00:00');
    const monthStart = new Date(start.getFullYear(), start.getMonth(), 1);
    const monthEnd = new Date(start.getFullYear(), start.getMonth()+1, 0);
    const firstWd = (monthStart.getDay()+6)%7;
    const grid = [];
    for (let i=0;i<firstWd;i++) grid.push(null);
    for (let d=1; d<=monthEnd.getDate(); d++) grid.push(new Date(start.getFullYear(),start.getMonth(),d).toISOString().slice(0,10));
    while (grid.length%7) grid.push(null);
    const max = Math.max(...days.map(d => dayTotal(d)),1);

    return (
      <div style={{ padding: '0 0 120px' }}>
        <div style={{ padding: '20px 24px 0' }}>
          <Eyebrow>{start.toLocaleDateString('de-DE', { month: 'long', year: 'numeric' })}</Eyebrow>
          <div style={{ fontFamily: F, fontSize: 22, color: p.ink, fontWeight: 500, marginTop: 4 }}>
            Im Kalender
          </div>
          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(7,1fr)', gap: 4, marginTop: 14 }}>
            {['M','D','M','D','F','S','S'].map((d,i) => (
              <div key={i} style={{ textAlign: 'center', fontFamily: F, fontSize: 10, color: p.muted, fontWeight: 600, padding: '2px 0' }}>{d}</div>
            ))}
            {grid.map((iso, i) => {
              if (!iso) return <div key={i}/>;
              const isTrip = days.includes(iso);
              const t = dayTotal(iso);
              const past = isTrip && tripDayNum(iso) <= daysPassed();
              const isToday = iso === TODAY;
              const intensity = past ? t/max : 0;
              return (
                <button key={i} onClick={() => isTrip && past && openDay(iso)} style={{
                  aspectRatio: '1', border: 0, padding: 0,
                  background: !isTrip ? 'transparent'
                            : !past ? `repeating-linear-gradient(45deg, transparent 0, transparent 2px, ${p.line} 2px, ${p.line} 3px)`
                            : `color-mix(in oklab, ${p.accent} ${intensity*70+10}%, ${p.paper})`,
                  borderRadius: 2,
                  cursor: isTrip && past ? 'pointer' : 'default',
                  display: 'flex', alignItems: 'center', justifyContent: 'center', position: 'relative',
                  outline: isToday ? `1.5px solid ${p.rust}` : 'none', outlineOffset: -1,
                }}>
                  <div style={{ fontFamily: F, fontSize: 11, fontWeight: 500,
                    color: !isTrip ? p.muted : (intensity > 0.45 ? p.paper : p.ink) }}>
                    {new Date(iso+'T00:00:00').getDate()}
                  </div>
                </button>
              );
            })}
          </div>
        </div>

        <HRule label="Rubriken im Detail" />
        <div style={{ padding: '0 24px', display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 4 }}>
          {cats.map((c) => (
            <button key={c.id} onClick={() => openCat(c.id)} style={{
              border: 0, background: 'transparent', textAlign: 'left',
              padding: '14px 0', cursor: 'pointer', borderBottom: `1px solid ${p.rule}`,
            }}>
              <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
                <CatMark cat={c} size={22}/>
                <Eyebrow style={{ fontSize: 9 }}>{c.label}</Eyebrow>
              </div>
              <div style={{ fontFamily: F, fontSize: 20, color: p.ink, fontWeight: 600, marginTop: 6, letterSpacing: -0.3 }}>
                {fmtEUR(c.total)}
              </div>
              <div style={{ fontFamily: F, fontSize: 11, color: p.muted, marginTop: 2 }}>
                {Math.round(c.total/total*100)}% · {EXPENSES.filter(e => e.cat === c.id).length}×
              </div>
            </button>
          ))}
        </div>
      </div>
    );
  }

  Object.assign(window, {
    MinHeute: HeuteView, MinWoche: WocheView, MinReise: ReiseView,
    MinListe: ListeView, MinRubrik: RubrikView,
  });
})();
