// Towbook Android — core component library
// Material 3 conventions, Towbook tokens. All components are self-contained, no external deps beyond
// React and the global I (icons) / TBT (tokens) helpers.

const { useState: useStateC, useEffect: useEffectC, useRef: useRefC } = React;

// ─────── Buttons ──────────────────────────────────────────────
// Variants: filled, tonal, outlined, text, destructive
// Sizes:   sm | md | lg
function TBButton({
  variant = 'filled', size = 'md', icon, trailingIcon,
  children, onClick, disabled, fullWidth, style,
}) {
  const [pressed, setPressed] = useStateC(false);
  const [hover, setHover] = useStateC(false);
  const h = size === 'sm' ? 36 : size === 'lg' ? 52 : 44;
  const padX = size === 'sm' ? 14 : size === 'lg' ? 24 : 18;
  const fs = size === 'sm' ? 13 : size === 'lg' ? 16 : 14;
  const iconSize = size === 'lg' ? 20 : 18;

  const palettes = {
    filled: {
      bg: pressed ? 'var(--tb-primary-press)' : (hover ? 'var(--tb-primary-hover)' : 'var(--tb-primary)'),
      fg: 'white',
      border: 'transparent',
      shadow: '0 1px 2px rgba(7,113,242,0.20)',
    },
    tonal: {
      bg: pressed ? 'var(--blue-5)' : (hover ? 'var(--blue-4)' : 'var(--blue-3)'),
      fg: 'var(--blue-11)',
      border: 'transparent',
      shadow: 'none',
    },
    outlined: {
      bg: pressed ? 'var(--slate-3)' : (hover ? 'var(--slate-2)' : 'transparent'),
      fg: 'var(--tb-on-surface)',
      border: 'var(--tb-border-strong)',
      shadow: 'none',
    },
    text: {
      bg: pressed ? 'var(--blue-a4)' : (hover ? 'var(--blue-a3)' : 'transparent'),
      fg: 'var(--blue-11)',
      border: 'transparent',
      shadow: 'none',
    },
    destructive: {
      bg: pressed ? 'var(--red-10)' : (hover ? 'var(--red-9)' : 'var(--red-9)'),
      fg: 'white',
      border: 'transparent',
      shadow: '0 1px 2px rgba(220,62,66,0.20)',
    },
  };
  const p = palettes[variant];

  return (
    <button
      onClick={disabled ? undefined : onClick}
      disabled={disabled}
      onMouseEnter={() => setHover(true)}
      onMouseLeave={() => { setHover(false); setPressed(false); }}
      onMouseDown={() => setPressed(true)}
      onMouseUp={() => setPressed(false)}
      style={{
        height: h,
        padding: `0 ${padX}px`,
        background: disabled ? 'var(--slate-3)' : p.bg,
        color: disabled ? 'var(--slate-9)' : p.fg,
        border: `1px solid ${disabled ? 'transparent' : p.border}`,
        borderRadius: 'var(--tb-r-button)',
        fontFamily: 'var(--font-sans)',
        fontSize: fs, fontWeight: 600, letterSpacing: '0.005em',
        display: 'inline-flex', alignItems: 'center', justifyContent: 'center', gap: 8,
        cursor: disabled ? 'not-allowed' : 'pointer',
        boxShadow: disabled ? 'none' : p.shadow,
        width: fullWidth ? '100%' : 'auto',
        transition: 'background 120ms var(--ease-in), box-shadow 120ms var(--ease-in)',
        whiteSpace: 'nowrap',
        ...style,
      }}>
      {icon ? React.createElement(icon, { size: iconSize }) : null}
      {children}
      {trailingIcon ? React.createElement(trailingIcon, { size: iconSize }) : null}
    </button>
  );
}

