/* Polish desktop shared primitives
   Alles neemt `t` (tokens) — werkt in dark én light. Model: screens/shared.jsx Sidebar + Topbar,
   gebrouwen met TK-tokens ipv hard-coded dark-hex. */

const { useState, useEffect, useRef } = React;

/* ─── Lucide icon ──────────────────────────────────────────── */
function PI({ name, size = 16, color = 'currentColor', strokeWidth = 2, style, fill = 'none' }) {
  const icons = window.lucide && window.lucide.icons;
  if (!icons) return null;
  const pascal = name.split('-').map(s => s[0].toUpperCase() + s.slice(1)).join('');
  const data = icons[pascal] || icons[name];
  if (!data) return null;
  const children = Array.isArray(data) ? (data[2] || []) : (data.children || []);
  const html = children.map(c => {
    if (!Array.isArray(c)) return '';
    const [tag, a] = c;
    if (!tag || !a) return '';
    const attrs = Object.entries(a).map(([k, v]) => `${k}="${v}"`).join(' ');
    return `<${tag} ${attrs}/>`;
  }).join('');
  return (
    <svg width={size} height={size} viewBox="0 0 24 24" fill={fill}
      stroke={color} strokeWidth={strokeWidth} strokeLinecap="round" strokeLinejoin="round"
      style={{ flexShrink: 0, ...(style || {}) }}
      dangerouslySetInnerHTML={{ __html: html }} />
  );
}

/* ─── BrowserShell — fake browser-chrome wrapper ─────────── */
function BrowserShell({ t, children, width = 1240, height = 820 }) {
  const isDark = t.mode === 'dark';
  return (
    <div style={{
      width, borderRadius: 14, overflow: 'hidden',
      background: t.bg,
      boxShadow: isDark
        ? '0 40px 100px rgba(0,0,0,0.55), 0 0 0 1px rgba(255,255,255,0.06)'
        : '0 24px 60px rgba(15,23,42,0.14), 0 4px 14px rgba(15,23,42,0.08), 0 0 0 1px rgba(15,23,42,0.06)',
    }}>
      {/* chrome */}
      <div style={{
        height: 40, background: isDark ? '#1A2235' : '#F1F5F9',
        display: 'flex', alignItems: 'center', padding: '0 16px', gap: 10,
        borderBottom: `1px solid ${isDark ? '#0B1120' : '#E2E8F0'}`,
      }}>
        <div style={{ display: 'flex', gap: 6 }}>
          <span style={{ width: 12, height: 12, borderRadius: 999, background: '#FF5F56' }} />
          <span style={{ width: 12, height: 12, borderRadius: 999, background: '#FFBD2E' }} />
          <span style={{ width: 12, height: 12, borderRadius: 999, background: '#27C93F' }} />
        </div>
        <div style={{
          flex: 1, maxWidth: 420, margin: '0 auto',
          background: isDark ? 'rgba(255,255,255,0.06)' : '#FFFFFF',
          border: isDark ? 'none' : '1px solid #E2E8F0',
          height: 24, borderRadius: 6,
          display: 'flex', alignItems: 'center', padding: '0 10px',
          fontSize: 11, color: isDark ? '#94A3B8' : '#64748B',
          fontWeight: 600, gap: 6,
        }}>🔒 snapsnel.nl/plannen</div>
      </div>
      {/* content */}
      <div style={{ height, display: 'flex', background: t.bg, overflow: 'hidden' }}>
        {children}
      </div>
    </div>
  );
}

/* ─── Pulse mascot (echte SVG-asset) ────────────────────── */
/* DS: preview/logo.html → lockup md = mascot 36px, word 20px */
function PulseMascot({ size = 36, mood = 'idle', style }) {
  const src = `polish/assets/pulse-${mood}.svg`;
  // 200:280 aspect ratio (preview/logo.html spec)
  const width = Math.round(size * (200 / 280));
  return (
    <img src={src} alt="" width={width} height={size}
      style={{ display: 'block', flexShrink: 0, ...(style || {}) }} />
  );
}

