// cards.jsx — Tip card variants, tracking widgets, body-system viz, icons.
// All variants share the same data shape but lean on different visual languages.

// ─────────────────────────────────────────────────────────────
// Small primitives
// ─────────────────────────────────────────────────────────────

function CatHue(catId) {
  const c = CATEGORIES.find((x) => x.id === catId);
  return c ? c.hue : 60;
}
function CatLabel(catId) {
  const c = CATEGORIES.find((x) => x.id === catId);
  return c ? c.short : catId;
}

function KindGlyph({ kind, size = 14, color = 'currentColor' }) {
  // simple geometric glyphs by kind — no emoji, no detailed SVGs.
  const s = size;
  const stroke = 1.5;
  const props = { width: s, height: s, viewBox: '0 0 24 24', fill: 'none', stroke: color, strokeWidth: stroke, strokeLinecap: 'round', strokeLinejoin: 'round' };
  switch (kind) {
    case 'supplement':  // capsule
      return (<svg {...props}><rect x="3" y="9" width="18" height="6" rx="3"/><path d="M12 9v6"/></svg>);
    case 'behavior':    // diamond
      return (<svg {...props}><path d="M12 3l9 9-9 9-9-9 9-9z"/></svg>);
    case 'exercise':    // arrow / play
      return (<svg {...props}><path d="M5 4l14 8-14 8V4z"/></svg>);
    case 'food':        // circle
      return (<svg {...props}><circle cx="12" cy="12" r="8"/><circle cx="12" cy="12" r="3" fill={color}/></svg>);
    case 'environment': // sun
      return (<svg {...props}><circle cx="12" cy="12" r="4"/><path d="M12 3v2M12 19v2M3 12h2M19 12h2M5.6 5.6l1.4 1.4M17 17l1.4 1.4M5.6 18.4L7 17M17 7l1.4-1.4"/></svg>);
    case 'mindset':     // square
      return (<svg {...props}><rect x="4" y="4" width="16" height="16" rx="2"/></svg>);
    default:
      return (<svg {...props}><circle cx="12" cy="12" r="8"/></svg>);
  }
}

function CategoryDot({ catId, size = 8 }) {
  const h = CatHue(catId);
  return <span style={{
    display: 'inline-block', width: size, height: size, borderRadius: 999,
    background: `oklch(0.62 0.10 ${h})`, flexShrink: 0,
  }} />;
}

function EffortDots({ value = 1, max = 5, color = 'currentColor' }) {
  return (
    <span style={{ display: 'inline-flex', gap: 3, alignItems: 'center' }}>
      {Array.from({ length: max }).map((_, i) => (
        <span key={i} style={{
          width: 5, height: 5, borderRadius: 999,
          background: i < value ? color : 'transparent',
          border: `1px solid ${color}`, opacity: i < value ? 1 : 0.35,
        }} />
      ))}
    </span>
  );
}

function CostMarks({ value = 1, max = 4, color = 'currentColor' }) {
  return (
    <span style={{ display: 'inline-flex', gap: 1, fontVariantNumeric: 'tabular-nums', letterSpacing: -1, color, fontWeight: 600, fontSize: 11 }}>
      {Array.from({ length: max }).map((_, i) => (
        <span key={i} style={{ opacity: i < value ? 1 : 0.25 }}>$</span>
      ))}
    </span>
  );
}

