// ui.jsx — theme + shared atoms (cards, status pills, headers, bottom tabs).

// ─────────────────────────────────────────────────────────────
// Theme tokens. Light = warm paper. Dark = cool charcoal.
// Accents are Alex's pen-code: red (lost / urgent) and blue (next-step / set).
// ─────────────────────────────────────────────────────────────
const THEMES = {
  light: {
    name: 'light',
    bg: '#F4F2EE',
    bgGrad: 'linear-gradient(180deg, #F6F4F0 0%, #EFECE6 100%)',
    surface: '#FFFFFF',
    surfaceAlt: '#FBF9F5',
    border: 'rgba(20,18,14,0.07)',
    borderStrong: 'rgba(20,18,14,0.12)',
    text: '#14120E',
    textMute: 'rgba(20,18,14,0.62)',
    textDim: 'rgba(20,18,14,0.38)',
    red: 'oklch(0.60 0.20 25)',
    redSoft: 'oklch(0.94 0.04 25)',
    redInk: 'oklch(0.42 0.18 25)',
    blue: 'oklch(0.55 0.18 255)',
    blueSoft: 'oklch(0.94 0.04 255)',
    blueInk: 'oklch(0.40 0.16 255)',
    green: 'oklch(0.55 0.14 155)',
    greenSoft: 'oklch(0.93 0.05 155)',
    greenInk: 'oklch(0.38 0.12 155)',
    chip: 'rgba(20,18,14,0.05)',
    chipInk: 'rgba(20,18,14,0.72)',
    cardRadius: 18,
    cardStyle: 'soft', // soft | sharp | tinted | outline | paper
    typeWeight: 'normal', // normal | heavy
    surfaceShadow: '0 1px 2px rgba(0,0,0,0.025), 0 1px 0 rgba(255,255,255,0.5) inset',
  },
  dark: {
    name: 'dark',
    bg: '#0E0F12',
    bgGrad: 'linear-gradient(180deg, #14161A 0%, #0B0C0F 100%)',
    surface: '#1A1C20',
    surfaceAlt: '#22252A',
    border: 'rgba(255,255,255,0.08)',
    borderStrong: 'rgba(255,255,255,0.14)',
    text: '#F2F1ED',
    textMute: 'rgba(242,241,237,0.62)',
    textDim: 'rgba(242,241,237,0.38)',
    red: 'oklch(0.70 0.20 25)',
    redSoft: 'oklch(0.32 0.10 25)',
    redInk: 'oklch(0.85 0.12 25)',
    blue: 'oklch(0.70 0.16 255)',
    blueSoft: 'oklch(0.30 0.10 255)',
    blueInk: 'oklch(0.85 0.10 255)',
    green: 'oklch(0.72 0.14 155)',
    greenSoft: 'oklch(0.30 0.08 155)',
    greenInk: 'oklch(0.85 0.10 155)',
    chip: 'rgba(255,255,255,0.06)',
    chipInk: 'rgba(242,241,237,0.78)',
    cardRadius: 18,
    cardStyle: 'soft',
    typeWeight: 'normal',
    surfaceShadow: '0 1px 0 rgba(255,255,255,0.04) inset',
  },
};

const useTheme = (dark) => dark ? THEMES.dark : THEMES.light;

// ───── Visual variants (for exploration). All share the same components;
// they differ in tokens that Card / PhoneShell / tabs consult.

// 1. EDITORIAL — Saturday-magazine. Cream + oxblood + ink. Serif headlines.
THEMES.editorial = {
  ...THEMES.light,
  name: 'editorial',
  bg: '#F2EDE0',
  bgGrad: 'linear-gradient(180deg, #F5F0E3 0%, #EEE8D8 100%)',
  surface: '#FBF7EB',
  surfaceAlt: '#F5F0E0',
  border: 'rgba(40,25,15,0.14)',
  borderStrong: 'rgba(40,25,15,0.28)',
  text: '#1B0F08',
  textMute: 'rgba(27,15,8,0.65)',
  textDim: 'rgba(27,15,8,0.42)',
  red: 'oklch(0.42 0.16 28)',        // oxblood
  redSoft: 'oklch(0.90 0.05 28)',
  redInk: 'oklch(0.32 0.16 28)',
  blue: 'oklch(0.35 0.14 250)',       // ink navy
  blueSoft: 'oklch(0.90 0.04 250)',
  blueInk: 'oklch(0.25 0.14 250)',
  green: 'oklch(0.40 0.10 145)',
  greenSoft: 'oklch(0.90 0.04 145)',
  greenInk: 'oklch(0.30 0.10 145)',
  chip: 'rgba(40,25,15,0.06)',
  chipInk: 'rgba(27,15,8,0.78)',
  cardRadius: 4,
  cardStyle: 'editorial',
  fontDisplay: '"Newsreader", "Times New Roman", serif',
  surfaceShadow: 'none',
};