/* ─── Lockup — DS-conform (preview/logo.html) ───────────── */
function Lockup({ t, size = 'md' }) {
  const dims = { sm: { mascot: 24, word: 16 }, md: { mascot: 36, word: 20 },
                 lg: { mascot: 48, word: 28 }, xl: { mascot: 72, word: 40 } }[size];
  const snelColor = t.mode === 'dark' ? '#00B4D8' : '#0096C7';
  return (
    <div style={{ display: 'inline-flex', alignItems: 'center', gap: 8 }}>
      <PulseMascot size={dims.mascot} mood="idle" />
      <span style={{
        fontFamily: 'Fredoka One', fontWeight: 400, fontSize: dims.word,
        lineHeight: 1, letterSpacing: '-0.02em',
      }}>
        <span style={{ color: t.fg }}>Snap</span>
        <span style={{ color: snelColor }}>Snel</span>
      </span>
    </div>
  );
}

/* ─── Sidebar ─────────────────────────────────────────────── */
function Sidebar({ t, active = 'plannen', width = 232 }) {
  const items = [
    { id: 'home',      label: 'Home',      icon: 'home' },
    { id: 'leren',     label: 'Leren',     icon: 'book-open' },
    { id: 'quizzen',   label: 'Quizzen',   icon: 'layers' },
    { id: 'plannen',   label: 'Plannen',   icon: 'calendar' },
    { id: 'ai',        label: 'AI Coach',  icon: 'sparkles', plan: 'premium' },
    { id: 'trofeeen',  label: 'Trofeeën',  icon: 'trophy' },
  ];
  return (
    <aside style={{
      width, flexShrink: 0, height: '100%', background: t.sidebar,
      borderRight: `1px solid ${t.border}`, display: 'flex', flexDirection: 'column',
      padding: '20px 12px', boxSizing: 'border-box',
    }}>
      <div style={{ padding: '0 6px 18px', marginBottom: 12, borderBottom: `1px solid ${t.border}` }}>
        <Lockup t={t} />
      </div>
      <nav style={{ display: 'flex', flexDirection: 'column', gap: 2, flex: 1 }}>
        {items.map(it => {
          const on = it.id === active;
          return (
            <div key={it.id} style={{
              display: 'flex', alignItems: 'center', gap: 12, padding: '10px 12px',
              borderRadius: 10, background: on ? t.primaryDim : 'transparent',
              color: on ? t.primary : t.fgDim,
              fontFamily: 'Nunito', fontWeight: on ? 800 : 600, fontSize: 13.5,
            }}>
              <PI name={it.icon} size={17} />
              <span style={{ flex: 1 }}>{it.label}</span>
              {it.plan === 'premium' && <PlanBadge t={t} plan="premium" size="sm" />}
              {on && <div style={{ width: 3, height: 18, background: t.primary, borderRadius: 2 }} />}
            </div>
          );
        })}
      </nav>
      <div style={{ paddingTop: 12, borderTop: `1px solid ${t.border}` }}>
        <div style={{
          display: 'flex', alignItems: 'center', gap: 10, padding: 10,
          background: t.card, borderRadius: 10,
          border: t.mode === 'light' ? `1px solid ${t.border}` : 'none',
        }}>
          <div style={{
            width: 34, height: 34, borderRadius: 999,
            background: 'linear-gradient(135deg, #0096C7, #9D4EDD)',
            color: '#fff', fontWeight: 800, fontSize: 14, display: 'flex',
            alignItems: 'center', justifyContent: 'center', flexShrink: 0,
          }}>S</div>
          <div style={{ minWidth: 0, flex: 1 }}>
            <div style={{ fontWeight: 800, fontSize: 13, color: t.fg,
              overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>Sanne de Vries</div>
            <div style={{ fontSize: 11, fontWeight: 700, color: t.fgMute, marginTop: 1 }}>4 HAVO · lvl 12</div>
          </div>
        </div>
      </div>
    </aside>
  );
}

/* ─── Topbar ──────────────────────────────────────────────── */
function Topbar({ t, title, subtitle, rightExtra = null }) {
  return (
    <header style={{
      padding: '18px 28px', display: 'flex', alignItems: 'center', gap: 16,
      background: t.topbar, borderBottom: `1px solid ${t.border}`, flexShrink: 0,
    }}>
      <div style={{ minWidth: 0, flex: 1 }}>
        <div style={{ fontFamily: 'Fredoka One', fontSize: 24, lineHeight: '28px',
          color: t.fg, letterSpacing: '-0.01em' }}>{title}</div>
        {subtitle && <div style={{ fontSize: 12.5, fontWeight: 600, color: t.fgDim, marginTop: 3 }}>{subtitle}</div>}
      </div>
      <div style={{ display: 'flex', alignItems: 'center', gap: 10, flexShrink: 0 }}>
        {rightExtra}
        <SnapsPill t={t} count={240} />
        <StreakPill t={t} count={5} />
        <button style={{
          width: 36, height: 36, borderRadius: 10, background: t.card,
          border: `1px solid ${t.border}`, color: t.fgDim,
          display: 'flex', alignItems: 'center', justifyContent: 'center',
          cursor: 'pointer', position: 'relative',
        }}>
          <PI name="bell" size={17} />
          <div style={{
            position: 'absolute', top: 7, right: 7, width: 8, height: 8,
            borderRadius: 999, background: t.red, border: `2px solid ${t.topbar}`,
          }} />
        </button>
      </div>
    </header>
  );
}

/* ─── Pills ──────────────────────────────────────────────── */
function SnapsPill({ t, count = 240 }) {
  return (
    <div style={{
      display: 'inline-flex', alignItems: 'center', gap: 5, height: 32, padding: '0 12px',
      borderRadius: 999, background: t.goldDim, color: t.gold,
      border: `1.5px solid ${hexToRgba(t.gold, 0.30)}`,
      fontFamily: 'Fredoka One', fontSize: 15, lineHeight: 1,
    }}>
      <PI name="zap" size={13} fill="currentColor" color={t.gold} strokeWidth={0} />
      <span style={{ marginTop: -1 }}>{count}</span>
    </div>
  );
}

function StreakPill({ t, count = 5 }) {
  const orange = t.mode === 'dark' ? '#F97316' : '#C2410C';
  const orangeBg = t.mode === 'dark' ? 'rgba(249,115,22,0.14)' : 'rgba(234,88,12,0.10)';
  const orangeBd = t.mode === 'dark' ? 'rgba(249,115,22,0.28)' : 'rgba(234,88,12,0.30)';
  return (
    <div style={{
      display: 'inline-flex', alignItems: 'center', gap: 5, height: 28, padding: '0 10px',
      borderRadius: 999, background: orangeBg, color: orange,
      border: `1.5px solid ${orangeBd}`,
    }}>
      <span style={{ fontSize: 12 }}>🔥</span>
      <span style={{ fontFamily: 'Fredoka One', fontWeight: 400, fontSize: 14, lineHeight: 1, marginTop: -1 }}>{count}x</span>
    </div>
  );
}

function PlanBadge({ t, plan = 'premium', size = 'md' }) {
  const isDark = t.mode === 'dark';
  const spec = plan === 'pro'
    ? {
        bg: isDark ? 'rgba(157,78,221,0.18)' : 'rgba(124,58,237,0.10)',
        fg: isDark ? '#C4B5FD' : '#6D28D9',
        bd: isDark ? 'rgba(157,78,221,0.36)' : 'rgba(124,58,237,0.30)',
        label: 'Pro', icon: 'sparkles',
      }
    : plan === 'free'
      ? {
          bg: isDark ? 'rgba(148,163,184,0.14)' : 'rgba(100,116,139,0.08)',
          fg: isDark ? '#CBD5E1' : '#475569',
          bd: isDark ? 'rgba(148,163,184,0.32)' : 'rgba(100,116,139,0.26)',
          label: 'Free', icon: 'circle',
        }
    : {
        bg: isDark ? 'rgba(255,208,0,0.14)' : 'rgba(217,119,6,0.10)',
        fg: isDark ? t.gold : '#B45309',
        bd: isDark ? 'rgba(255,208,0,0.36)' : 'rgba(217,119,6,0.30)',
        label: 'Premium', icon: 'sparkles',
      };
  const z = size === 'sm'
    ? { h: 18, px: '0 7px', fs: 9, ic: 9, gap: 3 }
    : { h: 22, px: '0 9px', fs: 10, ic: 10, gap: 4 };
  return (
    <span style={{
      display: 'inline-flex', alignItems: 'center', gap: z.gap, height: z.h, padding: z.px,
      borderRadius: 999, background: spec.bg, color: spec.fg, border: `1px solid ${spec.bd}`,
      fontFamily: 'Nunito', fontWeight: 800, fontSize: z.fs, letterSpacing: 0.4, textTransform: 'uppercase',
    }}>
      <PI name={spec.icon} size={z.ic} fill="currentColor" strokeWidth={0} color={spec.fg} />
      {spec.label}
    </span>
  );
}

/* ─── SubjectChip — DS pill (preview/pills.html) ────────── */
/* padding 4px 10px 4px 8px, radius 20px, 11px/800,
   bg color-mix ~12%, border ~20%, Lucide icon 12px */
const SUBJECT_ICON = {
  wiskunde: 'calculator', biologie: 'leaf', scheikunde: 'flask-conical',
  natuurkunde: 'zap', geschiedenis: 'landmark', aardrijkskunde: 'map',
  economie: 'trending-up', informatica: 'terminal',
  engels: 'book', nederlands: 'book-open-text', frans: 'languages', duits: 'languages',
  maatschappijleer: 'users',
};
function SubjectChip({ t, subject, size = 'md', iconOnly = false }) {
  const hex = SUBJECTS[subject] || '#64748B';
  const iconName = SUBJECT_ICON[subject] || 'book-open';
  const color = t.subjectFg(hex);
  const bg = hexToRgba(hex, 0.12);
  const bd = hexToRgba(hex, 0.22);
  if (iconOnly) {
    return (
      <span style={{
        display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
        width: size === 'sm' ? 18 : 22, height: size === 'sm' ? 18 : 22,
        borderRadius: 6, background: bg, color,
        border: `1px solid ${bd}`, flexShrink: 0,
      }}>
        <PI name={iconName} size={size === 'sm' ? 11 : 13} color={color} strokeWidth={2.2} />
      </span>
    );
  }
  const z = size === 'sm'
    ? { pad: '3px 9px 3px 7px', fs: 10,   ic: 11, gap: 4 }
    : { pad: '4px 10px 4px 8px', fs: 11, ic: 12, gap: 5 };
  return (
    <span style={{
      display: 'inline-flex', alignItems: 'center', gap: z.gap,
      padding: z.pad, borderRadius: 20, fontSize: z.fs, fontWeight: 800,
      background: bg, color, border: `1px solid ${bd}`,
      fontFamily: 'Nunito', textTransform: 'capitalize', letterSpacing: 0.1,
      whiteSpace: 'nowrap',
    }}>
      <PI name={iconName} size={z.ic} color={color} strokeWidth={2.2} />
      {subject}
    </span>
  );
}

/* ─── GradientBorderCard — DS quiz-cards pattern ──────── */
/* ::before mask-trick: 1.5px gradient-ring van --sc naar transparent 55% @ 0.45 */
function GradientBorderCard({ t, subject, radius = 12, children, style }) {
  const hex = SUBJECTS[subject] || '#64748B';
  const ref = useRef(null);
  useEffect(() => {
    if (!ref.current) return;
    // Inject ::before per-instance via unique class
    const el = ref.current;
    const id = 'gb-' + Math.random().toString(36).slice(2, 9);
    el.setAttribute('data-gb', id);
    const css = `[data-gb="${id}"]::before{content:"";position:absolute;inset:0;border-radius:inherit;padding:1.5px;pointer-events:none;z-index:1;background:linear-gradient(135deg, ${hex} 0%, transparent 55%);opacity:0.45;-webkit-mask:linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);mask:linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);-webkit-mask-composite:xor;mask-composite:exclude;}`;
    const style = document.createElement('style');
    style.textContent = css;
    document.head.appendChild(style);
    return () => { style.remove(); };
  }, [hex]);
  return (
    <div ref={ref} style={{
      background: t.card, border: `1px solid ${t.border}`,
      borderRadius: radius, position: 'relative', overflow: 'hidden', isolation: 'isolate',
      boxShadow: t.mode === 'dark' ? '0 2px 12px rgba(0,0,0,0.30)' : '0 1px 3px rgba(15,23,42,0.08)',
      ...(style || {}),
    }}>
      {children}
    </div>
  );
}

/* ─── Task-type label (DS-compliant: caps-label = 10px/800/tracked) ─── */
/* Keuze (b) uit DS: .label-stijl = 10px, weight 800, letter-spacing 1.2px, color --fg2.
   Dit is de DS-erkende conventie voor compacte labels (zie preview/pills.html .label).
   Uppercase hier is typografische label-conventie, geen emphasis-caps. */
function TaskTypeLabel({ t, children }) {
  return (
    <span style={{
      fontSize: 10, fontWeight: 800, color: t.fgMute,
      letterSpacing: 1.2, textTransform: 'uppercase', fontFamily: 'Nunito',
    }}>{children}</span>
  );
}

/* ─── TaskCard (compact, web-density) ────────────────────── */
function TaskCard({ t, subject, title, mins, source, type = 'oefenen', done = false, compact = false }) {
  const pad = compact ? '10px 12px' : '12px 14px';
  return (
    <GradientBorderCard t={t} subject={subject} radius={12}
      style={{ opacity: done ? 0.55 : 1 }}>
      <div style={{ padding: pad, display: 'flex', gap: 10, alignItems: 'flex-start' }}>
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 5 }}>
            <SubjectChip t={t} subject={subject} size="sm" />
            <TaskTypeLabel t={t}>{type}</TaskTypeLabel>
          </div>
          <div style={{
            fontSize: 13.5, color: t.fg, fontWeight: 700, lineHeight: 1.35,
            textDecoration: done ? 'line-through' : 'none',
          }}>{title}</div>
          <div style={{ fontSize: 11, color: t.fgDim, fontWeight: 600, marginTop: 3 }}>
            {source} · {mins} min
          </div>
        </div>
        <div style={{
          width: 22, height: 22, borderRadius: 6,
          border: `1.5px solid ${done ? t.green : t.borderStrong}`,
          background: done ? t.green : 'transparent',
          display: 'flex', alignItems: 'center', justifyContent: 'center',
          flexShrink: 0, marginTop: 2,
        }}>
          {done && <PI name="check" size={13} color={t.mode === 'dark' ? '#0A0F1E' : '#FFFFFF'} strokeWidth={3} />}
        </div>
      </div>
    </GradientBorderCard>
  );
}