// Compact placeholder image stripe — never draw a fake illustration.
function PlaceholderArt({ catId, kind, h = 96, label }) {
  const hue = CatHue(catId);
  return (
    <div style={{
      height: h, borderRadius: 12, overflow: 'hidden', position: 'relative',
      background:
        `repeating-linear-gradient(135deg,` +
        ` oklch(0.92 0.04 ${hue}) 0 8px,` +
        ` oklch(0.95 0.02 ${hue}) 8px 16px)`,
      color: `oklch(0.32 0.06 ${hue})`,
      display: 'flex', alignItems: 'center', justifyContent: 'center',
    }}>
      <div style={{
        fontFamily: 'var(--cb-mono)',
        fontSize: 10, opacity: 0.7, letterSpacing: 0.5, textTransform: 'uppercase',
      }}>{label || (kind ? KIND_META[kind].label : 'photo')}</div>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// Tip Card — four visual styles
// All take {tip, onOpen, onSave, saved, dark}
// ─────────────────────────────────────────────────────────────

function TipCardEditorial({ tip, onOpen, onSave, saved, dark }) {
  const fg = dark ? '#f4efe6' : '#1c1a15';
  const muted = dark ? 'rgba(244,239,230,0.55)' : 'rgba(28,26,21,0.55)';
  const card = dark ? 'rgba(255,255,255,0.04)' : '#fff';
  const stroke = dark ? 'rgba(255,255,255,0.07)' : 'rgba(28,26,21,0.08)';
  return (
    <article
      onClick={onOpen}
      style={{
        background: card, borderRadius: 20, padding: '18px 18px 16px',
        border: `0.5px solid ${stroke}`, color: fg, cursor: 'pointer',
        display: 'flex', flexDirection: 'column', gap: 12,
      }}>
      <header style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 8 }}>
        <span style={{ display: 'inline-flex', alignItems: 'center', gap: 8, fontSize: 11, letterSpacing: 0.6, textTransform: 'uppercase', color: muted }}>
          <CategoryDot catId={tip.primary} />
          <span>{CatLabel(tip.primary)}</span>
          <span style={{ opacity: 0.5 }}>·</span>
          <KindGlyph kind={tip.kind} size={11} color={muted} />
          <span>{KIND_META[tip.kind].label}</span>
        </span>
        <SaveBtn saved={saved} onSave={onSave} dark={dark} />
      </header>
      <h3 style={{
        fontFamily: 'var(--cb-display)',
        fontWeight: 400, fontSize: 26, lineHeight: 1.15, margin: 0,
        letterSpacing: -0.2, textWrap: 'pretty',
      }}>{tip.title}</h3>
      <p style={{ margin: 0, fontSize: 14, lineHeight: 1.45, color: muted, textWrap: 'pretty' }}>
        {tip.summary}
      </p>
      <div style={{
        marginTop: 2, padding: '10px 12px', borderRadius: 12,
        background: dark ? 'rgba(212,200,170,0.08)' : 'oklch(0.96 0.025 95)',
        fontSize: 13, lineHeight: 1.4, color: fg,
        borderLeft: `2px solid oklch(0.62 0.08 ${CatHue(tip.primary)})`,
      }}>
        <span style={{ fontFamily: 'var(--cb-mono)', fontSize: 10, letterSpacing: 1, opacity: 0.6, textTransform: 'uppercase' }}>Try this</span>
        <div>{tip.tryThis}</div>
      </div>
      <footer style={{ display: 'flex', alignItems: 'center', gap: 10, fontSize: 12, color: muted }}>
        <MetaPill label={tip.cadence} dark={dark} />
        <span style={{ display: 'inline-flex', alignItems: 'center', gap: 5 }}>
          <span style={{ opacity: 0.7 }}>Effort</span>
          <EffortDots value={tip.effort} color={fg} />
        </span>
        <span style={{ display: 'inline-flex', alignItems: 'center', gap: 5 }}>
          <CostMarks value={tip.cost} color={fg} />
        </span>
      </footer>
    </article>
  );
}

function TipCardMagazine({ tip, onOpen, onSave, saved, dark }) {
  const fg = dark ? '#f4efe6' : '#1c1a15';
  const muted = dark ? 'rgba(244,239,230,0.55)' : 'rgba(28,26,21,0.55)';
  const card = dark ? 'rgba(255,255,255,0.04)' : '#fff';
  const stroke = dark ? 'rgba(255,255,255,0.07)' : 'rgba(28,26,21,0.08)';
  return (
    <article onClick={onOpen}
      style={{
        background: card, borderRadius: 22, overflow: 'hidden',
        border: `0.5px solid ${stroke}`, color: fg, cursor: 'pointer',
      }}>
      <div style={{ position: 'relative' }}>
        <PlaceholderArt catId={tip.primary} kind={tip.kind} h={150} />
        <div style={{ position: 'absolute', top: 12, left: 12, display: 'flex', gap: 6 }}>
          <span style={{
            display: 'inline-flex', alignItems: 'center', gap: 6,
            padding: '5px 10px 5px 8px', borderRadius: 999,
            background: 'rgba(255,255,255,0.85)', color: '#1c1a15',
            fontSize: 11, letterSpacing: 0.4, textTransform: 'uppercase',
            backdropFilter: 'blur(10px)',
          }}>
            <CategoryDot catId={tip.primary} size={7}/>
            {CatLabel(tip.primary)}
          </span>
        </div>
        <div style={{ position: 'absolute', top: 12, right: 12 }}>
          <SaveBtn saved={saved} onSave={onSave} dark={false} />
        </div>
      </div>
      <div style={{ padding: '16px 18px 18px', display: 'flex', flexDirection: 'column', gap: 10 }}>
        <h3 style={{
          fontFamily: 'var(--cb-display)',
          fontWeight: 400, fontSize: 28, lineHeight: 1.12, margin: 0, letterSpacing: -0.4,
        }}>{tip.title}</h3>
        <p style={{ margin: 0, fontSize: 13.5, lineHeight: 1.5, color: muted, textWrap: 'pretty' }}>{tip.summary}</p>
        <div style={{ display: 'flex', alignItems: 'center', gap: 12, marginTop: 4, fontSize: 12, color: muted }}>
          <KindGlyph kind={tip.kind} size={12} color={muted}/>
          <span>{KIND_META[tip.kind].label}</span>
          <span style={{ opacity: 0.4 }}>·</span>
          <span>{tip.cadence}</span>
          <span style={{ opacity: 0.4 }}>·</span>
          <EffortDots value={tip.effort} color={fg}/>
        </div>
      </div>
    </article>
  );
}

