// ─────────────────────────────────────────────────────────────
// Finisher · Premium Design System
// Raycast DNA, elevated. Geist + Geist Mono. Paper · Ink · Indigo · Amber.
// Mirrors FinisherTheme.swift so this prototype maps 1:1 to the SwiftUI app.
// ─────────────────────────────────────────────────────────────

// Accent options (swappable). Default = light aubergine (Valteria, lightened).
const ACCENTS = {
  aubergine: { base: '#8463B0', deep: '#5B3D7C', soft: 'rgba(132,99,176,0.12)', tint: 'rgba(132,99,176,0.20)', glow: 'rgba(132,99,176,0.36)' },
  violet:    { base: '#6E50D1', deep: '#553EA3', soft: 'rgba(110,80,209,0.10)', tint: 'rgba(110,80,209,0.18)', glow: 'rgba(167,139,250,0.38)' },
  emerald:   { base: '#34B88E', deep: '#1E9A74', soft: 'rgba(52,184,142,0.12)', tint: 'rgba(52,184,142,0.20)', glow: 'rgba(52,184,142,0.34)' },
  copper:    { base: '#C9622E', deep: '#A84E1F', soft: 'rgba(201,98,46,0.10)', tint: 'rgba(201,98,46,0.18)', glow: 'rgba(224,139,92,0.34)' },
};

let _accentKey = 'aubergine';
function setAccent(key) { if (ACCENTS[key]) { _accentKey = key; rebuildTokens(); } }
function accentKey() { return _accentKey; }

let TOKENS = {};
function rebuildTokens() {
  const a = ACCENTS[_accentKey];
  TOKENS = {
    // ── Surface ramp — warm espresso neutral (de-oranged) ──
    bg:        '#ECEBE6',
    bgDeep:    '#E4E3DD',
    soft:      '#F4F3EF',
    card:      '#FFFFFF',
    raised:    '#FFFFFF',
    subtle:    'rgba(30,26,20,0.045)',
    input:     'rgba(30,26,20,0.05)',

    // ── Ink — warm espresso near-black ──
    ink:       '#211C16',
    text:      '#211C16',
    textDim:   'rgba(33,28,22,0.60)',
    textMuted: 'rgba(33,28,22,0.42)',
    textFaint: 'rgba(33,28,22,0.27)',
    textGhost: 'rgba(33,28,22,0.11)',

    // ── Hairlines ──
    hair:       'rgba(33,28,22,0.085)',
    hairStrong: 'rgba(33,28,22,0.15)',
    hairDash:   'rgba(33,28,22,0.20)',

    // ── Accent (single consistent color everywhere) ──
    accent:     a.base,
    accentDeep: a.deep,
    accentSoft: a.soft,
    accentTint: a.tint,
    accentGlow: a.glow,

    // ── Amber — streaks / achievement / this-week bridge ──
    amber:     '#C68A2E',
    amberDeep: '#9E6C1F',
    amberSoft: 'rgba(198,138,46,0.11)',
    amberTint: 'rgba(198,138,46,0.20)',

    // ── Semantic ──
    success:    '#2E8B57',
    successSoft:'rgba(46,139,87,0.11)',
    danger:     '#C8442B',
    dangerSoft: 'rgba(200,68,43,0.10)',

    // ── Shadows — warm, soft, tactile depth ──
    shadowSm: '0 1px 2px rgba(40,30,15,0.05), 0 1px 1px rgba(40,30,15,0.04)',
    shadowMd: '0 2px 4px rgba(40,30,15,0.05), 0 8px 18px -4px rgba(40,30,15,0.10), 0 18px 36px -12px rgba(40,30,15,0.12)',
    shadowLg: '0 4px 10px rgba(40,30,15,0.08), 0 18px 40px -8px rgba(40,30,15,0.16), 0 40px 70px -20px rgba(40,30,15,0.22)',

    // ── Radii ──
    rSm: 9, rMd: 13, rLg: 18, rXl: 24,

    // ── Motion ──
    spring:  'cubic-bezier(.32,.72,0,1)',
    springy: 'cubic-bezier(.34,1.36,.64,1)',
    ease:    'cubic-bezier(.4,0,.2,1)',
    dFast: '150ms', dBase: '240ms', dSlow: '380ms',
  };
  window.TOKENS = TOKENS;
}
rebuildTokens();