// 2. EUCALYPTUS — premium AU hospitality. Sage + sand + terracotta.
THEMES.eucalyptus = {
  ...THEMES.light,
  name: 'eucalyptus',
  bg: '#E8E4D2',
  bgGrad: 'linear-gradient(180deg, #EEEAD8 0%, #E2DEC8 100%)',
  surface: '#F5F2E4',
  surfaceAlt: '#EEEAD8',
  border: 'rgba(40,55,40,0.12)',
  borderStrong: 'rgba(40,55,40,0.22)',
  text: '#1F2A1F',
  textMute: 'rgba(31,42,31,0.62)',
  textDim: 'rgba(31,42,31,0.38)',
  red: 'oklch(0.55 0.16 38)',         // terracotta
  redSoft: 'oklch(0.90 0.06 38)',
  redInk: 'oklch(0.38 0.16 38)',
  blue: 'oklch(0.45 0.10 170)',       // eucalyptus
  blueSoft: 'oklch(0.88 0.05 170)',
  blueInk: 'oklch(0.32 0.12 170)',
  green: 'oklch(0.45 0.08 145)',
  greenSoft: 'oklch(0.88 0.05 145)',
  greenInk: 'oklch(0.32 0.10 145)',
  chip: 'rgba(40,55,40,0.06)',
  chipInk: 'rgba(31,42,31,0.78)',
  cardRadius: 20,
  cardStyle: 'soft',
  surfaceShadow: '0 1px 0 rgba(255,255,255,0.5) inset, 0 2px 6px rgba(40,55,40,0.04)',
};

// 3. KANBAN — uses default warm-paper colors but a different LAYOUT
//    (handled at the screen level — see screen-kanban.jsx)
THEMES.kanban = {
  ...THEMES.light,
  name: 'kanban',
  layout: 'kanban',
  bg: '#EFEBE2',
  bgGrad: 'linear-gradient(180deg, #F3EFE6 0%, #EAE6DC 100%)',
  surface: '#FCFAF4',
  cardRadius: 14,
  cardStyle: 'soft',
};

// 4. INDEX STACK — focused single-card view. Mid-century + cherry.
THEMES.stack = {
  ...THEMES.light,
  name: 'stack',
  layout: 'stack',
  bg: '#1A1E26',                       // outer goes dark to make card pop
  bgGrad: 'linear-gradient(180deg, #1F242E 0%, #131720 100%)',
  surface: '#F6F2EA',                  // the card stays creamy
  surfaceAlt: '#EFEAE0',
  border: 'rgba(30,20,15,0.10)',
  borderStrong: 'rgba(30,20,15,0.20)',
  text: '#1A120B',
  textMute: 'rgba(26,18,11,0.60)',
  textDim: 'rgba(26,18,11,0.38)',
  red: 'oklch(0.55 0.20 22)',          // cherry
  redSoft: 'oklch(0.92 0.06 22)',
  redInk: 'oklch(0.38 0.20 22)',
  blue: 'oklch(0.42 0.14 250)',
  blueSoft: 'oklch(0.92 0.04 250)',
  blueInk: 'oklch(0.30 0.16 250)',
  chip: 'rgba(30,20,15,0.06)',
  chipInk: 'rgba(26,18,11,0.78)',
  cardRadius: 22,
  cardStyle: 'soft',
  // text on the dark outer
  shellText: '#FFFFFF',
  shellMute: 'rgba(255,255,255,0.62)',
};