function TipCardData({ tip, onOpen, onSave, saved, dark }) {
  const fg = dark ? '#f4efe6' : '#1c1a15';
  const muted = dark ? 'rgba(244,239,230,0.55)' : 'rgba(28,26,21,0.55)';
  const card = dark ? 'rgba(255,255,255,0.04)' : '#fff';
  const stroke = dark ? 'rgba(255,255,255,0.07)' : 'rgba(28,26,21,0.08)';
  return (
    <article onClick={onOpen} style={{
      background: card, borderRadius: 18, padding: 14, color: fg, cursor: 'pointer',
      border: `0.5px solid ${stroke}`,
      display: 'flex', flexDirection: 'column', gap: 12,
    }}>
      <header style={{ display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between', gap: 10 }}>
        <div style={{ display: 'flex', flexDirection: 'column', gap: 6, minWidth: 0 }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 8, fontSize: 11, color: muted, textTransform: 'uppercase', letterSpacing: 0.5 }}>
            <CategoryDot catId={tip.primary} />
            <span>{CatLabel(tip.primary)}</span>
            <span style={{ opacity: 0.4 }}>·</span>
            <span>{tip.cadence}</span>
          </div>
          <h3 style={{
            margin: 0, fontSize: 17, fontWeight: 600, lineHeight: 1.2,
            fontFamily: 'inherit', textWrap: 'pretty',
          }}>{tip.title}</h3>
        </div>
        <SaveBtn saved={saved} onSave={onSave} dark={dark}/>
      </header>
      <p style={{ margin: 0, fontSize: 13, lineHeight: 1.45, color: muted, textWrap: 'pretty' }}>{tip.summary}</p>
      <BodySystemChips effects={tip.positive} dark={dark} compact max={4}/>
    </article>
  );
}

function TipCardMinimal({ tip, onOpen, onSave, saved, dark }) {
  const fg = dark ? '#f4efe6' : '#1c1a15';
  const muted = dark ? 'rgba(244,239,230,0.55)' : 'rgba(28,26,21,0.55)';
  const card = dark ? 'rgba(255,255,255,0.03)' : 'rgba(255,255,255,0.6)';
  const stroke = dark ? 'rgba(255,255,255,0.06)' : 'rgba(28,26,21,0.06)';
  return (
    <article onClick={onOpen} style={{
      background: card, borderRadius: 16, padding: '16px 18px', color: fg, cursor: 'pointer',
      border: `0.5px solid ${stroke}`,
      display: 'flex', flexDirection: 'column', gap: 10,
    }}>
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
        <span style={{ display: 'inline-flex', alignItems: 'center', gap: 8, fontSize: 11, letterSpacing: 0.6, color: muted, textTransform: 'uppercase' }}>
          <KindGlyph kind={tip.kind} size={11} color={`oklch(0.55 0.10 ${CatHue(tip.primary)})`}/>
          {CatLabel(tip.primary)} · {KIND_META[tip.kind].label}
        </span>
        <SaveBtn saved={saved} onSave={onSave} dark={dark}/>
      </div>
      <h3 style={{
        margin: 0, fontSize: 17, fontWeight: 600, lineHeight: 1.25,
        textWrap: 'pretty',
      }}>{tip.title}</h3>
      <p style={{
        margin: 0, fontSize: 14, lineHeight: 1.45, color: fg,
        fontFamily: 'var(--cb-display)',
        fontStyle: 'italic', textWrap: 'pretty',
      }}>
        <span style={{ color: `oklch(0.55 0.10 ${CatHue(tip.primary)})`, fontStyle: 'normal' }}>"</span>
        {tip.tryThis}
        <span style={{ color: `oklch(0.55 0.10 ${CatHue(tip.primary)})`, fontStyle: 'normal' }}>"</span>
      </p>
      <div style={{ display: 'flex', alignItems: 'center', gap: 10, fontSize: 11, color: muted, marginTop: 2 }}>
        <span>{tip.cadence}</span>
        <span style={{ opacity: 0.4 }}>·</span>
        <span style={{ display: 'inline-flex', alignItems: 'center', gap: 5 }}>
          Effort <EffortDots value={tip.effort} color={fg}/>
        </span>
      </div>
    </article>
  );
}

function Stat({ label, value, fg, muted }) {
  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 4 }}>
      <span style={{ fontSize: 10, letterSpacing: 0.5, color: muted, textTransform: 'uppercase' }}>{label}</span>
      <span style={{ fontSize: 13, color: fg, fontWeight: 500, display: 'inline-flex', alignItems: 'center' }}>{value}</span>
    </div>
  );
}