const FONTS = {
  sans: "'Geist', -apple-system, BlinkMacSystemFont, system-ui, sans-serif",
  mono: "'Geist Mono', ui-monospace, 'SF Mono', monospace",
};

// hex → rgba
function hexA(hex, alpha) {
  if (!hex) return `rgba(75,69,229,${alpha})`;
  let h = hex.replace('#', '');
  if (h.length === 3) h = h.split('').map(c => c + c).join('');
  const r = parseInt(h.slice(0, 2), 16), g = parseInt(h.slice(2, 4), 16), b = parseInt(h.slice(4, 6), 16);
  return `rgba(${r},${g},${b},${alpha})`;
}
// luminance check for readable foreground on a color
function readableOn(hex) {
  let h = (hex || '#000').replace('#', '');
  if (h.length === 3) h = h.split('').map(c => c + c).join('');
  const r = parseInt(h.slice(0,2),16)/255, g = parseInt(h.slice(2,4),16)/255, b = parseInt(h.slice(4,6),16)/255;
  return (0.2126*r + 0.7152*g + 0.0722*b) > 0.6 ? '#0B0B0F' : '#FFFFFF';
}

/* ───────────── Primitives ───────────── */

// Card — r18, soft/card bg, hair stroke, restrained shadow. Pressable variant.
function Card({ children, style = {}, onClick, hero = false, pressable = false, accentColor }) {
  const [press, setPress] = React.useState(false);
  const T = TOKENS;
  const bg = hero ? 'linear-gradient(135deg, #FDFCF9 0%, #FFFFFF 46%, ' + hexA(accentColor || T.accent, 0.05) + ' 100%)' : T.card;
  return (
    <div
      onClick={onClick}
      onPointerDown={pressable ? () => setPress(true) : undefined}
      onPointerUp={pressable ? () => setPress(false) : undefined}
      onPointerLeave={pressable ? () => setPress(false) : undefined}
      style={{
        background: bg,
        border: `1px solid ${T.hair}`,
        borderRadius: T.rXl,
        boxShadow: T.shadowMd,
        cursor: onClick ? 'pointer' : 'default',
        transform: press ? 'scale(0.985)' : 'scale(1)',
        transition: `transform ${T.dFast} ${T.spring}, box-shadow ${T.dBase} ${T.spring}`,
        ...style,
      }}
    >{children}</div>
  );
}

// Dark signature card — warm espresso gradient, white content.
function DarkCard({ children, style = {}, onClick, pressable = true }) {
  const [press, setPress] = React.useState(false);
  const T = TOKENS;
  return (
    <div onClick={onClick}
      onPointerDown={pressable ? () => setPress(true) : undefined}
      onPointerUp={pressable ? () => setPress(false) : undefined}
      onPointerLeave={pressable ? () => setPress(false) : undefined}
      style={{
        position: 'relative', overflow: 'hidden',
        background: `linear-gradient(155deg, #2A211A 0%, #211A14 50%, #18130E 100%)`,
        borderRadius: T.rXl, border: `1px solid rgba(255,255,255,0.06)`,
        boxShadow: `0 1px 0 rgba(255,255,255,0.05) inset, ${T.shadowLg}`,
        cursor: onClick ? 'pointer' : 'default',
        transform: press ? 'scale(0.985)' : 'scale(1)',
        transition: `transform ${T.dFast} ${T.spring}`,
        ...style,
      }}>
      <div style={{ position: 'absolute', top: -90, right: -50, width: 240, height: 240, borderRadius: '50%', background: `radial-gradient(circle, ${hexA(T.accent, 0.42)}, transparent 70%)`, filter: 'blur(10px)', pointerEvents: 'none' }} />
      <div style={{ position: 'relative', zIndex: 1 }}>{children}</div>
    </div>
  );
}

// Reveal — CSS-only entrance (slide, no opacity gating → content is ALWAYS visible).
// Stagger via animation-delay. Resilient to rAF/timer throttling.
function Reveal({ children, delay = 0, y = 12, style = {} }) {
  return <div className="fin-in" style={{ animationDelay: `${delay}ms`, ...style }}>{children}</div>;
}