/* ─── PulseCard ───────────────────────────────────────────── */
/* Layout: [mascot] [tekst-kolom: label + heading + body] */
function PulseCard({ t, label = 'Pulse', title, body, footer, prominent = true, mood = 'idle' }) {
  const fill = prominent ? t.pulseFill : t.card;
  const titleColor = t.mode === 'dark' ? '#F1F5F9' : '#1E1B4B';
  const bodyColor = t.mode === 'dark' ? t.fgDim : '#4C1D95';
  const labelCol = t.mode === 'dark' ? '#C4B5FD' : '#7C3AED';
  const borderCol = t.mode === 'dark' ? 'rgba(157,78,221,0.25)' : '#C4B5FD';
  return (
    <div style={{
      background: fill, border: `1px solid ${borderCol}`,
      borderRadius: 14, padding: '14px 16px',
      boxShadow: prominent ? t.pulseGlow : 'none',
      position: 'relative', overflow: 'hidden',
      display: 'flex', gap: 12, alignItems: 'flex-start',
    }}>
      <PulseMascot size={52} mood={mood} style={{ marginTop: 2 }} />
      <div style={{ flex: 1, minWidth: 0 }}>
        <div style={{
          display: 'inline-flex', alignItems: 'center', gap: 6, marginBottom: 6,
        }}>
          <div style={{
            width: 7, height: 7, borderRadius: 999, background: labelCol,
            boxShadow: t.mode === 'dark' ? '0 0 8px ' + labelCol : 'none',
          }} />
          <span style={{
            fontSize: 10, fontWeight: 800, letterSpacing: 0.6, textTransform: 'uppercase',
            color: labelCol,
          }}>{label}</span>
        </div>
        <div style={{
          fontFamily: 'Fredoka One', fontWeight: 400, fontSize: 17, lineHeight: 1.3,
          letterSpacing: '-0.01em', color: titleColor, marginBottom: 5,
        }}>{title}</div>
        <div style={{ fontSize: 12.5, fontWeight: 500, color: bodyColor, lineHeight: 1.55 }}>{body}</div>
        {footer && (
          <div style={{
            marginTop: 10, paddingTop: 10,
            borderTop: `1px solid ${t.mode === 'dark' ? 'rgba(196,181,253,0.18)' : 'rgba(124,58,237,0.18)'}`,
            fontSize: 11.5, color: t.mode === 'dark' ? '#94A3B8' : '#6D28D9', fontWeight: 600,
          }}>{footer}</div>
        )}
      </div>
    </div>
  );
}