function MetaPill({ label, dark }) {
  return (
    <span style={{
      padding: '3px 8px', borderRadius: 999, fontSize: 11,
      background: dark ? 'rgba(255,255,255,0.07)' : 'oklch(0.94 0.005 80)',
      color: 'inherit',
    }}>{label}</span>
  );
}

function SaveBtn({ saved, onSave, dark }) {
  return (
    <button
      onClick={(e) => { e.stopPropagation(); onSave && onSave(); }}
      aria-label={saved ? 'Remove from routine' : 'Add to routine'}
      style={{
        appearance: 'none', border: 0, padding: 0, cursor: 'pointer',
        width: 32, height: 32, borderRadius: 999,
        background: saved
          ? (dark ? 'oklch(0.78 0.12 var(--cb-accent-hue))' : '#1c1a15')
          : (dark ? 'rgba(255,255,255,0.06)' : 'rgba(28,26,21,0.05)'),
        color: saved ? (dark ? '#1c1a15' : '#fafaf7') : 'inherit',
        display: 'flex', alignItems: 'center', justifyContent: 'center',
        flexShrink: 0,
      }}>
      <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round">
        {saved
          ? <path d="M5 12l4 4 10-10" />
          : <path d="M12 5v14M5 12h14" />}
      </svg>
    </button>
  );
}

// Dispatcher
function TipCard({ variant = 'editorial', tip, ...rest }) {
  if (variant === 'magazine') return <TipCardMagazine tip={tip} {...rest}/>;
  if (variant === 'data')     return <TipCardData     tip={tip} {...rest}/>;
  if (variant === 'minimal')  return <TipCardMinimal  tip={tip} {...rest}/>;
  return <TipCardEditorial tip={tip} {...rest}/>;
}

// ─────────────────────────────────────────────────────────────
// Body-system viz
// ─────────────────────────────────────────────────────────────

const SYSTEM_REGIONS = {
  Brain:        { x: 50, y: 9,  r: 8 },
  Mood:         { x: 50, y: 9,  r: 8 },
  Nervous:      { x: 50, y: 9,  r: 8 },
  Eyes:         { x: 50, y: 12, r: 5 },
  Dental:       { x: 50, y: 16, r: 4 },
  Thyroid:      { x: 50, y: 21, r: 4 },
  Heart:        { x: 45, y: 33, r: 8 },
  Cardio:       { x: 45, y: 33, r: 8 },
  Immune:       { x: 55, y: 33, r: 8 },
  Hormones:     { x: 50, y: 40, r: 7 },
  Metabolism:   { x: 50, y: 47, r: 8 },
  'Blood sugar':{ x: 50, y: 47, r: 8 },
  Gut:          { x: 50, y: 54, r: 9 },
  'Fat storage':{ x: 50, y: 54, r: 9 },
  Muscles:      { x: 32, y: 38, r: 6 },
  Bones:        { x: 68, y: 38, r: 6 },
  Joints:       { x: 30, y: 70, r: 5 },
  Sleep:        { x: 50, y: 6,  r: 6 },
  Cellular:     { x: 70, y: 50, r: 5 },
  Mitochondria: { x: 70, y: 50, r: 5 },
};