// Subtle paper grain — tactile warmth, fixed behind content
function Grain({ opacity = 0.5 }) {
  return null;
}

// Eyebrow — mono, uppercase, quiet
function Eyebrow({ children, color, style = {} }) {
  return (
    <div style={{
      fontFamily: FONTS.mono, fontSize: 10.5, fontWeight: 500,
      letterSpacing: 0.5, textTransform: 'uppercase',
      color: color || TOKENS.textMuted, whiteSpace: 'nowrap', ...style,
    }}>{children}</div>
  );
}

// Section heading — title + optional subtitle + trailing metric
function SectionHeading({ title, subtitle, trailing }) {
  const T = TOKENS;
  return (
    <div style={{ display: 'flex', alignItems: 'flex-end', justifyContent: 'space-between', gap: 12 }}>
      <div style={{ minWidth: 0 }}>
        <div style={{ fontSize: 14.5, fontWeight: 600, color: T.ink, letterSpacing: -0.2 }}>{title}</div>
        {subtitle && <div style={{ fontSize: 12.5, color: T.textMuted, letterSpacing: -0.1, marginTop: 2 }}>{subtitle}</div>}
      </div>
      {trailing != null && (
        <div style={{ fontFamily: FONTS.mono, fontSize: 11, color: T.textMuted, fontWeight: 500, fontVariantNumeric: 'tabular-nums', flexShrink: 0, paddingBottom: 1 }}>{trailing}</div>
      )}
    </div>
  );
}

// Large screen title block — editorial, oversized
function ScreenTitle({ eyebrow, title, sub }) {
  const T = TOKENS;
  return (
    <div style={{ marginBottom: 4 }}>
      {eyebrow && <Eyebrow color={T.accent} style={{ marginBottom: 8 }}>{eyebrow}</Eyebrow>}
      <div style={{ fontSize: 38, fontWeight: 700, color: T.ink, letterSpacing: -1.6, lineHeight: '40px' }}>{title}</div>
      {sub && <div style={{ marginTop: 7, fontSize: 15, color: T.textDim, letterSpacing: -0.2, lineHeight: '21px', maxWidth: 340, textWrap: 'pretty' }}>{sub}</div>}
    </div>
  );
}

// CircleCheck — animated check pop on complete (the "subtle acknowledgment")
function CircleCheck({ checked, onClick, size = 22, color }) {
  const T = TOKENS;
  const c = color || T.accent;
  const [burst, setBurst] = React.useState(false);
  const handle = (e) => {
    e?.stopPropagation?.();
    if (!checked) { setBurst(true); setTimeout(() => setBurst(false), 420); }
    onClick?.();
  };
  return (
    <button onClick={handle} style={{
      position: 'relative', width: size, height: size, borderRadius: '50%',
      background: checked ? c : 'transparent',
      border: `1.5px solid ${checked ? c : T.hairStrong}`,
      display: 'flex', alignItems: 'center', justifyContent: 'center',
      cursor: 'pointer', padding: 0, flexShrink: 0,
      transition: `background ${T.dBase} ${T.spring}, border-color ${T.dBase} ${T.spring}, transform ${T.dFast} ${T.springy}`,
      transform: burst ? 'scale(1.18)' : 'scale(1)',
    }}>
      {burst && <span style={{
        position: 'absolute', inset: -4, borderRadius: '50%',
        border: `2px solid ${c}`, animation: 'ringPop 0.42s ease-out forwards',
      }} />}
      <svg width={size * 0.5} height={size * 0.5} viewBox="0 0 12 12" fill="none" style={{
        opacity: checked ? 1 : 0, transform: checked ? 'scale(1)' : 'scale(0.5)',
        transition: `opacity ${T.dFast}, transform ${T.dBase} ${T.springy}`,
      }}>
        <path d="M2.5 6.2L4.8 8.5L9.5 3.5" stroke="#fff" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round" />
      </svg>
    </button>
  );
}