// 5. TACTICAL — true-black HUD. Electric green / cyan.
THEMES.tactical = {
  ...THEMES.dark,
  name: 'tactical',
  bg: '#000000',
  bgGrad: 'linear-gradient(180deg, #050505 0%, #000 100%)',
  surface: '#0A0C0A',
  surfaceAlt: '#0F1410',
  border: 'rgba(120,255,170,0.14)',
  borderStrong: 'rgba(120,255,170,0.30)',
  text: '#E8FFE8',
  textMute: 'rgba(232,255,232,0.62)',
  textDim: 'rgba(232,255,232,0.38)',
  red: 'oklch(0.74 0.22 25)',
  redSoft: 'oklch(0.22 0.14 25)',
  redInk: 'oklch(0.88 0.16 25)',
  blue: 'oklch(0.85 0.18 165)',         // signal green primary "blue" slot
  blueSoft: 'oklch(0.22 0.14 165)',
  blueInk: 'oklch(0.90 0.20 165)',
  green: 'oklch(0.85 0.18 165)',
  greenSoft: 'oklch(0.22 0.10 165)',
  greenInk: 'oklch(0.90 0.20 165)',
  chip: 'rgba(120,255,170,0.07)',
  chipInk: 'rgba(232,255,232,0.84)',
  cardRadius: 6,
  cardStyle: 'sharp',
  fontDisplay: '"JetBrains Mono", ui-monospace, monospace',
  surfaceShadow: '0 0 0 0.5px rgba(120,255,170,0.1) inset',
};

window.THEMES = THEMES;

// 6. MIDNIGHT — pure black + electric indigo (CustomerShip-style).
//    Soft purple light-beam glow from the top of the phone, vivid indigo primary,
//    subtle gradient-fade on display titles.
THEMES.midnight = {
  ...THEMES.dark,
  name: 'midnight',
  bg: '#000000',
  bgGrad: 'linear-gradient(180deg, #050507 0%, #000 100%)',
  // a separate beam overlay PhoneShell will render on top of the bg
  beam: true,
  surface: '#0F0F14',
  surfaceAlt: '#16161D',
  border: 'rgba(255,255,255,0.07)',
  borderStrong: 'rgba(255,255,255,0.14)',
  text: '#FFFFFF',
  textMute: 'rgba(255,255,255,0.62)',
  textDim: 'rgba(255,255,255,0.38)',
  red: 'oklch(0.66 0.22 25)',
  redSoft: 'oklch(0.30 0.14 25)',
  redInk: 'oklch(0.85 0.16 25)',
  // PRIMARY accent: electric indigo
  blue: 'oklch(0.60 0.22 275)',
  blueSoft: 'oklch(0.32 0.14 275)',
  blueInk: 'oklch(0.85 0.16 275)',
  green: 'oklch(0.72 0.16 155)',
  greenSoft: 'oklch(0.28 0.10 155)',
  greenInk: 'oklch(0.85 0.14 155)',
  chip: 'rgba(255,255,255,0.06)',
  chipInk: 'rgba(255,255,255,0.80)',
  cardRadius: 14,
  cardStyle: 'soft',
  surfaceShadow: '0 1px 0 rgba(255,255,255,0.04) inset',
  // accent color used for primary CTA gradients
  accentGrad: 'linear-gradient(180deg, #6A6BFF 0%, #4F50E8 100%)',
  accentSolid: '#5C5DEF',
  // title fade effect — first chars dimmer
  titleFade: true,
};
window.useTheme = useTheme;

// ─────────────────────────────────────────────────────────────
// StatusPill — Alex's red/blue/neutral code, one-tap.
// ─────────────────────────────────────────────────────────────
function StatusDot({ status, theme, size = 10 }) {
  const c = status === 'red' ? theme.red : status === 'blue' ? theme.blue : theme.textDim;
  return <span style={{
    display: 'inline-block', width: size, height: size, borderRadius: 99,
    background: c, flexShrink: 0,
  }} />;
}