function BodyDiagram({ effects = [], negative = [], dark = false }) {
  const fg = dark ? '#f4efe6' : '#1c1a15';
  const muted = dark ? 'rgba(244,239,230,0.5)' : 'rgba(28,26,21,0.4)';
  const byPos = {};
  effects.forEach((e) => { byPos[e.system] = Math.max(byPos[e.system] || 0, e.weight); });
  const byNeg = {};
  negative.forEach((e) => { byNeg[e.system] = Math.max(byNeg[e.system] || 0, e.weight); });

  const regions = Object.entries(SYSTEM_REGIONS).filter(([sys]) => byPos[sys] || byNeg[sys]);

  return (
    <div style={{
      position: 'relative', width: '100%', aspectRatio: '5 / 7',
      background: dark ? 'rgba(255,255,255,0.03)' : 'oklch(0.97 0.005 80)',
      borderRadius: 18, overflow: 'hidden',
    }}>
      <svg viewBox="0 0 100 140" style={{ width: '100%', height: '100%', display: 'block' }}>
        <g fill={dark ? 'rgba(255,255,255,0.07)' : 'rgba(28,26,21,0.05)'} stroke={muted} strokeWidth="0.3">
          <ellipse cx="50" cy="12" rx="8.5" ry="9.5" />
          <rect x="46.5" y="20" width="7" height="5" rx="1.5" />
          <path d="M30 28 Q50 24 70 28 L66 70 Q50 74 34 70 Z" />
          <path d="M30 28 Q22 38 22 60 Q24 78 28 88" fill="none" strokeWidth="6" stroke={dark ? 'rgba(255,255,255,0.07)' : 'rgba(28,26,21,0.05)'} strokeLinecap="round"/>
          <path d="M70 28 Q78 38 78 60 Q76 78 72 88" fill="none" strokeWidth="6" stroke={dark ? 'rgba(255,255,255,0.07)' : 'rgba(28,26,21,0.05)'} strokeLinecap="round"/>
          <path d="M40 70 Q38 90 40 115 L46 130" fill="none" strokeWidth="9" stroke={dark ? 'rgba(255,255,255,0.07)' : 'rgba(28,26,21,0.05)'} strokeLinecap="round"/>
          <path d="M60 70 Q62 90 60 115 L54 130" fill="none" strokeWidth="9" stroke={dark ? 'rgba(255,255,255,0.07)' : 'rgba(28,26,21,0.05)'} strokeLinecap="round"/>
        </g>
        {regions.map(([sys, pos]) => {
          const p = byPos[sys] || 0;
          const n = byNeg[sys] || 0;
          const dominant = p >= n ? 'pos' : 'neg';
          const w = Math.max(p, n);
          const radius = pos.r * (0.55 + w * 0.12);
          const color = dominant === 'pos'
            ? 'oklch(0.65 0.13 var(--cb-accent-hue))'
            : 'oklch(0.62 0.16 28)';
          return (
            <g key={sys}>
              <circle cx={pos.x} cy={pos.y} r={radius}
                      fill={color} opacity={0.18}/>
              <circle cx={pos.x} cy={pos.y} r={radius * 0.45}
                      fill={color}/>
            </g>
          );
        })}
      </svg>
      <div style={{
        position: 'absolute', left: 12, bottom: 12, display: 'flex', gap: 12,
        fontSize: 10, color: muted, letterSpacing: 0.5, textTransform: 'uppercase',
      }}>
        <span style={{ display: 'inline-flex', alignItems: 'center', gap: 5 }}>
          <span style={{ width: 8, height: 8, borderRadius: 999, background: 'oklch(0.65 0.13 var(--cb-accent-hue))'}}/> Positive
        </span>
        {negative.length > 0 && (
          <span style={{ display: 'inline-flex', alignItems: 'center', gap: 5 }}>
            <span style={{ width: 8, height: 8, borderRadius: 999, background: 'oklch(0.62 0.16 28)'}}/> Negative
          </span>
        )}
      </div>
    </div>
  );
}