// 12-dot week strip — current week is a longer capsule, animates
function WeekStrip({ week = 1, total = 12, color }) {
  const T = TOKENS;
  const c = color || T.accent;
  return (
    <div style={{ display: 'flex', gap: 4, alignItems: 'center' }}>
      {Array.from({ length: total }).map((_, i) => {
        const filled = i < week;
        const curr = i === week - 1;
        return <div key={i} style={{
          width: curr ? 17 : 9, height: 4, borderRadius: 3,
          background: filled ? c : T.textGhost,
          transition: `width ${T.dSlow} ${T.springy} ${i * 14}ms, background ${T.dBase} ${i * 14}ms`,
        }} />;
      })}
    </div>
  );
}

// Progress ring
function Ring({ size = 62, stroke = 5, progress = 0, color, children }) {
  const T = TOKENS;
  const c = color || T.accent;
  const r = (size - stroke) / 2;
  const circ = 2 * Math.PI * r;
  return (
    <div style={{ position: 'relative', width: size, height: size, flexShrink: 0 }}>
      <svg width={size} height={size} style={{ transform: 'rotate(-90deg)' }}>
        <circle cx={size/2} cy={size/2} r={r} stroke={T.textGhost} strokeWidth={stroke} fill="none" />
        <circle cx={size/2} cy={size/2} r={r} stroke={c} strokeWidth={stroke} fill="none"
          strokeDasharray={circ} strokeDashoffset={circ * (1 - progress)} strokeLinecap="round"
          style={{ transition: `stroke-dashoffset ${T.dSlow} ${T.spring}` }} />
      </svg>
      <div style={{ position: 'absolute', inset: 0, display: 'flex', alignItems: 'center', justifyContent: 'center', flexDirection: 'column' }}>{children}</div>
    </div>
  );
}