// FAB — floating action button. Variants: regular, extended (with label), small.
function TBFab({ icon = I.Plus, label, size = 'regular', onClick, color = 'primary', style }) {
  const [pressed, setPressed] = useStateC(false);
  const dim = size === 'small' ? 40 : 56;
  const iconSize = size === 'small' ? 20 : 24;
  const isExtended = !!label;

  const palette = color === 'primary'
    ? { bg: 'var(--tb-primary)', fg: 'white' }
    : color === 'tonal'
    ? { bg: 'var(--blue-3)', fg: 'var(--blue-11)' }
    : { bg: 'var(--tb-surface)', fg: 'var(--blue-11)' };

  return (
    <button
      onClick={onClick}
      onMouseDown={() => setPressed(true)}
      onMouseUp={() => setPressed(false)}
      onMouseLeave={() => setPressed(false)}
      style={{
        height: dim,
        width: isExtended ? undefined : dim,
        minWidth: isExtended ? 80 : dim,
        padding: isExtended ? '0 20px 0 16px' : 0,
        borderRadius: isExtended ? 16 : (dim/2),
        background: palette.bg,
        color: palette.fg,
        border: 0,
        boxShadow: pressed
          ? '0 2px 4px rgba(7,113,242,0.22)'
          : 'var(--tb-elev-fab)',
        display: 'inline-flex', alignItems: 'center', justifyContent: 'center', gap: 10,
        fontFamily: 'var(--font-sans)', fontSize: 15, fontWeight: 600,
        cursor: 'pointer',
        transform: pressed ? 'translateY(1px)' : 'none',
        transition: 'transform 80ms var(--ease-in), box-shadow 120ms var(--ease-in)',
        ...style,
      }}>
      {React.createElement(icon, { size: iconSize })}
      {label}
    </button>
  );
}

// ─────── Inputs ──────────────────────────────────────────────
// Outlined text field (M3) with floating label, supporting + error states.
function TBTextField({
  label, value, onChange, placeholder,
  leadingIcon, trailingIcon, supporting, error,
  type = 'text', disabled, fullWidth = true,
  multiline, rows = 4,
}) {
  const [focused, setFocused] = useStateC(false);
  const filled = (value !== undefined && value !== '') || focused;
  const borderColor = error
    ? 'var(--red-9)'
    : focused
      ? 'var(--tb-primary)'
      : 'var(--tb-border-strong)';
  const labelColor = error
    ? 'var(--red-11)'
    : focused
      ? 'var(--blue-11)'
      : 'var(--tb-on-surface-muted)';

  const input = multiline ? (
    <textarea
      rows={rows}
      value={value || ''}
      onChange={e => onChange?.(e.target.value)}
      onFocus={() => setFocused(true)} onBlur={() => setFocused(false)}
      disabled={disabled}
      placeholder={focused ? placeholder : ''}
      style={{
        width: '100%', resize: 'none',
        background: 'transparent', border: 0, outline: 'none',
        fontFamily: 'var(--font-sans)', fontSize: 15, color: 'var(--tb-on-surface)',
        padding: 0,
      }}/>
  ) : (
    <input
      type={type} value={value || ''}
      onChange={e => onChange?.(e.target.value)}
      onFocus={() => setFocused(true)} onBlur={() => setFocused(false)}
      disabled={disabled}
      placeholder={focused ? placeholder : ''}
      style={{
        width: '100%', height: 24,
        background: 'transparent', border: 0, outline: 'none',
        fontFamily: 'var(--font-sans)', fontSize: 15, color: 'var(--tb-on-surface)',
      }}/>
  );

  return (
    <div style={{ width: fullWidth ? '100%' : 'auto', opacity: disabled ? 0.5 : 1 }}>
      <div style={{
        position: 'relative',
        border: `${focused || error ? 2 : 1}px solid ${borderColor}`,
        borderRadius: 'var(--tb-r-input)',
        padding: '0 14px',
        minHeight: multiline ? undefined : 56,
        display: 'flex', alignItems: multiline ? 'flex-start' : 'center', gap: 12,
        transition: 'border-color 120ms var(--ease-in)',
        background: 'var(--tb-surface)',
      }}>
        {leadingIcon && <div style={{ color: 'var(--tb-on-surface-muted)', display: 'flex', paddingTop: multiline ? 18 : 0 }}>{React.createElement(leadingIcon, { size: 20 })}</div>}
        <div style={{ flex: 1, paddingTop: filled ? 18 : 0, paddingBottom: multiline ? 14 : 0, position: 'relative' }}>
          {label && (
            <span style={{
              position: 'absolute',
              top: filled ? -7 : '50%',
              left: 0,
              transform: filled ? 'none' : 'translateY(-50%)',
              fontSize: filled ? 12 : 15,
              fontWeight: filled ? 500 : 400,
              color: labelColor,
              background: filled ? 'var(--tb-surface)' : 'transparent',
              padding: filled ? '0 4px' : 0,
              marginLeft: filled ? -4 : 0,
              pointerEvents: 'none',
              transition: 'all 120ms var(--ease-in)',
            }}>{label}</span>
          )}
          {input}
        </div>
        {trailingIcon && <div style={{ color: 'var(--tb-on-surface-muted)', display: 'flex' }}>{React.createElement(trailingIcon, { size: 20 })}</div>}
      </div>
      {(supporting || error) && (
        <div style={{
          fontSize: 12, lineHeight: '16px',
          color: error ? 'var(--red-11)' : 'var(--tb-on-surface-muted)',
          padding: '4px 14px 0',
        }}>{error || supporting}</div>
      )}
    </div>
  );
}