function BodySystemChips({ effects, dark, compact = false, max = 99 }) {
  if (!effects || !effects.length) return null;
  const map = {};
  effects.forEach((e) => {
    map[e.system] = Math.max(map[e.system] || 0, e.weight);
  });
  const items = Object.entries(map).slice(0, max);
  return (
    <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
      {items.map(([sys, w]) => (
        <span key={sys} style={{
          display: 'inline-flex', alignItems: 'center', gap: 6,
          padding: compact ? '3px 8px' : '5px 10px',
          borderRadius: 999, fontSize: compact ? 11 : 12,
          background: dark ? 'oklch(0.78 0.10 var(--cb-accent-hue) / 0.18)' : 'oklch(0.94 0.04 var(--cb-accent-hue))',
          color: dark ? 'oklch(0.85 0.10 var(--cb-accent-hue))' : 'oklch(0.32 0.10 var(--cb-accent-hue))',
        }}>
          <span style={{ width: 6, height: 6, borderRadius: 999, background: 'oklch(0.62 0.13 var(--cb-accent-hue))' }}/>
          {sys}
        </span>
      ))}
    </div>
  );
}

function EffectBars({ positive = [], negative = [], dark = false }) {
  const fg = dark ? '#f4efe6' : '#1c1a15';
  const muted = dark ? 'rgba(244,239,230,0.5)' : 'rgba(28,26,21,0.5)';
  const all = [...positive.map(e => ({...e, sign: 1})), ...negative.map(e => ({...e, sign: -1}))];
  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 7 }}>
      {all.map((e, i) => {
        const color = e.sign > 0 ? 'oklch(0.62 0.13 var(--cb-accent-hue))' : 'oklch(0.62 0.16 28)';
        return (
          <div key={i} style={{ display: 'grid', gridTemplateColumns: '85px 1fr 50px', alignItems: 'center', gap: 10 }}>
            <span style={{ fontSize: 11, color: muted, letterSpacing: 0.3 }}>{e.system}</span>
            <div style={{ position: 'relative', height: 6, borderRadius: 999, background: dark ? 'rgba(255,255,255,0.06)' : 'rgba(28,26,21,0.06)' }}>
              <div style={{
                position: 'absolute', left: 0, top: 0, bottom: 0,
                width: `${(e.weight / 4) * 100}%`,
                background: color, borderRadius: 999,
              }}/>
            </div>
            <span style={{ fontSize: 11, color: fg, textAlign: 'right' }}>{e.effect}</span>
          </div>
        );
      })}
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// Tracking widgets — three styles
// ─────────────────────────────────────────────────────────────

function TrackingChecklist({ items, state, onToggle, dark, accent }) {
  const fg = dark ? '#f4efe6' : '#1c1a15';
  const muted = dark ? 'rgba(244,239,230,0.55)' : 'rgba(28,26,21,0.55)';
  const card = dark ? 'rgba(255,255,255,0.04)' : '#fff';
  const stroke = dark ? 'rgba(255,255,255,0.06)' : 'rgba(28,26,21,0.06)';
  return (
    <div style={{
      background: card, borderRadius: 18, border: `0.5px solid ${stroke}`,
      overflow: 'hidden',
    }}>
      {items.map((tip, i) => {
        const done = !!state[tip.id];
        return (
          <button key={tip.id} onClick={() => onToggle(tip.id)}
            style={{
              all: 'unset', cursor: 'pointer',
              display: 'flex', alignItems: 'center', gap: 12,
              padding: '14px 16px',
              borderTop: i === 0 ? 0 : `0.5px solid ${stroke}`,
              width: '100%', boxSizing: 'border-box',
            }}>
            <span style={{
              width: 22, height: 22, borderRadius: 7,
              border: `1.5px solid ${done ? accent : (dark ? 'rgba(255,255,255,0.25)' : 'rgba(28,26,21,0.2)')}`,
              background: done ? accent : 'transparent',
              display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0,
              transition: 'all 0.15s',
            }}>
              {done && (
                <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke={dark ? '#1c1a15' : '#fff'} strokeWidth="3" strokeLinecap="round" strokeLinejoin="round">
                  <path d="M5 12l4 4 10-10"/>
                </svg>
              )}
            </span>
            <div style={{ flex: 1, minWidth: 0, display: 'flex', flexDirection: 'column', gap: 2 }}>
              <span style={{
                color: fg, fontSize: 15, fontWeight: 500,
                textDecoration: done ? 'line-through' : 'none',
                textDecorationColor: muted, opacity: done ? 0.55 : 1,
              }}>{tip.title}</span>
              <span style={{ fontSize: 11.5, color: muted, display: 'inline-flex', alignItems: 'center', gap: 6 }}>
                <CategoryDot catId={tip.primary} size={6}/>
                {CatLabel(tip.primary)} · {tip.cadence}
              </span>
            </div>
          </button>
        );
      })}
    </div>
  );
}