/* ─── WeekStrip — content-rich, 7-koloms dag-boxen ───────── */
/* Inspired by screens/paradigm-1-stapel.jsx WeekCell: per dag een card
   met datum, vak-pills, of deadline-vak, of "— leeg —". Today = glow. */
function WeekStrip({ t, week, label = 'Week 41', range = '7–13 okt', context, controls = true }) {
  return (
    <div>
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 10 }}>
        <div style={{ display: 'flex', alignItems: 'baseline', gap: 10, flexWrap: 'wrap' }}>
          <span style={{ fontFamily: 'Fredoka One', fontSize: 18, color: t.fg, letterSpacing: '-0.01em' }}>{label}</span>
          <span style={{ fontSize: 12, color: t.fgMute, fontWeight: 700 }}>{range}</span>
          {context && <span style={{ fontSize: 12, color: t.fgDim, fontWeight: 600 }}>· {context}</span>}
        </div>
        {controls && (
          <div style={{ display: 'flex', gap: 6 }}>
            <BtnGhost t={t}><PI name="chevron-left" size={13} /></BtnGhost>
            <BtnGhost t={t}><PI name="calendar" size={13} />Maand</BtnGhost>
            <BtnGhost t={t}><PI name="chevron-right" size={13} /></BtnGhost>
          </div>
        )}
      </div>
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(7, 1fr)', gap: 10 }}>
        {week.map((d, i) => <WeekCell key={i} t={t} d={d} />)}
      </div>
    </div>
  );
}