// Switch (Material 3)
function TBSwitch({ checked, onChange, disabled }) {
  return (
    <button
      onClick={() => !disabled && onChange?.(!checked)}
      disabled={disabled}
      style={{
        width: 52, height: 32,
        padding: 2,
        borderRadius: 999,
        border: `2px solid ${checked ? 'var(--tb-primary)' : 'var(--tb-border-strong)'}`,
        background: checked ? 'var(--tb-primary)' : 'transparent',
        position: 'relative', cursor: disabled ? 'not-allowed' : 'pointer',
        transition: 'all 160ms var(--ease-in)',
        opacity: disabled ? 0.4 : 1,
      }}>
      <span style={{
        position: 'absolute',
        width: checked ? 22 : 16, height: checked ? 22 : 16,
        background: checked ? 'white' : 'var(--tb-on-surface-muted)',
        borderRadius: '50%',
        top: '50%',
        left: checked ? 26 : 6,
        transform: 'translateY(-50%)',
        transition: 'all 160ms var(--ease-in)',
      }}/>
    </button>
  );
}

// Checkbox
function TBCheckbox({ checked, onChange, indeterminate, disabled }) {
  return (
    <button
      onClick={() => !disabled && onChange?.(!checked)}
      disabled={disabled}
      style={{
        width: 20, height: 20,
        border: `2px solid ${checked || indeterminate ? 'var(--tb-primary)' : 'var(--tb-border-strong)'}`,
        background: checked || indeterminate ? 'var(--tb-primary)' : 'transparent',
        borderRadius: 3,
        display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
        cursor: disabled ? 'not-allowed' : 'pointer',
        padding: 0, color: 'white',
        opacity: disabled ? 0.4 : 1,
      }}>
      {checked && <I.Check size={14} strokeWidth={3}/>}
      {indeterminate && !checked && <span style={{ width: 10, height: 2, background: 'white' }}/>}
    </button>
  );
}

// Radio
function TBRadio({ checked, onChange, disabled }) {
  return (
    <button
      onClick={() => !disabled && onChange?.(true)}
      disabled={disabled}
      style={{
        width: 20, height: 20,
        border: `2px solid ${checked ? 'var(--tb-primary)' : 'var(--tb-border-strong)'}`,
        background: 'transparent',
        borderRadius: '50%',
        display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
        cursor: disabled ? 'not-allowed' : 'pointer',
        padding: 0,
        opacity: disabled ? 0.4 : 1,
      }}>
      {checked && <span style={{ width: 10, height: 10, background: 'var(--tb-primary)', borderRadius: '50%' }}/>}
    </button>
  );
}