function TrackingRings({ items, state, onToggle, dark, accent }) {
  const fg = dark ? '#f4efe6' : '#1c1a15';
  const muted = dark ? 'rgba(244,239,230,0.55)' : 'rgba(28,26,21,0.55)';
  const ringTrack = dark ? 'rgba(255,255,255,0.08)' : 'rgba(28,26,21,0.07)';
  return (
    <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(85px, 1fr))', gap: 12 }}>
      {items.map((tip) => {
        const done = !!state[tip.id];
        const hue = CatHue(tip.primary);
        const color = `oklch(0.62 0.12 ${hue})`;
        return (
          <button key={tip.id} onClick={() => onToggle(tip.id)}
            style={{
              all: 'unset', cursor: 'pointer',
              display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 6,
              padding: 10,
            }}>
            <div style={{ position: 'relative', width: 64, height: 64 }}>
              <svg viewBox="0 0 64 64" style={{ position: 'absolute', inset: 0, transform: 'rotate(-90deg)' }}>
                <circle cx="32" cy="32" r="28" fill="none" stroke={ringTrack} strokeWidth="6"/>
                <circle cx="32" cy="32" r="28" fill="none" stroke={color} strokeWidth="6"
                        strokeLinecap="round"
                        strokeDasharray={`${2 * Math.PI * 28}`}
                        strokeDashoffset={done ? 0 : 2 * Math.PI * 28}
                        style={{ transition: 'stroke-dashoffset 0.4s cubic-bezier(.3,.7,.4,1)' }}/>
              </svg>
              <div style={{
                position: 'absolute', inset: 0, display: 'flex',
                alignItems: 'center', justifyContent: 'center',
                color: done ? color : muted,
                transition: 'color 0.2s',
              }}>
                <KindGlyph kind={tip.kind} size={22} color="currentColor"/>
              </div>
            </div>
            <span style={{
              fontSize: 11, color: fg, textAlign: 'center', lineHeight: 1.2,
              opacity: done ? 1 : 0.7, maxWidth: 80, textWrap: 'pretty',
            }}>{tip.title.split(',')[0]}</span>
          </button>
        );
      })}
    </div>
  );
}

function TrackingGarden({ items, state, onToggle, dark, accent }) {
  const fg = dark ? '#f4efe6' : '#1c1a15';
  const muted = dark ? 'rgba(244,239,230,0.55)' : 'rgba(28,26,21,0.55)';
  const card = dark ? 'rgba(255,255,255,0.04)' : '#fff';
  const stroke = dark ? 'rgba(255,255,255,0.06)' : 'rgba(28,26,21,0.06)';
  return (
    <div style={{
      background: card, borderRadius: 22, padding: 16,
      border: `0.5px solid ${stroke}`,
    }}>
      <div style={{
        display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(70px, 1fr))', gap: 8,
        paddingBottom: 12, borderBottom: `0.5px dashed ${stroke}`,
      }}>
        {items.map((tip) => {
          const done = !!state[tip.id];
          const hue = CatHue(tip.primary);
          return (
            <button key={tip.id} onClick={() => onToggle(tip.id)}
              style={{
                all: 'unset', cursor: 'pointer',
                display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 4,
              }}>
              <Plant grown={done} hue={hue} dark={dark}/>
              <span style={{
                fontSize: 10, color: muted, letterSpacing: 0.3,
                textAlign: 'center', lineHeight: 1.1,
                maxWidth: 80, textWrap: 'pretty',
              }}>{tip.title.split(',')[0].split(' ').slice(0, 2).join(' ')}</span>
            </button>
          );
        })}
      </div>
      <div style={{
        height: 14, marginTop: 10, borderRadius: 8,
        background: `repeating-linear-gradient(90deg,
          oklch(0.55 0.05 60) 0 4px,
          oklch(0.52 0.05 60) 4px 8px)`,
      }}/>
      <div style={{ marginTop: 10, fontSize: 11, color: muted, textAlign: 'center', letterSpacing: 0.4 }}>
        Tend your garden — tap a sprout to water it.
      </div>
    </div>
  );
}