function WeekCell({ t, d }) {
  const isToday = !!d.today;
  const isDeadline = !!d.deadline;
  const isMissed = !!d.missed;
  const isWeekend = d.day === 'za' || d.day === 'zo';
  const hex = isDeadline ? SUBJECTS[d.deadline] : null;

  const border = isToday
    ? t.primary
    : isMissed
      ? t.herstelBorder
      : t.border;

  const bg = isToday
    ? t.primarySoft
    : isMissed
      ? t.herstelBg
      : isWeekend
        ? t.cardSunken
        : t.card;

  return (
    <div style={{
      background: bg,
      border: `1px solid ${border}`,
      borderRadius: 12, padding: '10px 10px 12px',
      display: 'flex', flexDirection: 'column', gap: 8, minHeight: 108,
      position: 'relative', overflow: 'hidden',
      opacity: isWeekend && !isToday && d.items?.length === 0 ? 0.72 : 1,
      boxShadow: isToday
        ? (t.mode === 'dark' ? '0 8px 20px rgba(0,180,216,0.12)' : '0 6px 16px rgba(0,150,199,0.12)')
        : 'none',
    }}>
      {isToday && (
        <div style={{
          position: 'absolute', top: 0, left: 0, right: 0, height: 3,
          background: `linear-gradient(90deg, ${t.primary}, transparent)`,
        }} />
      )}

      <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between' }}>
        <span style={{
          fontSize: 10, fontWeight: 800,
          color: isToday ? t.primary : isMissed ? t.herstelFg : t.fgMute,
          letterSpacing: 0.8, textTransform: 'uppercase',
        }}>{d.day}{isToday ? ' · nu' : ''}</span>
        <span style={{
          fontFamily: 'Fredoka One', fontSize: 17, lineHeight: 1,
          color: isToday ? t.primary : isMissed ? t.herstelTitle : t.fg, letterSpacing: '-0.01em',
        }}>{d.date}</span>
      </div>

      {isDeadline ? (
        <div style={{
          marginTop: 2, background: hexToRgba(hex, 0.16),
          border: `1px solid ${hexToRgba(hex, 0.36)}`,
          borderRadius: 8, padding: '6px 8px',
          display: 'flex', flexDirection: 'column', gap: 2,
        }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 4 }}>
            <PI name="file-text" size={10} color={t.subjectFg(hex)} />
            <span style={{ fontSize: 9, fontWeight: 800, color: t.subjectFg(hex), letterSpacing: 0.6, textTransform: 'uppercase' }}>
              {d.dlType || 'Toets'}
            </span>
          </div>
          <span style={{ fontSize: 11, fontWeight: 800, color: t.fg, lineHeight: 1.3 }}>{d.dlLabel}</span>
        </div>
      ) : (d.items?.length > 0 ? (
        <div style={{ display: 'flex', flexWrap: 'wrap', gap: 4 }}>
          {d.items.slice(0, 3).map((it, i) => (
            <SubjectChip key={i} t={t} subject={it.s} size="sm" iconOnly />
          ))}
          {d.items.length > 3 && (
            <span style={{
              fontSize: 10, color: t.fgMute, fontWeight: 800,
              padding: '2px 6px', borderRadius: 6,
              background: t.cardSunken, border: `1px solid ${t.border}`,
              display: 'inline-flex', alignItems: 'center',
            }}>+{d.items.length - 3}</span>
          )}
        </div>
      ) : (
        <div style={{ fontSize: 10, color: t.fgFaint, fontWeight: 600, fontStyle: 'italic' }}>— leeg —</div>
      ))}

      {isMissed && (
        <div style={{
          marginTop: 'auto', display: 'flex', alignItems: 'center', gap: 4,
          fontSize: 9, fontWeight: 800, color: t.herstelFg, letterSpacing: 0.5,
        }}>
          <PI name="rotate-ccw" size={9} color={t.herstelFg} />
          <span style={{ textTransform: 'uppercase' }}>gemist</span>
        </div>
      )}
    </div>
  );
}