// ─────── Cards / surfaces ────────────────────────────────────
function TBCard({ children, elevated, style, onClick, padding = 16 }) {
  const [hover, setHover] = useStateC(false);
  return (
    <div
      onClick={onClick}
      onMouseEnter={() => setHover(true)}
      onMouseLeave={() => setHover(false)}
      style={{
        background: 'var(--tb-surface)',
        borderRadius: 'var(--tb-r-card)',
        border: elevated ? 'none' : '1px solid var(--tb-border)',
        boxShadow: elevated
          ? (hover ? 'var(--tb-elev-2)' : 'var(--tb-elev-1)')
          : 'none',
        padding,
        cursor: onClick ? 'pointer' : 'default',
        transition: 'box-shadow 120ms var(--ease-in)',
        ...style,
      }}>
      {children}
    </div>
  );
}

// ─────── Chips ──────────────────────────────────────────────
// Variants: assist, filter (selected/unselected), input
function TBChip({ children, selected, onClick, leadingIcon, trailingIcon, variant = 'filter', onRemove }) {
  const [hover, setHover] = useStateC(false);
  const palette = variant === 'filter'
    ? selected
      ? { bg: 'var(--blue-3)', fg: 'var(--blue-11)', border: 'var(--tb-primary)' }
      : { bg: hover ? 'var(--slate-2)' : 'transparent', fg: 'var(--tb-on-surface)', border: 'var(--tb-border-strong)' }
    : variant === 'input'
      ? { bg: 'var(--slate-3)', fg: 'var(--tb-on-surface)', border: 'transparent' }
      : { bg: hover ? 'var(--slate-2)' : 'transparent', fg: 'var(--tb-on-surface)', border: 'var(--tb-border-strong)' };

  return (
    <button
      onClick={onClick}
      onMouseEnter={() => setHover(true)}
      onMouseLeave={() => setHover(false)}
      style={{
        height: 32, padding: '0 12px',
        background: palette.bg, color: palette.fg,
        border: `1px solid ${palette.border}`,
        borderRadius: 'var(--tb-r-chip)',
        fontFamily: 'var(--font-sans)', fontSize: 13, fontWeight: 500,
        display: 'inline-flex', alignItems: 'center', gap: 6,
        cursor: 'pointer',
      }}>
      {selected && variant === 'filter' && <I.Check size={16} strokeWidth={2.5}/>}
      {leadingIcon && React.createElement(leadingIcon, { size: 16 })}
      {children}
      {variant === 'input' && onRemove && (
        <span onClick={e => { e.stopPropagation(); onRemove(); }} style={{ display: 'inline-flex' }}>
          <I.X size={14}/>
        </span>
      )}
      {trailingIcon && React.createElement(trailingIcon, { size: 16 })}
    </button>
  );
}

// ─────── Tabs ──────────────────────────────────────────────
// Primary tabs (Material 3) — full-width or scrollable
function TBTabs({ items, value, onChange, variant = 'primary', scrollable }) {
  return (
    <div style={{
      display: 'flex',
      borderBottom: '1px solid var(--tb-divider)',
      background: variant === 'primary' ? 'var(--tb-primary)' : 'var(--tb-surface)',
      overflowX: scrollable ? 'auto' : 'hidden',
      flexShrink: 0,
    }}>
      {items.map((it) => {
        const isActive = it.value === value;
        const fg = variant === 'primary'
          ? (isActive ? 'white' : 'rgba(255,255,255,0.78)')
          : (isActive ? 'var(--tb-primary)' : 'var(--tb-on-surface-muted)');
        return (
          <button key={it.value}
            onClick={() => onChange?.(it.value)}
            style={{
              flex: scrollable ? '0 0 auto' : 1,
              minWidth: scrollable ? 100 : 0,
              height: 48,
              padding: '0 16px',
              border: 0, background: 'transparent',
              fontFamily: 'var(--font-sans)', fontSize: 13, fontWeight: 600,
              letterSpacing: '0.04em', textTransform: 'uppercase',
              color: fg,
              borderBottom: `3px solid ${isActive ? (variant === 'primary' ? 'white' : 'var(--tb-primary)') : 'transparent'}`,
              cursor: 'pointer',
              display: 'inline-flex', alignItems: 'center', justifyContent: 'center', gap: 6,
              transition: 'color 120ms var(--ease-in)',
            }}>
            {it.label}
            {it.count !== undefined && (
              <span style={{
                fontSize: 11, fontWeight: 700,
                padding: '1px 6px', borderRadius: 999,
                background: variant === 'primary' ? 'rgba(255,255,255,0.20)' : 'var(--slate-3)',
                color: variant === 'primary' ? 'white' : 'var(--tb-on-surface-muted)',
              }}>{it.count}</span>
            )}
          </button>
        );
      })}
    </div>
  );
}