function Plant({ grown, hue, dark }) {
  const stem = `oklch(0.55 0.10 var(--cb-accent-hue))`;
  const flower = `oklch(0.65 0.14 ${hue})`;
  const soil = dark ? 'rgba(120, 80, 60, 0.4)' : 'oklch(0.55 0.06 60)';
  return (
    <svg width="50" height="60" viewBox="0 0 50 60" style={{ overflow: 'visible' }}>
      <path d="M14 48 L36 48 L34 58 Q25 60 16 58 Z" fill={soil}/>
      <ellipse cx="25" cy="48" rx="11" ry="2" fill={`oklch(0.42 0.04 60)`}/>
      {grown ? (
        <g style={{ transformOrigin: '25px 48px' }}>
          <path d="M25 48 Q24 38 25 30 Q26 22 25 16" stroke={stem} strokeWidth="2" fill="none" strokeLinecap="round"/>
          <ellipse cx="20" cy="35" rx="5" ry="2.5" fill={stem} transform="rotate(-25 20 35)"/>
          <ellipse cx="30" cy="28" rx="5" ry="2.5" fill={stem} transform="rotate(25 30 28)"/>
          <circle cx="25" cy="14" r="5" fill={flower}/>
          <circle cx="25" cy="14" r="2" fill={dark ? '#1c1a15' : '#fff8e5'}/>
        </g>
      ) : (
        <g>
          <path d="M25 48 Q24 44 25 42" stroke={stem} strokeWidth="2" fill="none" strokeLinecap="round" opacity="0.7"/>
          <ellipse cx="22" cy="43" rx="3" ry="1.5" fill={stem} opacity="0.7" transform="rotate(-20 22 43)"/>
        </g>
      )}
    </svg>
  );
}

function TrackingWidget({ variant = 'checklist', items, state, onToggle, dark, accent }) {
  const props = { items, state, onToggle, dark, accent };
  if (variant === 'rings')  return <TrackingRings  {...props}/>;
  if (variant === 'garden') return <TrackingGarden {...props}/>;
  return <TrackingChecklist {...props}/>;
}

// ─────────────────────────────────────────────────────────────
// Brand — Actova logo (mark + wordmark + lockup)
// ─────────────────────────────────────────────────────────────
function ActovaMark({ size = 32, dark = false, inverted = false }) {
  const ink = inverted
    ? `oklch(${dark ? 0.78 : 0.62} 0.18 var(--cb-accent-hue))`
    : (dark ? '#fafaf6' : '#0a0a08');
  const accent = inverted
    ? (dark ? '#0a0a08' : '#fafaf6')
    : `oklch(${dark ? 0.82 : 0.78} 0.20 var(--cb-accent-hue))`;
  return (
    <svg width={size} height={size} viewBox="0 0 40 40" style={{ flexShrink: 0, display: 'block' }}>
      <circle cx="20" cy="20" r="20" fill={ink} />
      <path d="M20 9 L29.5 28 L23.4 28 L20 21 L16.6 28 L10.5 28 Z" fill={accent} />
      <rect x="14.5" y="22.5" width="11" height="2.4" rx="1.2" fill={accent} />
    </svg>
  );
}

function ActovaWordmark({ size = 22, dark = false, weight = 600 }) {
  const ink = dark ? '#fafaf6' : '#0a0a08';
  const accent = `oklch(${dark ? 0.78 : 0.62} 0.18 var(--cb-accent-hue))`;
  return (
    <span style={{
      fontFamily: 'var(--cb-display)',
      fontWeight: weight, fontSize: size,
      letterSpacing: `${-size * 0.018}px`,
      color: ink, lineHeight: 1,
      display: 'inline-flex', alignItems: 'baseline', whiteSpace: 'nowrap',
    }}>
      <span>actova</span>
      <span style={{
        color: accent, marginLeft: 1,
        width: size * 0.18, height: size * 0.18, borderRadius: 999,
        background: accent, display: 'inline-block',
        transform: `translateY(${-size * 0.02}px)`,
      }} />
    </span>
  );
}

function ActovaLockup({ size = 22, dark = false, gap = 9 }) {
  return (
    <span style={{
      display: 'inline-flex', alignItems: 'center', gap,
    }}>
      <ActovaMark size={size * 1.4} dark={dark} />
      <ActovaWordmark size={size} dark={dark} />
    </span>
  );
}

Object.assign(window, {
  KindGlyph, CategoryDot, EffortDots, CostMarks, PlaceholderArt,
  TipCard, TipCardEditorial, TipCardMagazine, TipCardData, TipCardMinimal,
  BodyDiagram, BodySystemChips, EffectBars,
  TrackingWidget, TrackingChecklist, TrackingRings, TrackingGarden,
  CatHue, CatLabel, SaveBtn, MetaPill,
  ActovaMark, ActovaWordmark, ActovaLockup,
});