// Goal badge / chip
function GoalBadge({ label, color, compact }) {
  const T = TOKENS;
  const c = color || T.accent;
  return (
    <div style={{
      display: 'inline-flex', alignItems: 'center', gap: 6,
      padding: compact ? '3px 8px' : '4px 10px', borderRadius: 999,
      background: hexA(c, 0.11), border: `1px solid ${hexA(c, 0.26)}`,
      maxWidth: 160,
    }}>
      <span style={{ width: 5, height: 5, borderRadius: 3, background: c, flexShrink: 0 }} />
      <span style={{ fontSize: compact ? 11 : 11.5, fontWeight: 500, color: T.ink, letterSpacing: -0.1, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{label}</span>
    </div>
  );
}

// Deadline pill — status driven
function deadlineStatus(deadline, isComplete, now = new Date()) {
  if (isComplete) return 'complete';
  const d0 = new Date(deadline); d0.setHours(0,0,0,0);
  const t0 = new Date(now); t0.setHours(0,0,0,0);
  if (d0 < t0) return 'overdue';
  const days = Math.round((d0 - t0) / 86400000);
  return days <= 7 ? 'dueThisWeek' : 'future';
}
function DeadlinePill({ status, date, compact }) {
  const T = TOKENS;
  const map = {
    complete:    { label: 'Complete',  short: 'Complete', color: T.success, icon: 'check' },
    overdue:     { label: 'Overdue',   short: 'Overdue',  color: T.danger,  icon: 'warn' },
    dueThisWeek: { label: 'Due this week', short: 'This week', color: T.amber, icon: 'clock' },
    future:      { label: 'Scheduled', short: 'Scheduled',color: T.accent,  icon: 'cal' },
  };
  const s = map[status] || map.future;
  const icons = {
    check: <path d="M2.5 6L5 8.5 9.5 3.5" stroke={s.color} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" fill="none" />,
    warn:  <path d="M6 2.5L10.5 9.5H1.5L6 2.5zM6 5.4v1.8M6 8.2v.05" stroke={s.color} strokeWidth="1.3" strokeLinecap="round" strokeLinejoin="round" fill="none" />,
    clock: <g stroke={s.color} strokeWidth="1.3" fill="none"><circle cx="6" cy="6" r="4.2" /><path d="M6 3.8V6l1.6 1" strokeLinecap="round" /></g>,
    cal:   <g stroke={s.color} strokeWidth="1.2" fill="none"><rect x="1.8" y="2.6" width="8.4" height="7.4" rx="1.4" /><path d="M1.8 4.8h8.4M4 1.6v2M8 1.6v2" strokeLinecap="round" /></g>,
  };
  const dateStr = date ? new Date(date).toLocaleDateString('en-US', { month: 'short', day: 'numeric' }) : null;
  return (
    <div style={{
      display: 'inline-flex', alignItems: 'center', gap: compact ? 4 : 6,
      padding: compact ? '0 8px' : '0 10px', height: compact ? 24 : 28, borderRadius: 999,
      background: hexA(s.color, 0.11), border: `1px solid ${hexA(s.color, 0.22)}`,
    }}>
      <svg width="12" height="12" viewBox="0 0 12 12">{icons[s.icon]}</svg>
      <span style={{ fontSize: compact ? 11 : 12, fontWeight: 600, color: s.color, letterSpacing: -0.1 }}>{compact ? s.short : s.label}</span>
      {dateStr && !compact && <span style={{ fontSize: 11.5, color: T.textMuted }}>{dateStr}</span>}
    </div>
  );
}

// Primary button
function Button2({ children, onClick, variant = 'secondary', full = false, size = 'md', icon, style = {}, disabled }) {
  const T = TOKENS;
  const [press, setPress] = React.useState(false);
  const variants = {
    primary:   { bg: T.accent, fg: '#fff', border: 'transparent', shadow: `0 1px 2px ${hexA(T.accent,0.4)}, inset 0 1px 0 rgba(255,255,255,0.18)` },
    secondary: { bg: T.soft, fg: T.ink, border: T.hair, shadow: 'none' },
    ghost:     { bg: 'transparent', fg: T.ink, border: 'transparent', shadow: 'none' },
    selected:  { bg: T.accentSoft, fg: T.ink, border: hexA(T.accent,0.28), shadow: 'none' },
    danger:    { bg: T.danger, fg: '#fff', border: 'transparent', shadow: 'none' },
  };
  const v = variants[variant] || variants.secondary;
  const h = size === 'lg' ? 46 : size === 'sm' ? 34 : 40;
  return (
    <button onClick={disabled ? undefined : onClick}
      onPointerDown={() => setPress(true)} onPointerUp={() => setPress(false)} onPointerLeave={() => setPress(false)}
      style={{
        display: 'inline-flex', alignItems: 'center', justifyContent: 'center', gap: 7,
        width: full ? '100%' : 'auto', height: h, padding: `0 ${size === 'sm' ? 12 : 16}px`,
        borderRadius: T.rMd, border: `1px solid ${v.border}`, background: v.bg, color: v.fg,
        fontFamily: FONTS.sans, fontSize: size === 'lg' ? 14.5 : 13.5, fontWeight: 600, letterSpacing: -0.15,
        cursor: disabled ? 'default' : 'pointer', opacity: disabled ? 0.5 : 1, boxShadow: v.shadow,
        transform: press ? 'scale(0.97)' : 'scale(1)', transition: `transform ${T.dFast} ${T.spring}`,
        ...style,
      }}>
      {icon}{children}
    </button>
  );
}

// Icon glyphs (stroke, 1.4) — minimal line set
function Icon({ name, size = 16, color, strokeWidth = 1.5 }) {
  const c = color || TOKENS.ink;
  const p = { stroke: c, strokeWidth, strokeLinecap: 'round', strokeLinejoin: 'round', fill: 'none' };
  const paths = {
    home:    <path d="M3 9.5L10 4l7 5.5M5 8.5V16h10V8.5" {...p} />,
    daily:   <g {...p}><rect x="3" y="4" width="14" height="13" rx="2.5" /><path d="M3 8h14M7 2.5v3M13 2.5v3" /></g>,
    weekly:  <g {...p}><rect x="3" y="4" width="14" height="13" rx="2.5" /><path d="M3 8h14M7 2.5v3M13 2.5v3" /><circle cx="13.5" cy="13" r="0.3" /></g>,
    goals:   <g {...p}><circle cx="10" cy="10" r="6.5" /><circle cx="10" cy="10" r="3" /><circle cx="10" cy="10" r="0.4" /></g>,
    vision:  <g {...p}><path d="M2.5 10s3-4.5 7.5-4.5S17.5 10 17.5 10s-3 4.5-7.5 4.5S2.5 10 2.5 10z" /><circle cx="10" cy="10" r="2" /></g>,
    habits:  <path d="M3.5 10.5l3.2 3L16.5 4.5" {...p} strokeWidth={1.7} />,
    notes:   <g {...p}><path d="M5 3h7l3 3v11H5z" /><path d="M11.5 3v3.5H15M7.5 10h5M7.5 13h3.5" /></g>,
    chevR:   <path d="M7.5 4l4 4-4 4" {...p} />,
    chevL:   <path d="M12.5 4l-4 4 4 4" {...p} />,
    chevD:   <path d="M4 7l4 4 4-4" {...p} />,
    arrowR:  <path d="M3 9h12M10 4l5 5-5 5" {...p} />,
    plus:    <path d="M9 3.5v11M3.5 9h11" {...p} strokeWidth={1.7} />,
    person:  <g {...p}><circle cx="9" cy="6.5" r="3" /><path d="M3.5 16c0-3 2.5-5 5.5-5s5.5 2 5.5 5" /></g>,
    clock:   <g {...p}><circle cx="9" cy="9" r="6.5" /><path d="M9 5.5V9l2.5 1.5" /></g>,
    sun:     <g {...p}><circle cx="9" cy="9" r="3.2" /><path d="M9 1.5v2M9 14.5v2M1.5 9h2M14.5 9h2M3.7 3.7l1.4 1.4M12.9 12.9l1.4 1.4M3.7 14.3l1.4-1.4M12.9 5.1l1.4-1.4" /></g>,
    pencil:  <path d="M12.5 3L15 5.5 6 14.5l-3 .5.5-3L12.5 3z" {...p} />,
    trash:   <g {...p}><path d="M4 5h10M7.5 5V3.5h3V5M5.5 5l.6 9h5.8l.6-9" /></g>,
    target:  <g {...p}><circle cx="9" cy="9" r="6.5" /><circle cx="9" cy="9" r="3" /></g>,
    briefcase:<g {...p}><rect x="3" y="6" width="14" height="9" rx="2" /><path d="M7 6V4.6A1.6 1.6 0 0 1 8.6 3h2.8A1.6 1.6 0 0 1 13 4.6V6M3 10.5h14" /></g>,
    code:    <g {...p}><path d="M7 6.5l-3.2 3.5 3.2 3.5M13 6.5l3.2 3.5-3.2 3.5" /></g>,
    chart:   <g {...p}><path d="M3.5 3.5v13h13" /><path d="M6.5 12.5l3-3 2.5 2 4-4.7" /></g>,
    team:    <g {...p}><circle cx="7.2" cy="7.5" r="2.5" /><path d="M3 16c0-2.5 1.9-4 4.2-4s4.2 1.5 4.2 4" /><path d="M12.6 5.4a2.4 2.4 0 0 1 0 4.5M14.4 16c0-2.1-1-3.5-2.5-4.1" /></g>,
    sparkles:<path d="M9 2.5l1.4 4.1L14.5 8l-4.1 1.4L9 13.5l-1.4-4.1L3.5 8l4.1-1.4L9 2.5z" {...p} />,
    flame:   <path d="M9 2.5c2.5 3 4 4.8 4 7.5a4 4 0 11-8 0c0-1.3.6-2.4 1.5-3.2C6.8 8 7 9 8 9.2 8.6 7 9 4.8 9 2.5z" {...p} />,
    search:  <g {...p}><circle cx="8" cy="8" r="5" /><path d="M11.8 11.8L15.5 15.5" /></g>,
    note2:   <g {...p}><rect x="3.5" y="3.5" width="13" height="13" rx="2.5" /><path d="M7 8h6M7 11h4" /></g>,
    back:    <path d="M11 4.5L6.5 9l4.5 4.5" {...p} strokeWidth={1.7} />,
    close:   <path d="M5 5l10 10M15 5L5 15" {...p} strokeWidth={1.6} />,
  };
  return <svg width={size} height={size} viewBox="0 0 20 20" style={{ flexShrink: 0 }}>{paths[name]}</svg>;
}

// ─────────────────────────────────────────────────────────────
// Content-first primitives — the anti-container layout language
// ─────────────────────────────────────────────────────────────

// An open section: quiet label row + content directly on the page. No box.
function Section({ label, trailing, action, onAction, children, style = {} }) {
  const T = TOKENS;
  return (
    <section style={{ display: 'flex', flexDirection: 'column', gap: 12, ...style }}>
      {(label || trailing || action) && (
        <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 10 }}>
          <div style={{ fontFamily: FONTS.mono, fontSize: 11, fontWeight: 500, letterSpacing: 0.6, textTransform: 'uppercase', color: T.textMuted }}>{label}</div>
          {action ? (
            <button onClick={onAction} style={{ display: 'inline-flex', alignItems: 'center', gap: 4, background: 'transparent', border: 'none', cursor: 'pointer', fontFamily: FONTS.sans, fontSize: 12.5, fontWeight: 500, color: T.accent, letterSpacing: -0.1, padding: 0 }}>
              {action}<svg width="11" height="11" viewBox="0 0 20 20"><path d="M7.5 4l4 4-4 4" stroke={T.accent} strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" fill="none" /></svg>
            </button>
          ) : trailing != null ? (
            <div style={{ fontFamily: FONTS.mono, fontSize: 11, color: T.textMuted, fontVariantNumeric: 'tabular-nums', fontWeight: 500 }}>{trailing}</div>
          ) : null}
        </div>
      )}
      {children}
    </section>
  );
}