function StatusPill({ status, theme, label, onClick }) {
  const map = {
    red:     { bg: theme.redSoft, ink: theme.redInk,   dot: theme.red },
    blue:    { bg: theme.blueSoft, ink: theme.blueInk, dot: theme.blue },
    neutral: { bg: theme.chip, ink: theme.chipInk,     dot: theme.textDim },
  };
  const s = map[status] || map.neutral;
  return (
    <button onClick={onClick} style={{
      display: 'inline-flex', alignItems: 'center', gap: 6,
      padding: '5px 10px 5px 8px', borderRadius: 99,
      background: s.bg, color: s.ink, border: 'none',
      fontSize: 12, fontWeight: 600, letterSpacing: -0.1,
      fontFamily: 'inherit', cursor: 'pointer', whiteSpace: 'nowrap',
    }}>
      <span style={{
        display: 'inline-block', width: 7, height: 7, borderRadius: 99,
        background: s.dot,
      }} />
      {label}
    </button>
  );
}

// Status toggle bar — appears inside customer card. Tap to set status.
function StatusToggle({ status, onChange, theme }) {
  const opts = [
    { key: 'red', label: 'Flag', desc: 'No-show / lost / important' },
    { key: 'blue', label: 'Set', desc: 'Callback / next step set' },
    { key: 'neutral', label: 'Note', desc: 'Plain note' },
  ];
  return (
    <div style={{
      display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: 6,
      padding: 4, borderRadius: 14, background: theme.chip,
    }}>
      {opts.map(o => {
        const active = status === o.key;
        const c = o.key === 'red' ? theme.red : o.key === 'blue' ? theme.blue : theme.text;
        return (
          <button key={o.key} onClick={() => onChange(o.key)} style={{
            border: 'none', borderRadius: 11, padding: '8px 4px',
            background: active ? theme.surface : 'transparent',
            color: active ? c : theme.textMute,
            fontFamily: 'inherit', fontSize: 13, fontWeight: 600,
            display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 6,
            cursor: 'pointer', letterSpacing: -0.1,
            boxShadow: active ? '0 1px 3px rgba(0,0,0,0.08)' : 'none',
            transition: 'all 0.15s ease',
          }}>
            <span style={{
              width: 8, height: 8, borderRadius: 99,
              background: o.key === 'red' ? theme.red : o.key === 'blue' ? theme.blue : theme.textDim,
            }} />
            {o.label}
          </button>
        );
      })}
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// Card — base surface element.
// ─────────────────────────────────────────────────────────────
function Card({ children, theme, style, onClick, status, density = 'regular' }) {
  const pad = density === 'compact' ? '12px 14px' : '14px 16px';
  const accent = status === 'red' ? theme.red : status === 'blue' ? theme.blue : null;
  const cs = theme.cardStyle || 'soft';
  const radius = theme.cardRadius ?? 18;

  // Style presets per variant.
  let surface = theme.surface;
  let border = `0.5px solid ${theme.border}`;
  let shadow = theme.surfaceShadow || '0 1px 2px rgba(0,0,0,0.025), 0 1px 0 rgba(255,255,255,0.5) inset';

  if (cs === 'outline') {
    surface = theme.surface;
    border = `1px solid ${theme.borderStrong}`;
    shadow = 'none';
  } else if (cs === 'sharp') {
    surface = theme.surfaceAlt;
    border = `0.5px solid ${theme.border}`;
    shadow = 'none';
  } else if (cs === 'paper') {
    surface = theme.surface;
    border = `0.5px solid ${theme.border}`;
    shadow = theme.surfaceShadow;
  } else if (cs === 'tinted' && status === 'red') {
    surface = theme.redSoft;
    border = `0.5px solid ${theme.red}33`;
  } else if (cs === 'tinted' && status === 'blue') {
    surface = theme.blueSoft;
    border = `0.5px solid ${theme.blue}33`;
  } else if (cs === 'editorial') {
    // newsprint classified — no rounded corners, hairline rule on top
    surface = theme.surface;
    border = `0.5px solid ${theme.borderStrong}`;
    shadow = 'none';
  }

  return (
    <div onClick={onClick} style={{
      background: surface, borderRadius: radius,
      padding: pad, position: 'relative', overflow: 'hidden',
      border, boxShadow: shadow,
      cursor: onClick ? 'pointer' : 'default',
      ...style,
    }}>
      {accent && cs !== 'tinted' && <div style={{
        position: 'absolute', left: 0, top: 10, bottom: 10,
        width: cs === 'outline' ? 4 : 3,
        background: accent, borderRadius: 99,
      }} />}
      {children}
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// SectionHeader — Alex skims these.
// ─────────────────────────────────────────────────────────────
function SectionHeader({ title, theme, count, action, actionLabel, kicker, icon }) {
  return (
    <div style={{
      display: 'flex', alignItems: 'baseline', justifyContent: 'space-between',
      padding: '0 4px 8px',
    }}>
      <div style={{ display: 'flex', alignItems: 'baseline', gap: 8 }}>
        {kicker && <span style={{
          fontSize: 11, fontWeight: 700, letterSpacing: 1, textTransform: 'uppercase',
          color: theme.textMute,
        }}>{kicker}</span>}
        <span style={{
          fontSize: 17, fontWeight: 700, color: theme.text, letterSpacing: -0.3,
        }}>{title}</span>
        {count !== undefined && <span style={{
          fontSize: 14, fontWeight: 500, color: theme.textDim, letterSpacing: -0.1,
        }}>{count}</span>}
      </div>
      {action && <button onClick={action} style={{
        border: 'none', background: 'transparent', color: theme.blue,
        fontFamily: 'inherit', fontSize: 14, fontWeight: 600, padding: 0,
        cursor: 'pointer',
      }}>{actionLabel || 'See all'}</button>}
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// PhoneShell — wraps the iOS frame + scrollable body. 390 wide.
// We're not using the IOSDevice nav bar; we render our own.
// ─────────────────────────────────────────────────────────────
function PhoneShell({ children, theme, dark, hideHomeIndicator = false }) {
  const W = 430, H = 932;
  const isNotebook = theme.name === 'notebook';
  return (
    <div style={{
      width: W, height: H, borderRadius: 48, overflow: 'hidden', position: 'relative',
      background: isNotebook ? theme.bgBase : theme.bgGrad,
      backgroundImage: isNotebook ? `${theme.bgGrad}` : undefined,
      backgroundSize: isNotebook ? theme.bgGradSize : undefined,
      boxShadow: '0 30px 80px rgba(0,0,0,0.18), 0 0 0 1px rgba(0,0,0,0.12), 0 0 0 12px #111 inset',
      fontFamily: '-apple-system, "SF Pro Text", system-ui, sans-serif',
      WebkitFontSmoothing: 'antialiased',
      color: theme.text,
    }}>
      {/* light beam (midnight theme) */}
      {theme.beam && (
        <React.Fragment>
          <div style={{
            position: 'absolute', top: 0, left: 0, right: 0, height: 380, zIndex: 1,
            pointerEvents: 'none',
            background:
              'radial-gradient(ellipse 60% 70% at 50% -10%, rgba(120,108,255,0.55) 0%, rgba(80,70,220,0.18) 35%, transparent 70%)',
          }}/>
          <div style={{
            position: 'absolute', top: -20, left: '20%', width: 280, height: 460, zIndex: 1,
            pointerEvents: 'none',
            background: 'linear-gradient(165deg, rgba(150,140,255,0.22), transparent 60%)',
            transform: 'rotate(15deg)', filter: 'blur(40px)',
          }}/>
          <div style={{
            position: 'absolute', top: -10, left: '8%', width: 80, height: 480, zIndex: 1,
            pointerEvents: 'none',
            background: 'linear-gradient(180deg, rgba(180,170,255,0.18), transparent 70%)',
            transform: 'rotate(20deg) skewX(-10deg)', filter: 'blur(20px)',
          }}/>
        </React.Fragment>
      )}
      {/* dynamic island */}
      <div style={{
        position: 'absolute', top: 11, left: '50%', transform: 'translateX(-50%)',
        width: 126, height: 37, borderRadius: 24, background: '#000', zIndex: 50,
      }} />
      {/* status bar */}
      <div style={{ position: 'absolute', top: 0, left: 0, right: 0, zIndex: 20 }}>
        <IOSStatusBar dark={dark} />
      </div>
      {/* content */}
      <div style={{
        position: 'absolute', inset: 0, paddingTop: 0,
        display: 'flex', flexDirection: 'column', zIndex: 5,
      }}>
        {children}
      </div>
      {/* home indicator */}
      {!hideHomeIndicator && <div style={{
        position: 'absolute', bottom: 0, left: 0, right: 0, zIndex: 60,
        height: 34, display: 'flex', justifyContent: 'center', alignItems: 'flex-end',
        paddingBottom: 8, pointerEvents: 'none',
      }}>
        <div style={{
          width: 139, height: 5, borderRadius: 100,
          background: dark ? 'rgba(255,255,255,0.7)' : 'rgba(0,0,0,0.28)',
        }} />
      </div>}
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// TopBar — appears below status bar, holds back/title/action.
// ─────────────────────────────────────────────────────────────
function TopBar({ theme, title, kicker, onBack, trailing, large = false }) {
  const hasTopRow = onBack || trailing || (!large && title);
  return (
    <div data-topbar style={{
      padding: '60px 18px 8px', flexShrink: 0,
    }}>
      {hasTopRow && (
        <div style={{
          display: 'flex', alignItems: 'center', justifyContent: 'space-between',
          minHeight: 36,
        }}>
          {onBack ? (
            <button onClick={onBack} style={{
              border: 'none', background: 'transparent', padding: '6px 8px 6px 0',
              color: theme.blue, display: 'flex', alignItems: 'center', gap: 2,
              fontFamily: 'inherit', fontSize: 17, fontWeight: 500, cursor: 'pointer',
              letterSpacing: -0.2,
            }}>
              <Icon name="chevron-left" size={22} stroke={2.2}/>
              <span style={{ marginLeft: -2 }}>Back</span>
            </button>
          ) : <div style={{ width: 1 }} />}
          {!large && title && <div style={{
            position: 'absolute', left: 0, right: 0, textAlign: 'center',
            fontWeight: 600, fontSize: 16, color: theme.text, pointerEvents: 'none',
            letterSpacing: -0.2,
          }}>{title}</div>}
          <div style={{ display: 'flex', gap: 4 }}>{trailing}</div>
        </div>
      )}
      {large && (
        <div style={{ paddingTop: hasTopRow ? 10 : 0 }}>
          {kicker && <div style={{
            fontSize: 13, fontWeight: 500, color: theme.textMute, letterSpacing: -0.1,
            fontFamily: theme.fontDisplay && theme.name === 'tactical' ? theme.fontDisplay : 'inherit',
          }}>{kicker}</div>}
          <div style={{
            fontSize: theme.name === 'editorial' ? 36 : 32,
            fontWeight: theme.name === 'editorial' ? 600 : 700,
            color: theme.text,
            letterSpacing: theme.name === 'editorial' ? -1.2 : -0.6,
            lineHeight: theme.name === 'editorial' ? '38px' : '36px',
            fontFamily: theme.fontDisplay || 'inherit',
            fontStyle: theme.name === 'editorial' ? 'italic' : 'normal',
            ...(theme.titleFade ? {
              background: `linear-gradient(95deg, rgba(255,255,255,0.45) 0%, rgba(255,255,255,0.85) 18%, #FFFFFF 35%)`,
              WebkitBackgroundClip: 'text', backgroundClip: 'text',
              WebkitTextFillColor: 'transparent', color: 'transparent',
            } : {}),
          }}>{title}</div>
        </div>
      )}
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// BottomTabBar — primary nav.
// ─────────────────────────────────────────────────────────────
function BottomTabBar({ tab, setTab, onAdd, theme, dark }) {
  const tabs = [
    { key: 'today',     icon: 'sun',      label: 'Today' },
    { key: 'pipeline',  icon: 'pipeline', label: 'Pipeline' },
    { key: 'add',       icon: 'plus',     label: '', isPlus: true },
    { key: 'nurturing', icon: 'sprout',   label: 'Nurturing' },
    { key: 'reminders', icon: 'bell',     label: 'Reminders' },
  ];
  return (
    <div style={{
      position: 'relative', flexShrink: 0,
      padding: '8px 14px 28px',
      background: dark
        ? 'linear-gradient(180deg, rgba(14,15,18,0) 0%, rgba(14,15,18,0.92) 40%)'
        : 'linear-gradient(180deg, rgba(244,242,238,0) 0%, rgba(244,242,238,0.92) 40%)',
      backdropFilter: 'blur(20px)', WebkitBackdropFilter: 'blur(20px)',
    }}>
      <div style={{
        display: 'grid', gridTemplateColumns: 'repeat(5, 1fr)',
        background: theme.surface, borderRadius: 22,
        padding: '6px 4px',
        border: `0.5px solid ${theme.border}`,
        boxShadow: '0 6px 20px rgba(0,0,0,0.08), 0 1px 0 rgba(255,255,255,0.5) inset',
      }}>
        {tabs.map(t => {
          const active = tab === t.key;
          if (t.isPlus) {
            return (
              <button key={t.key} onClick={onAdd} style={{
                border: 'none', background: 'transparent', padding: 4,
                display: 'flex', alignItems: 'center', justifyContent: 'center',
                cursor: 'pointer',
              }}>
                <span style={{
                  width: 44, height: 44, borderRadius: 14,
                  background: theme.accentGrad || theme.text,
                  color: theme.accentGrad ? '#fff' : theme.bg,
                  display: 'flex', alignItems: 'center', justifyContent: 'center',
                  boxShadow: theme.accentGrad
                    ? '0 8px 20px rgba(95,90,240,0.45), 0 1px 0 rgba(255,255,255,0.25) inset'
                    : '0 4px 12px rgba(0,0,0,0.18)',
                }}>
                  <Icon name="plus" size={22} stroke={2.4}/>
                </span>
              </button>
            );
          }
          return (
            <button key={t.key} onClick={() => setTab(t.key)} style={{
              border: 'none', background: 'transparent',
              padding: '6px 0 4px',
              display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 2,
              cursor: 'pointer', color: active ? theme.text : theme.textDim,
              fontFamily: 'inherit',
            }}>
              <Icon name={t.icon} size={22} stroke={active ? 2 : 1.7}/>
              <span style={{ fontSize: 10, fontWeight: 600, letterSpacing: 0.1 }}>{t.label}</span>
            </button>
          );
        })}
      </div>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// ScrollBody — scrollable area between TopBar and BottomTabBar
// ─────────────────────────────────────────────────────────────
function ScrollBody({ children, style }) {
  return (
    <div style={{
      flex: 1, overflowY: 'auto', overflowX: 'hidden',
      padding: '4px 16px 12px', WebkitOverflowScrolling: 'touch',
      ...style,
    }}>{children}</div>
  );
}

// Avatar — initial-based, color-hashed.
function Avatar({ name, theme, size = 38 }) {
  const initials = name.split(' ').map(p => p[0]).slice(0, 2).join('');
  // hash hue from name
  let h = 0;
  for (let i = 0; i < name.length; i++) h = (h * 31 + name.charCodeAt(i)) % 360;
  const bg = `oklch(0.88 0.04 ${h})`;
  const ink = `oklch(0.40 0.06 ${h})`;
  return (
    <div style={{
      width: size, height: size, borderRadius: 99,
      background: bg, color: ink,
      display: 'flex', alignItems: 'center', justifyContent: 'center',
      fontSize: size * 0.38, fontWeight: 600, letterSpacing: -0.2, flexShrink: 0,
    }}>{initials}</div>
  );
}

// Small inline chip
function Chip({ children, theme, tone = 'neutral', icon }) {
  const tones = {
    neutral: { bg: theme.chip, ink: theme.chipInk },
    red:     { bg: theme.redSoft, ink: theme.redInk },
    blue:    { bg: theme.blueSoft, ink: theme.blueInk },
    green:   { bg: theme.greenSoft, ink: theme.greenInk },
  };
  const c = tones[tone];
  return (
    <span style={{
      display: 'inline-flex', alignItems: 'center', gap: 4,
      padding: '4px 9px', borderRadius: 99,
      background: c.bg, color: c.ink,
      fontSize: 11.5, fontWeight: 600, letterSpacing: -0.05,
      whiteSpace: 'nowrap',
    }}>
      {icon && <Icon name={icon} size={12} stroke={2.2}/>}
      {children}
    </span>
  );
}

Object.assign(window, {
  StatusDot, StatusPill, StatusToggle, Card, SectionHeader,
  PhoneShell, TopBar, BottomTabBar, ScrollBody, Avatar, Chip,
});