// ─────── Sub nav (scrollable, blue underline) ──────────────
// Horizontal sub-navigation that overflows the viewport. Selected item shows
// brand-blue text + 2px underline. Sliding arrows appear when content overflows
// and scroll the strip 70% of the visible width per click.
function TBSubNav({ items, value, onChange, sticky = true }) {
  const trackRef = useRefC(null);
  const [overflowL, setOverflowL] = useStateC(false);
  const [overflowR, setOverflowR] = useStateC(false);

  const recalc = () => {
    const el = trackRef.current;
    if (!el) return;
    setOverflowL(el.scrollLeft > 4);
    setOverflowR(el.scrollLeft + el.clientWidth < el.scrollWidth - 4);
  };

  useEffectC(() => {
    const el = trackRef.current;
    if (!el) return;
    recalc();
    el.addEventListener('scroll', recalc, { passive: true });
    const ro = new ResizeObserver(recalc);
    ro.observe(el);
    return () => { el.removeEventListener('scroll', recalc); ro.disconnect(); };
  }, [items]);

  // Auto-scroll selected into view
  useEffectC(() => {
    const el = trackRef.current;
    if (!el) return;
    const sel = el.querySelector('[data-selected="true"]');
    if (sel) {
      const elRect = el.getBoundingClientRect();
      const selRect = sel.getBoundingClientRect();
      if (selRect.left < elRect.left + 24 || selRect.right > elRect.right - 24) {
        sel.scrollIntoView({ behavior: 'smooth', inline: 'center', block: 'nearest' });
      }
    }
  }, [value]);

  const slide = (dir) => {
    const el = trackRef.current;
    if (!el) return;
    el.scrollBy({ left: dir * el.clientWidth * 0.7, behavior: 'smooth' });
  };

  return (
    <div style={{
      position: 'relative',
      background: 'var(--tb-surface)',
      borderBottom: '1px solid var(--tb-divider)',
      flexShrink: 0,
    }}>
      <div
        ref={trackRef}
        style={{
          display: 'flex',
          overflowX: 'auto',
          scrollbarWidth: 'none',
          msOverflowStyle: 'none',
          WebkitOverflowScrolling: 'touch',
        }}
      >
        <style>{`.tb-subnav-track::-webkit-scrollbar{display:none}`}</style>
        {items.map((it) => {
          const isActive = it.value === value;
          return (
            <button key={it.value}
              data-selected={isActive}
              onClick={() => onChange?.(it.value)}
              style={{
                flex: '0 0 auto',
                height: 44,
                padding: '0 16px',
                border: 0, background: 'transparent',
                fontFamily: 'var(--font-sans)',
                fontSize: 14,
                fontWeight: isActive ? 600 : 500,
                color: isActive ? 'var(--tb-primary)' : 'var(--tb-on-surface-muted)',
                position: 'relative',
                cursor: 'pointer',
                display: 'inline-flex', alignItems: 'center', gap: 6,
                whiteSpace: 'nowrap',
                transition: 'color 120ms var(--ease-in)',
              }}>
              {it.label}
              {it.count !== undefined && (
                <span style={{
                  fontSize: 11, fontWeight: 700,
                  padding: '1px 6px', borderRadius: 999,
                  background: isActive ? 'var(--blue-3)' : 'var(--slate-3)',
                  color: isActive ? 'var(--blue-11)' : 'var(--tb-on-surface-muted)',
                }}>{it.count}</span>
              )}
              <span style={{
                position: 'absolute', left: 12, right: 12, bottom: 0, height: 2,
                background: isActive ? 'var(--tb-primary)' : 'transparent',
                borderRadius: '2px 2px 0 0',
                transition: 'background 120ms var(--ease-in)',
              }}/>
            </button>
          );
        })}
      </div>

      {/* Edge fades — visual hint that more content is available */}
      {overflowL && (
        <div style={{
          position: 'absolute', left: 0, top: 0, bottom: 1, width: 24,
          background: 'linear-gradient(to right, var(--tb-surface), transparent)',
          pointerEvents: 'none',
        }}/>
      )}
      {overflowR && (
        <div style={{
          position: 'absolute', right: 0, top: 0, bottom: 1, width: 24,
          background: 'linear-gradient(to left, var(--tb-surface), transparent)',
          pointerEvents: 'none',
        }}/>
      )}
    </div>
  );
}