function BtnGhost({ t, children }) {
  return (
    <button style={{
      display: 'inline-flex', alignItems: 'center', gap: 5,
      padding: '6px 10px', borderRadius: 8,
      background: t.card, border: `1px solid ${t.border}`,
      color: t.fgDim, fontSize: 11, fontWeight: 700, cursor: 'pointer',
      fontFamily: 'Nunito, system-ui, sans-serif',
    }}>{children}</button>
  );
}

/* ─── ColumnHeader + SectionLabel ─────────────────────────── */
function ColumnHeader({ t, title, subtitle, accent, count }) {
  return (
    <div style={{
      padding: '14px 18px 12px', borderBottom: `1px solid ${t.border}`,
      display: 'flex', alignItems: 'baseline', gap: 10,
    }}>
      <h2 style={{
        fontFamily: 'Fredoka One', fontSize: 20, color: accent || t.fg,
        margin: 0, letterSpacing: '-0.01em', lineHeight: 1.1,
      }}>{title}</h2>
      {count !== undefined && (
        <span style={{
          fontSize: 11, fontWeight: 800, color: t.fgMute, letterSpacing: 0.4,
        }}>{count} taken</span>
      )}
      {subtitle && (
        <span style={{ fontSize: 11, color: t.fgDim, fontWeight: 600, marginLeft: 'auto' }}>{subtitle}</span>
      )}
    </div>
  );
}

function SectionLabel({ t, children, right }) {
  return (
    <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 10 }}>
      <div style={{
        fontSize: 10.5, fontWeight: 800, color: t.fgMute,
        letterSpacing: 0.8, textTransform: 'uppercase',
      }}>{children}</div>
      <div style={{ flex: 1, height: 1, background: t.border }} />
      {right}
    </div>
  );
}

/* ─── Expose ───────────────────────────────────────────────── */
Object.assign(window, {
  PI, BrowserShell, Lockup, PulseMascot, Sidebar, Topbar,
  SnapsPill, StreakPill, PlanBadge, SubjectChip, GradientBorderCard, TaskCard, TaskTypeLabel, PulseCard,
  WeekStrip, WeekCell, BtnGhost, ColumnHeader, SectionLabel,
});