// A full-bleed list — rows separated by hairlines, no surrounding border/box.
function List({ children, style = {} }) {
  return <div style={{ display: 'flex', flexDirection: 'column', ...style }}>{children}</div>;
}

// A list row with a hairline under it (except last). Open, no card chrome.
function Row({ children, onClick, first, last, style = {}, pad = '14px 2px' }) {
  const T = TOKENS;
  const [press, setPress] = React.useState(false);
  return (
    <div onClick={onClick}
      onPointerDown={onClick ? () => setPress(true) : undefined}
      onPointerUp={onClick ? () => setPress(false) : undefined}
      onPointerLeave={onClick ? () => setPress(false) : undefined}
      style={{
        display: 'flex', alignItems: 'center', gap: 12, padding: pad,
        borderBottom: last ? 'none' : `1px solid ${T.hair}`,
        cursor: onClick ? 'pointer' : 'default',
        background: press ? T.subtle : 'transparent',
        borderRadius: press ? 8 : 0,
        transition: `background ${T.dFast}`,
        ...style,
      }}>{children}</div>
  );
}

function Divider({ style = {} }) {
  return <div style={{ height: 1, background: TOKENS.hair, ...style }} />;
}

// keyframes + base reset injected once
function DSStyle() {
  return <style>{`
    @keyframes ringPop { from { opacity: .9; transform: scale(.8); } to { opacity: 0; transform: scale(1.7); } }
    @keyframes rise { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } }
    @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
    @keyframes screenIn { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: translateY(0); } }
    @keyframes finBob { 0%,100% { transform: translateY(0); } 50% { transform: translateY(4px); } }
    .fin-bob { animation: finBob 1.8s ease-in-out infinite; }
    @keyframes finIn { from { transform: translateY(11px); } to { transform: none; } }
    .fin-in { animation: finIn .55s cubic-bezier(.32,.72,0,1) both; }
    .fin-scroll::-webkit-scrollbar { width: 0; height: 0; }
    * { -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; -webkit-tap-highlight-color: transparent; }
    input, textarea, button { font-family: inherit; }
  `}</style>;
}

Object.assign(window, {
  ACCENTS, setAccent, accentKey, FONTS, hexA, readableOn,
  Card, DarkCard, Reveal, Grain, Eyebrow, SectionHeading, ScreenTitle, CircleCheck, WeekStrip, Ring,
  GoalBadge, deadlineStatus, DeadlinePill, Button2, Icon, DSStyle, rebuildTokens,
  Section, List, Row, Divider,
});