// ─────── List item ──────────────────────────────────────────
function TBListItem({ leading, headline, supporting, trailing, onClick, divider = true, twoLine }) {
  const [pressed, setPressed] = useStateC(false);
  return (
    <div
      onClick={onClick}
      onMouseDown={() => setPressed(true)}
      onMouseUp={() => setPressed(false)}
      onMouseLeave={() => setPressed(false)}
      style={{
        display: 'flex', alignItems: 'center', gap: 16,
        padding: '12px 16px',
        minHeight: twoLine ? 72 : 56,
        background: pressed ? 'var(--slate-3)' : 'transparent',
        cursor: onClick ? 'pointer' : 'default',
        borderBottom: divider ? '1px solid var(--tb-divider)' : 'none',
        transition: 'background 80ms var(--ease-in)',
      }}>
      {leading && <div style={{ flexShrink: 0, color: 'var(--tb-on-surface-muted)' }}>{leading}</div>}
      <div style={{ flex: 1, minWidth: 0 }}>
        <div style={{
          fontSize: 15, lineHeight: '20px', fontWeight: 500, color: 'var(--tb-on-surface)',
          overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap',
        }}>{headline}</div>
        {supporting && (
          <div style={{
            fontSize: 13, lineHeight: '18px', color: 'var(--tb-on-surface-muted)', marginTop: 2,
            overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap',
          }}>{supporting}</div>
        )}
      </div>
      {trailing && <div style={{ flexShrink: 0, color: 'var(--tb-on-surface-muted)' }}>{trailing}</div>}
    </div>
  );
}

// ─────── Dialog (alert) ─────────────────────────────────────
function TBDialog({ open, title, children, actions, icon, onDismiss }) {
  if (!open) return null;
  return (
    <div style={{
      position: 'absolute', inset: 0,
      background: 'rgba(15,17,21,0.55)',
      display: 'flex', alignItems: 'center', justifyContent: 'center',
      padding: 28,
      zIndex: 30,
      animation: 'tb-fade 160ms var(--ease-in)',
    }} onClick={onDismiss}>
      <div onClick={e => e.stopPropagation()} style={{
        background: 'var(--tb-surface)',
        borderRadius: 28,
        padding: 24,
        width: '100%', maxWidth: 312,
        boxShadow: 'var(--tb-elev-3)',
        animation: 'tb-scale 200ms var(--ease-in)',
        textAlign: icon ? 'center' : 'left',
      }}>
        {icon && (
          <div style={{
            display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
            width: 48, height: 48, borderRadius: '50%',
            background: 'var(--blue-3)', color: 'var(--blue-11)',
            margin: '0 auto 16px',
          }}>{React.createElement(icon, { size: 24 })}</div>
        )}
        <div style={{ fontSize: 22, fontWeight: 600, color: 'var(--tb-on-surface)', marginBottom: 12, letterSpacing: '-0.01em' }}>{title}</div>
        <div style={{ fontSize: 14, color: 'var(--tb-on-surface-muted)', lineHeight: '20px', marginBottom: 20 }}>{children}</div>
        <div style={{ display: 'flex', justifyContent: 'flex-end', gap: 8 }}>{actions}</div>
      </div>
    </div>
  );
}

// ─────── Bottom sheet ───────────────────────────────────────
function TBBottomSheet({ open, onDismiss, children, title, height }) {
  return (
    <div style={{
      position: 'absolute', inset: 0,
      background: open ? 'rgba(15,17,21,0.40)' : 'transparent',
      pointerEvents: open ? 'auto' : 'none',
      transition: 'background 200ms var(--ease-in)',
      zIndex: 25,
    }} onClick={onDismiss}>
      <div onClick={e => e.stopPropagation()} style={{
        position: 'absolute', left: 0, right: 0, bottom: 0,
        background: 'var(--tb-surface)',
        borderRadius: '28px 28px 0 0',
        boxShadow: 'var(--tb-elev-3)',
        padding: '12px 0 8px',
        transform: open ? 'translateY(0)' : 'translateY(100%)',
        transition: 'transform 240ms var(--ease-in)',
        maxHeight: height || '70%',
        display: 'flex', flexDirection: 'column',
      }}>
        <div style={{ display: 'flex', justifyContent: 'center', padding: '4px 0 8px' }}>
          <div style={{ width: 32, height: 4, borderRadius: 2, background: 'var(--tb-border-strong)' }}/>
        </div>
        {title && <div style={{ padding: '8px 24px 12px', fontSize: 16, fontWeight: 600 }}>{title}</div>}
        <div style={{ overflowY: 'auto' }}>{children}</div>
      </div>
    </div>
  );
}

// ─────── Snackbar ───────────────────────────────────────────
function TBSnackbar({ open, children, action, onDismiss }) {
  return (
    <div style={{
      position: 'absolute', bottom: 16, left: 16, right: 16,
      transform: open ? 'translateY(0)' : 'translateY(80px)',
      opacity: open ? 1 : 0,
      transition: 'all 200ms var(--ease-in)',
      pointerEvents: open ? 'auto' : 'none',
      zIndex: 28,
    }}>
      <div style={{
        background: 'var(--slate-12)',
        color: 'white',
        borderRadius: 8,
        padding: '14px 16px',
        boxShadow: 'var(--tb-elev-3)',
        display: 'flex', alignItems: 'center', gap: 12,
        fontSize: 14,
      }}>
        <div style={{ flex: 1 }}>{children}</div>
        {action && (
          <button onClick={action.onClick} style={{
            background: 'transparent', border: 0,
            color: '#8ec8f6', fontWeight: 600, fontSize: 13,
            cursor: 'pointer', textTransform: 'uppercase', letterSpacing: '0.04em',
          }}>{action.label}</button>
        )}
        {onDismiss && (
          <button onClick={onDismiss} style={{
            background: 'transparent', border: 0, color: 'rgba(255,255,255,0.7)',
            cursor: 'pointer', display: 'inline-flex', padding: 0,
          }}><I.X size={18}/></button>
        )}
      </div>
    </div>
  );
}

// ─────── Linear progress ────────────────────────────────────
function TBLinearProgress({ value, indeterminate }) {
  return (
    <div style={{
      height: 4, width: '100%',
      background: 'var(--blue-3)',
      borderRadius: 2, overflow: 'hidden',
      position: 'relative',
    }}>
      {indeterminate ? (
        <div style={{
          position: 'absolute', height: '100%', width: '40%',
          background: 'var(--tb-primary)',
          animation: 'tb-indeterminate 1.4s linear infinite',
        }}/>
      ) : (
        <div style={{
          height: '100%', width: `${value*100}%`,
          background: 'var(--tb-primary)',
          transition: 'width 200ms var(--ease-in)',
        }}/>
      )}
    </div>
  );
}

// Circular progress (used as pull-to-refresh + spinner)
function TBSpinner({ size = 24, strokeWidth = 3, color = 'var(--tb-primary)' }) {
  return (
    <svg width={size} height={size} viewBox="0 0 24 24" style={{ animation: 'tb-rotate 1s linear infinite' }}>
      <circle cx="12" cy="12" r="9" fill="none" stroke={color} strokeWidth={strokeWidth} strokeLinecap="round"
              strokeDasharray="40 60" />
    </svg>
  );
}

Object.assign(window, {
  TBButton, TBFab, TBTextField, TBSwitch, TBCheckbox, TBRadio,
  TBCard, TBChip, TBTabs, TBSubNav, TBListItem,
  TBDialog, TBBottomSheet, TBSnackbar,
  TBLinearProgress, TBSpinner,
});
