// KOVA · Components · Wave B
// Atoms · Molecules · Shell · Overlays · all React, all reading from primitives.css
// Exports onto window for cross-file use under the Babel-standalone setup.

const { useState, useEffect, useRef, useMemo, useCallback } = React;

/* ============================================================
   ICON — single ultra-minimal glyph set
   ============================================================ */
const ICONS = {
  home: '⌂', orbit: '◯', vault: '◇', price: '$', kraft: '✦',
  approvals: '✓', monitor: '⌕', connect: '⇄', admin: '⚙', wiki: '☷',
  search: '⌕', bell: '◌', cmd: '⌘', plus: '+', check: '✓', cross: '✕',
  chev: '›', chevDown: '⌄', dot: '•', arrow: '→', more: '⋯',
  lock: '⌹', drift: '⊘', book: '☷', filter: '⚲', sort: '⇅',
  external: '↗', refresh: '↻', play: '▸', pause: '◼',
  k: 'K',
  // VAULT v2 · capital-intelligence glyph set (ultra-minimal, no emoji)
  transfer: '⇄', reprice: '%', remake: '↻', hold: '‖', melt: '▽',
  globe: '◍', zap: '↯', target: '◎', trend: '↗', warning: '△',
  doc: '▤', clock: '◷', sliders: '⇳', layers: '≣', pin: '⌖',
  inbox: '⊞', x: '✕', check2: '✓',
};
const Icon = ({ name, size = 14, style }) => (
  <span style={{ fontSize: size, lineHeight: 1, display: 'inline-block', ...style }}>
    {ICONS[name] || '·'}
  </span>
);

/* ============================================================
   ATOMS
   ============================================================ */

const Btn = ({
  children, variant = 'default', size = 'md', icon, kbd,
  loading, disabled, onClick, style, type = 'button', ...rest
}) => {
  const cls = [
    'k-btn',
    variant === 'primary' && 'k-btn-primary',
    variant === 'accent'  && 'k-btn-accent',
    variant === 'ghost'   && 'k-btn-ghost',
    variant === 'approve' && 'k-btn-approve',
    variant === 'reject'  && 'k-btn-reject',
    size === 'sm' && 'k-btn-sm',
    size === 'lg' && 'k-btn-lg',
    disabled && 'is-disabled',
  ].filter(Boolean).join(' ');
  return (
    <button type={type} className={cls} disabled={disabled} onClick={onClick} style={style} {...rest}>
      {loading ? <span className="k-spin" style={{ borderTopColor: variant === 'primary' || variant === 'accent' ? '#fff' : undefined }} />
               : icon && <Icon name={icon} />}
      <span>{children}</span>
      {kbd && <Kbd style={
        variant === 'primary' || variant === 'accent'
          ? { background: 'rgba(255,255,255,0.12)', borderColor: 'rgba(255,255,255,0.18)', color: '#fff' }
          : undefined
      }>{kbd}</Kbd>}
    </button>
  );
};

const IconBtn = ({ icon, onClick, dot, label, style }) => (
  <button type="button" className="k-iconbtn" onClick={onClick} aria-label={label} style={style}>
    <Icon name={icon} />
    {dot && <span className="k-dot" />}
  </button>
);

const Input = ({
  value, defaultValue, onChange, placeholder, prefix, suffix,
  error, disabled, readOnly,
}) => {
  const cls = ['k-input', error && 'is-error', disabled && 'is-disabled'].filter(Boolean).join(' ');
  return (
    <div className={cls}>
      {prefix && <span className="k-input-aff">{prefix}</span>}
      <input
        value={value} defaultValue={defaultValue}
        onChange={onChange ? (e) => onChange(e.target.value) : undefined}
        placeholder={placeholder} disabled={disabled} readOnly={readOnly}
      />
      {suffix && <span className="k-input-aff">{suffix}</span>}
    </div>
  );
};

const Textarea = ({ value, defaultValue, onChange, placeholder, rows = 4, disabled }) => (
  <textarea
    className="k-textarea"
    rows={rows}
    value={value}
    defaultValue={defaultValue}
    onChange={onChange ? (e) => onChange(e.target.value) : undefined}
    placeholder={placeholder}
    disabled={disabled}
  />
);

const Checkbox = ({ checked, onChange, label, disabled }) => {
  const cls = ['k-check', checked && 'is-checked', disabled && 'is-disabled'].filter(Boolean).join(' ');
  return (
    <label className={cls} onClick={(e) => { if (disabled) return; e.preventDefault(); onChange?.(!checked); }}>
      <span className="k-check-box" />
      {label && <span>{label}</span>}
    </label>
  );
};

const Switch = ({ on, onChange, disabled }) => {
  const cls = ['k-switch', on && 'is-on', disabled && 'is-disabled'].filter(Boolean).join(' ');
  return (
    <button type="button" className={cls} onClick={() => !disabled && onChange?.(!on)} aria-pressed={on} />
  );
};

const Chip = ({ children, variant, dot, onClick }) => {
  const cls = [
    'k-chip',
    variant === 'success' && 'k-chip-success',
    variant === 'warn'    && 'k-chip-warn',
    variant === 'danger'  && 'k-chip-danger',
    variant === 'info'    && 'k-chip-info',
    variant === 'accent'  && 'k-chip-accent',
    variant === 'solid'   && 'k-chip-solid',
    variant === 'mute'    && 'k-chip-mute',
  ].filter(Boolean).join(' ');
  const Tag = onClick ? 'button' : 'span';
  return (
    <Tag className={cls} onClick={onClick} type={onClick ? 'button' : undefined}>
      {dot && <span className="k-chip-dot" />}
      {children}
    </Tag>
  );
};

const StatusDot = ({ kind }) => {
  const cls = ['k-status-dot', kind && `is-${kind}`].filter(Boolean).join(' ');
  return <span className={cls} />;
};

const Kbd = ({ children, style }) => <kbd className="k-kbd" style={style}>{children}</kbd>;

const Avatar = ({ initials, size = 28, style }) => (
  <div className="k-avatar" style={{ width: size, height: size, fontSize: size * 0.4, ...style }}>
    {initials}
  </div>
);

const Spinner = ({ light }) => (
  <span className="k-spin" style={{ borderTopColor: light ? '#fff' : undefined }} />
);

const Skeleton = ({ width, height = 12, style }) => (
  <div className="k-skel" style={{ width, height, ...style }} />
);

/* ============================================================
   MOLECULES
   ============================================================ */

const Field = ({ label, help, error, children }) => (
  <div className="k-field">
    {label && <div className="k-field-label">{label}</div>}
    {children}
    {(help || error) && <div className={`k-field-help${error ? ' is-error' : ''}`}>{error || help}</div>}
  </div>
);

const Tabs = ({ items, value, onChange, mod }) => (
  <div className="k-tabs" style={{ '--m-mod': mod ? `var(--m-${mod})` : undefined }}>
    {items.map(it => (
      <div key={it.id}
           className={`k-tab${it.id === value ? ' is-active' : ''}`}
           onClick={() => onChange?.(it.id)}>
        {it.label}
        {typeof it.count === 'number' && <span className="k-tab-count">{it.count}</span>}
      </div>
    ))}
  </div>
);

const Seg = ({ items, value, onChange }) => (
  <div className="k-seg">
    {items.map(it => (
      <button key={it.id} type="button"
              className={it.id === value ? 'is-on' : ''}
              onClick={() => onChange?.(it.id)}>
        {it.label}
      </button>
    ))}
  </div>
);

const Search = ({ value, placeholder, onClick, kbd = '⌘K' }) => (
  <div className="k-search" onClick={onClick} style={{ cursor: 'pointer' }}>
    <Icon name="search" />
    <span>{value || placeholder || 'Search…'}</span>
    {kbd && <Kbd>{kbd}</Kbd>}
  </div>
);

const Crumb = ({ items }) => (
  <div className="k-crumb">
    {items.map((it, i) => (
      <React.Fragment key={i}>
        {i > 0 && <span className="k-crumb-sep">/</span>}
        <span>{it}</span>
      </React.Fragment>
    ))}
  </div>
);

const KPITile = ({ label, value, trend, foot, mod, valueColor }) => (
  <div className="k-kpi" style={{ '--m-mod': mod ? `var(--m-${mod})` : undefined }}>
    <div className="k-kpi-label">{label}</div>
    <div className="k-kpi-value" style={{ color: valueColor }}>{value}</div>
    {(trend || foot) && (
      <div className="k-kpi-foot">
        {trend && <span className={`k-kpi-trend ${trend.dir}`}>{trend.label}</span>}
        {foot && <span>{foot}</span>}
      </div>
    )}
  </div>
);

const ConfidenceMeter = ({ level, label, mod }) => (
  <span className="k-conf" style={{ '--m-mod': mod ? `var(--m-${mod})` : undefined }}>
    <span className="k-conf-bars">
      {[1,2,3,4].map(i => <span key={i} className={i <= level ? 'on' : ''} />)}
    </span>
    {label}
  </span>
);

const NotificationRow = ({ title, meta, read, mod, onClick }) => (
  <div className={`k-notif${read ? ' is-read' : ''}`}
       style={{ '--m-mod': mod ? `var(--m-${mod})` : undefined }}
       onClick={onClick}>
    <span className="k-notif-dot" />
    <div className="k-notif-body">
      <div className="k-notif-title">{title}</div>
      <div className="k-notif-meta">{meta}</div>
    </div>
    <Icon name="chev" />
  </div>
);

const ApprovalStep = ({ who, meta, state = 'pending', mod }) => {
  const cls = ['k-tl-step',
    state === 'done' && 'is-done',
    state === 'now'  && 'is-now',
  ].filter(Boolean).join(' ');
  return (
    <div className={cls} style={{ '--m-mod': mod ? `var(--m-${mod})` : undefined }}>
      <div className="k-tl-who" style={state === 'now' ? { fontWeight: 600 } : undefined}>{who}</div>
      <div className="k-tl-meta">{meta}</div>
    </div>
  );
};

const ApprovalChain = ({ steps, mod }) => (
  <div className="k-tl" style={{ '--m-mod': mod ? `var(--m-${mod})` : undefined }}>
    {steps.map((s, i) => <ApprovalStep key={i} {...s} mod={mod} />)}
  </div>
);

const RunBadge = ({ id, version, when }) => (
  <span className="k-run-badge">
    <span>{id}</span>
    {version && <span>·</span>}
    {version && <span>{version}</span>}
    {when && <span>·</span>}
    {when && <span>{when}</span>}
  </span>
);

const StatusBadge = ({ kind, children }) => {
  const cls = ['k-status-badge',
    kind === 'verified' && 'is-verified',
    kind === 'pending'  && 'is-pending',
    kind === 'failed'   && 'is-failed',
    kind === 'drift'    && 'is-drift',
  ].filter(Boolean).join(' ');
  const dot = { verified: 'success', pending: 'warn', failed: 'danger', drift: null }[kind];
  return (
    <span className={cls}>
      <StatusDot kind={dot} />
      <span>{children}</span>
    </span>
  );
};

const VerificationStamp = ({ children }) => (
  <span className="k-verify">{children}</span>
);

const PageHead = ({ crumb, title, subtitle, actions }) => (
  <header className="k-pagehead">
    <div>
      {crumb && <Crumb items={crumb} />}
      <h1 className="t-h1" style={{ margin: '6px 0 0' }}>{title}</h1>
      {subtitle && <div className="t-meta" style={{ marginTop: 6 }}>{subtitle}</div>}
    </div>
    {actions && <div className="k-pagehead-actions">{actions}</div>}
  </header>
);

const Card = ({ title, eyebrow, children, footer, tight, flat, style }) => {
  const cls = ['k-card', tight && 'k-card-tight', flat && 'k-card-flat'].filter(Boolean).join(' ');
  return (
    <section className={cls} style={style}>
      {eyebrow && <div className="t-eyebrow" style={{ marginBottom: 8 }}>{eyebrow}</div>}
      {title && <h3 className="t-h3" style={{ margin: 0 }}>{title}</h3>}
      {children}
      {footer && <div style={{ marginTop: 12 }}>{footer}</div>}
    </section>
  );
};


/* ============================================================
   STATE LAYOUTS — empty · loading · error · restricted
   ============================================================ */

const EmptyState = ({ mark = 'K', title, body, cta }) => (
  <div className="k-empty">
    <div className="k-empty-mark">{mark}</div>
    <div className="k-empty-title">{title}</div>
    {body && <div className="k-empty-body">{body}</div>}
    {cta && <div className="k-empty-cta">{cta}</div>}
  </div>
);

const RestrictedState = ({ badge = 'ADMIN ONLY', title, body, cta }) => (
  <div className="k-locked">
    <div className="k-locked-badge">{badge}</div>
    <h3 className="t-h3" style={{ margin: '6px 0 0' }}>{title}</h3>
    {body && <p style={{ fontSize: 13, marginTop: 8, lineHeight: 1.55 }}>{body}</p>}
    {cta && <div style={{ marginTop: 12 }}>{cta}</div>}
  </div>
);

const ErrorState = ({ code, title, body, retry }) => (
  <div className="k-card" style={{ background: 'var(--danger-soft)', borderColor: 'var(--danger-line)' }}>
    <div className="t-eyebrow" style={{ color: 'var(--danger)' }}>Error · retry path</div>
    <h3 className="t-h3" style={{ margin: '6px 0 0' }}>{title}</h3>
    <p className="t-body-sm" style={{ marginTop: 6 }}>{body}</p>
    <div className="t-mono" style={{ fontSize: 11, color: 'var(--mute)', marginTop: 8 }}>{code}</div>
    {retry && <div style={{ marginTop: 14, display: 'flex', gap: 8 }}>{retry}</div>}
  </div>
);

const LoadingBlock = ({ rows = 5 }) => (
  <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
    <Skeleton width="40%" height={14} />
    <Skeleton width="85%" height={22} />
    {Array.from({ length: rows - 2 }).map((_, i) => (
      <Skeleton key={i} width={['100%','95%','60%','78%','55%'][i % 5]} height={12} />
    ))}
  </div>
);


/* ============================================================
   SHELL — TopBar · Rail · PageWrap
   ============================================================ */

const TopBar = ({
  tenant = 'Acme Jewels', user = 'RP', userName = 'Rohan Patel', userEmail = 'rohan@acme.com',
  approvalCount = 4,
  onCmdK, onBell, onAvatar, avatarMenuOpen, onSignOut, authMethod, onShortcuts,
  onProfile, onSwitchWorkspace,
}) => {
  const providerLabel = {
    google: 'Google Workspace',
    microsoft: 'Microsoft Entra ID',
    password: 'Email · password',
    dev:      'Dev login',
  }[authMethod] || 'SSO';

  // Click-outside closes the avatar menu
  useEffect(() => {
    if (!avatarMenuOpen) return;
    const onDoc = (e) => {
      if (!e.target.closest('.k-avatar-menu-wrap')) onAvatar?.();
    };
    setTimeout(() => document.addEventListener('click', onDoc), 0);
    return () => document.removeEventListener('click', onDoc);
  }, [avatarMenuOpen, onAvatar]);

  return (
    <header className="k-topbar k-shell-top">
      <div className="k-brand">
        <div className="k-brand-mark">K</div>
        <div className="k-brand-name">KOVA</div>
        <span className="k-brand-tenant">/ {tenant}</span>
      </div>
      <Search placeholder="Search runs, decisions, SKUs…" onClick={onCmdK} />
      <div style={{ marginLeft: 'auto', display: 'flex', alignItems: 'center', gap: 10 }}>
        {approvalCount > 0 && (
          <Chip variant="warn" dot>{approvalCount} approvals</Chip>
        )}
        <IconBtn icon="bell" dot onClick={onBell} label="Notifications" />

        <div className="k-avatar-menu-wrap" style={{ position: 'relative' }}>
          <button type="button"
                  className="k-iconbtn"
                  onClick={onAvatar}
                  aria-label="Account"
                  style={{ padding: 0, width: 32, height: 32 }}>
            <Avatar initials={user} size={28} />
          </button>

          {avatarMenuOpen && (
            <div className="k-avatar-menu" role="menu">
              <div className="k-avatar-menu-head">
                <Avatar initials={user} size={32} />
                <div style={{ minWidth: 0 }}>
                  <div className="t-body-sm" style={{ color: 'var(--ink)', fontWeight: 600 }}>{userName}</div>
                  <div className="t-meta">{userEmail}</div>
                </div>
              </div>
              <div className="k-avatar-menu-chip">
                <StatusDot kind="success" />
                <span>Signed in via {providerLabel}</span>
              </div>
              <div className="k-avatar-menu-sep" />
              <button className="k-avatar-menu-item" onClick={() => { onAvatar?.(); onProfile?.(); }}>
                <span>Profile &amp; preferences</span>
                <Kbd>⌘ ,</Kbd>
              </button>
              <button className="k-avatar-menu-item" onClick={() => { onAvatar?.(); onSwitchWorkspace?.(); }}>
                <span>Switch workspace</span>
                <Kbd>⌘ ⇧ O</Kbd>
              </button>
              <button className="k-avatar-menu-item" onClick={() => { onAvatar?.(); onShortcuts?.(); }}>
                <span>Keyboard shortcuts</span>
                <Kbd>?</Kbd>
              </button>
              <div className="k-avatar-menu-sep" />
              <button className="k-avatar-menu-item is-danger" onClick={onSignOut}>
                <span>Sign out</span>
              </button>
            </div>
          )}
        </div>
      </div>
    </header>
  );
};

const RAIL_ITEMS = [
  { group: 'Operate', items: [
    { id: 'home',     label: 'Home',      mod: 'home' },
    { id: 'orbit',    label: 'Orbit',     mod: 'orbit' },
    { id: 'vault',    label: 'Vault',     mod: 'vault', count: 2 },
    { id: 'price',    label: 'Price',     mod: 'price', count: 1 },
    { id: 'kraft',    label: 'Kraft',     mod: 'kraft' },
  ]},
  { group: 'Trust', items: [
    { id: 'approvals',label: 'Approvals', mod: 'approvals', count: 4 },
    { id: 'monitor',  label: 'Monitor',   mod: 'monitor' },
  ]},
  { group: 'Configure', items: [
    { id: 'connect',  label: 'Connect',   mod: 'connect' },
    { id: 'admin',    label: 'Admin',     mod: 'admin' },
    { id: 'wiki',     label: 'Wiki',      mod: 'wiki' },
  ]},
  { group: 'System', items: [
    { id: 'library',  label: 'Design library', mod: 'home' },
  ]},
];

const Rail = ({ active, onNavigate, role, canAccess }) => {
  const visible = (id) => !canAccess || canAccess(role, id);
  return (
    <nav className="k-rail k-shell-rail">
      {RAIL_ITEMS.map(({ group, items }) => {
        const allowed = items.filter(it => visible(it.id));
        if (allowed.length === 0) return null;
        return (
          <React.Fragment key={group}>
            <div className="k-rail-section">{group}</div>
            {allowed.map(it => (
              <div key={it.id}
                   className={`k-nav${active === it.id ? ' is-active' : ''}`}
                   style={{ '--m-mod': `var(--m-${it.mod})` }}
                   onClick={() => onNavigate?.(it.id)}>
                <span className="k-nav-dot" />
                <span>{it.label}</span>
                {it.count && <span className="k-nav-count">{it.count}</span>}
              </div>
            ))}
          </React.Fragment>
        );
      })}
    </nav>
  );
};


/* ============================================================
   OVERLAYS — Drawer · Modal · CommandPalette · Toasts
   ============================================================ */

const Drawer = ({ open, title, eyebrow, onClose, footer, children }) => {
  useEscape(open, onClose);
  return (
    <div className={`k-drawer-portal${open ? ' is-open' : ''}`}>
      <div className="k-drawer-scrim" onClick={onClose} />
      <aside className="k-drawer">
        <div className="k-drawer-head">
          <div>
            {eyebrow && <div className="t-eyebrow" style={{ marginBottom: 4 }}>{eyebrow}</div>}
            {title && <div className="t-h2">{title}</div>}
          </div>
          <IconBtn icon="cross" onClick={onClose} label="Close" />
        </div>
        <div className="k-drawer-body">{children}</div>
        {footer && <div className="k-drawer-foot">{footer}</div>}
      </aside>
    </div>
  );
};

const Modal = ({ open, title, onClose, footer, children, destructive }) => {
  useEscape(open, onClose);
  return (
    <div className={`k-modal-portal${open ? ' is-open' : ''}`} onClick={onClose}>
      <div className="k-modal" onClick={(e) => e.stopPropagation()}>
        {title && (
          <div className="k-modal-head">
            <div className="k-modal-title">{title}</div>
          </div>
        )}
        <div className="k-modal-body">{children}</div>
        {footer && <div className="k-modal-foot">{footer}</div>}
      </div>
    </div>
  );
};

const CommandPalette = ({ open, onClose, sections, onPick }) => {
  const [q, setQ] = useState('');
  const [active, setActive] = useState(0);
  const inputRef = useRef(null);
  useEscape(open, onClose);

  useEffect(() => {
    if (open) {
      setQ(''); setActive(0);
      const t = setTimeout(() => inputRef.current?.focus(), 60);
      return () => clearTimeout(t);
    }
  }, [open]);

  const flat = useMemo(() => {
    const filterText = q.trim().toLowerCase();
    const out = [];
    sections.forEach(section => {
      const matches = section.items.filter(it =>
        !filterText || it.label.toLowerCase().includes(filterText) ||
        (it.kw && it.kw.some(k => k.toLowerCase().includes(filterText)))
      );
      if (matches.length) out.push({ group: section.group, items: matches });
    });
    return out;
  }, [q, sections]);

  const flatList = useMemo(() => flat.flatMap(s => s.items), [flat]);

  useEffect(() => {
    if (active >= flatList.length) setActive(Math.max(0, flatList.length - 1));
  }, [flatList.length, active]);

  const onKey = (e) => {
    if (e.key === 'ArrowDown') { e.preventDefault(); setActive(a => Math.min(a + 1, flatList.length - 1)); }
    else if (e.key === 'ArrowUp')   { e.preventDefault(); setActive(a => Math.max(a - 1, 0)); }
    else if (e.key === 'Enter')     { e.preventDefault(); const pick = flatList[active]; if (pick) { onPick?.(pick); onClose?.(); } }
  };

  let idx = 0;
  return (
    <div className={`k-cmdk-portal${open ? ' is-open' : ''}`} onClick={onClose}>
      <div className="k-cmdk" onClick={(e) => e.stopPropagation()}>
        <div className="k-cmdk-input">
          <Icon name="search" size={16} />
          <input ref={inputRef} value={q} onChange={(e) => setQ(e.target.value)}
                 onKeyDown={onKey} placeholder="Jump to module · type a command · search runs…" />
          <Kbd>esc</Kbd>
        </div>
        <div className="k-cmdk-list">
          {flat.length === 0 && <div className="k-cmdk-empty">No matches for “{q}”.</div>}
          {flat.map(section => (
            <React.Fragment key={section.group}>
              <div className="k-cmdk-group-label">{section.group}</div>
              {section.items.map(it => {
                const i = idx++;
                return (
                  <div key={it.id}
                       className={`k-cmdk-row${i === active ? ' is-on' : ''}`}
                       style={{ '--m-mod': it.mod ? `var(--m-${it.mod})` : undefined }}
                       onMouseEnter={() => setActive(i)}
                       onClick={() => { onPick?.(it); onClose?.(); }}>
                    <span className="k-cmdk-dot" />
                    <span>{it.label}</span>
                    {it.kbd && (
                      <span className="k-cmdk-kbd">
                        {it.kbd.split(' ').map((p, k) => <Kbd key={k}>{p}</Kbd>)}
                      </span>
                    )}
                  </div>
                );
              })}
            </React.Fragment>
          ))}
        </div>
        <div className="k-cmdk-foot">
          <span className="k-cmdk-foot-key"><Kbd>↑</Kbd> <Kbd>↓</Kbd> navigate</span>
          <span className="k-cmdk-foot-key"><Kbd>⏎</Kbd> open</span>
          <span className="k-cmdk-foot-key"><Kbd>esc</Kbd> dismiss</span>
        </div>
      </div>
    </div>
  );
};

/* ============================================================
   NOTIFICATIONS DRAWER — bell icon target
   Separate from EvidenceDrawer · architecture §11 admin telemetry
   ============================================================ */
const NotificationsDrawer = ({ open, notifs, onClose, onMarkAll, onPick }) => {
  useEscape(open, onClose);
  const [filter, setFilter] = useState('all');

  const filtered = useMemo(() => {
    if (filter === 'all') return notifs;
    return notifs.filter(n => n.kind === filter);
  }, [filter, notifs]);

  const unreadCount = notifs.filter(n => !n.read).length;

  return (
    <div className={`k-drawer-portal${open ? ' is-open' : ''}`}>
      <div className="k-drawer-scrim" onClick={onClose} />
      <aside className="k-drawer">
        <div className="k-drawer-head">
          <div>
            <div className="t-eyebrow" style={{ marginBottom: 4 }}>
              Notifications · {unreadCount > 0 ? `${unreadCount} unread` : 'all read'}
            </div>
            <div className="t-h2">Activity</div>
          </div>
          <IconBtn icon="cross" onClick={onClose} label="Close" />
        </div>
        <div className="k-notifs-filter">
          <Chip variant={filter === 'all'       ? 'solid' : 'mute'} onClick={() => setFilter('all')}>All</Chip>
          <Chip variant={filter === 'approval'  ? 'solid' : 'mute'} onClick={() => setFilter('approval')}>Approvals</Chip>
          <Chip variant={filter === 'run'       ? 'solid' : 'mute'} onClick={() => setFilter('run')}>Runs</Chip>
          <Chip variant={filter === 'error'     ? 'solid' : 'mute'} onClick={() => setFilter('error')}>Errors</Chip>
          <Chip variant={filter === 'system'    ? 'solid' : 'mute'} onClick={() => setFilter('system')}>System</Chip>
        </div>
        <div className="k-drawer-body" style={{ paddingTop: 0 }}>
          {filtered.length === 0 ? (
            <div className="k-notifs-empty">
              {filter === 'all' ? 'Nothing waiting.' : `No ${filter} notifications.`}
            </div>
          ) : filtered.map(n => (
            <NotificationRow key={n.id}
                             mod={n.mod}
                             title={n.title}
                             meta={n.meta}
                             read={n.read}
                             onClick={() => onPick?.(n)} />
          ))}
          {filtered.length > 0 && unreadCount > 0 && (
            <button type="button" className="k-notifs-mark-read" onClick={onMarkAll}>
              Mark all as read
            </button>
          )}
        </div>
        <div className="k-drawer-foot">
          <span style={{ flex: 1, fontSize: 'var(--t-meta)', color: 'var(--mute)' }}>
            Notification policy is audited · §11
          </span>
          <Btn variant="ghost" onClick={onClose}>Close</Btn>
          <Btn onClick={() => { onClose?.(); location.hash = 'monitor'; }}>Open MONITOR</Btn>
        </div>
      </aside>
    </div>
  );
};


/* ============================================================
   SHORTCUTS OVERLAY — ? key
   ============================================================ */
const SHORTCUT_GROUPS = [
  { group: 'Global', items: [
    [['⌘', 'K'],       'Command palette'],
    [['⌘', 'E'],       'Open evidence drawer'],
    [['⌘', ','],       'Profile & preferences'],
    [['⌘', '⇧', 'O'],  'Switch workspace'],
    [['⌘', '\\'],      'Collapse rail'],
    [['?'],            'Show this overlay'],
    [['esc'],          'Close any overlay'],
  ]},
  { group: 'Decision', items: [
    [['⌘', '⏎'],       'Approve & sign'],
    [['⌘', '⇧', '⏎'],  'Reject with reason'],
    [['⌘', 'R'],       'Request revision'],
    [['⌘', 'V'],       'Open evidence'],
    [['⌘', 'H'],       'Open run history'],
  ]},
  { group: 'Navigate', items: [
    [['g', 'h'],       'Go to Home'],
    [['g', 'o'],       'Go to Orbit'],
    [['g', 'v'],       'Go to Vault'],
    [['g', 'p'],       'Go to Price'],
    [['g', 'k'],       'Go to Kraft'],
    [['g', 'a'],       'Go to Approvals'],
    [['g', 'm'],       'Go to Monitor'],
  ]},
];

const ShortcutsOverlay = ({ open, onClose }) => {
  useEscape(open, onClose);
  return (
    <div className={`k-shortcuts-portal${open ? ' is-open' : ''}`} onClick={onClose}>
      <div className="k-shortcuts" onClick={(e) => e.stopPropagation()}>
        <div className="k-shortcuts-head">
          <div>
            <div className="t-eyebrow" style={{ marginBottom: 4 }}>Help</div>
            <div className="t-h2">Keyboard shortcuts</div>
          </div>
          <IconBtn icon="cross" onClick={onClose} label="Close" />
        </div>
        <div className="k-shortcuts-body">
          {SHORTCUT_GROUPS.map(g => (
            <div key={g.group} className="k-shortcuts-group">
              <div className="t-eyebrow">{g.group}</div>
              {g.items.map(([keys, label], i) => (
                <div key={i} className="k-shortcuts-row">
                  <span>{label}</span>
                  <span className="k-shortcuts-keys">
                    {keys.map((k, j) => <Kbd key={j}>{k}</Kbd>)}
                  </span>
                </div>
              ))}
            </div>
          ))}
        </div>
      </div>
    </div>
  );
};


/* ============================================================
   PROFILE OVERLAY — account & preferences
   Maps to architecture §4.6 (user provisioning) + §4.8 (users / identity_accounts).
   The IdP (Entra ID / Google Workspace) owns password + MFA per §4.1, so this
   overlay surfaces read-only identity facts and the editable preference subset
   that lives in the tenant D1.
   ============================================================ */
const PROFILE_PROVIDER_META = {
  google:    { label: 'Google Workspace',    badge: 'Google · SSO',     statusKind: 'success' },
  microsoft: { label: 'Microsoft Entra ID',  badge: 'Microsoft · SSO',  statusKind: 'success' },
  password:  { label: 'Email · password',    badge: 'Email · password', statusKind: 'info'    },
  dev:       { label: 'Dev login',           badge: 'Dev login',        statusKind: 'warn'    },
};

const ProfileOverlay = ({
  open, onClose,
  user = {},          // { name, email, role, roleLabel, tenant, tenantId, initials, authMethod, lastSignInLabel }
  prefs = {},         // { dailyBrief, approvalsDigest, monitorAlerts, marketingNews }
  onPrefChange,       // (key, value) => void
  onOpenShortcuts,
  onSignOut,
}) => {
  useEscape(open, onClose);
  const [tab, setTab] = useState('profile');
  useEffect(() => { if (open) setTab('profile'); }, [open]);

  const provider = PROFILE_PROVIDER_META[user.authMethod] || PROFILE_PROVIDER_META.google;

  return (
    <div className={`k-profile-portal${open ? ' is-open' : ''}`} onClick={onClose}>
      <div className="k-profile" onClick={(e) => e.stopPropagation()} role="dialog" aria-label="Profile and preferences">
        <div className="k-profile-head">
          <Avatar initials={user.initials || 'CE'} size={44} />
          <div className="k-profile-head-text">
            <div className="k-profile-name">{user.name || 'CEO'}</div>
            <div className="k-profile-meta">{user.email || ''}</div>
          </div>
          <IconBtn icon="cross" onClick={onClose} label="Close" />
        </div>

        <div className="k-profile-tabs" role="tablist">
          <button role="tab" aria-selected={tab === 'profile'}
                  className={`k-profile-tab${tab === 'profile' ? ' is-on' : ''}`}
                  onClick={() => setTab('profile')}>Profile</button>
          <button role="tab" aria-selected={tab === 'prefs'}
                  className={`k-profile-tab${tab === 'prefs' ? ' is-on' : ''}`}
                  onClick={() => setTab('prefs')}>Preferences</button>
          <button role="tab" aria-selected={tab === 'security'}
                  className={`k-profile-tab${tab === 'security' ? ' is-on' : ''}`}
                  onClick={() => setTab('security')}>Security</button>
        </div>

        <div className="k-profile-body">
          {tab === 'profile' && (
            <>
              <div className="k-profile-row">
                <div className="k-profile-row-label">Tenant</div>
                <div className="k-profile-row-value">
                  <span>{user.tenant || '—'}</span>
                  {user.tenantId && <Chip variant="mute">{user.tenantId}</Chip>}
                </div>
              </div>
              <div className="k-profile-row">
                <div className="k-profile-row-label">Display name</div>
                <div className="k-profile-row-value">{user.name || '—'}</div>
              </div>
              <div className="k-profile-row">
                <div className="k-profile-row-label">Email</div>
                <div className="k-profile-row-value">{user.email || '—'}</div>
              </div>
              <div className="k-profile-row">
                <div className="k-profile-row-label">Role</div>
                <div className="k-profile-row-value">
                  <Chip variant="info">{user.roleLabel || user.role || 'CEO'}</Chip>
                </div>
              </div>
              <div className="k-profile-row">
                <div className="k-profile-row-label">Identity provider</div>
                <div className="k-profile-row-value">
                  <StatusDot kind={provider.statusKind} />
                  <span>{provider.label}</span>
                </div>
              </div>
              <div className="k-profile-row">
                <div className="k-profile-row-label">Last sign-in</div>
                <div className="k-profile-row-value">{user.lastSignInLabel || 'Just now · this session'}</div>
              </div>
              <div className="t-meta" style={{ marginTop: 8 }}>
                Display name and notification preferences are editable. Email, role, and identity
                provider are managed in <strong>Admin</strong> by your KOVA administrator
                (architecture §4 · SSO &amp; provisioning).
              </div>
            </>
          )}

          {tab === 'prefs' && (
            <>
              <div className="k-pref-row">
                <div className="k-pref-row-text">
                  <div className="k-pref-row-title">Daily brief email</div>
                  <div className="k-pref-row-desc">Receive the 6 AM Orbit summary by email.</div>
                </div>
                <Switch on={!!prefs.dailyBrief}
                        onChange={(v) => onPrefChange?.('dailyBrief', v)} />
              </div>
              <div className="k-pref-row">
                <div className="k-pref-row-text">
                  <div className="k-pref-row-title">Approvals digest</div>
                  <div className="k-pref-row-desc">Twice-a-day summary of pending verified decisions.</div>
                </div>
                <Switch on={!!prefs.approvalsDigest}
                        onChange={(v) => onPrefChange?.('approvalsDigest', v)} />
              </div>
              <div className="k-pref-row">
                <div className="k-pref-row-text">
                  <div className="k-pref-row-title">Monitor alerts</div>
                  <div className="k-pref-row-desc">Page the bell when a run lands in retry or denial.</div>
                </div>
                <Switch on={!!prefs.monitorAlerts}
                        onChange={(v) => onPrefChange?.('monitorAlerts', v)} />
              </div>
              <div className="k-pref-row">
                <div className="k-pref-row-text">
                  <div className="k-pref-row-title">Product news</div>
                  <div className="k-pref-row-desc">Occasional updates on KOVA modules and skills.</div>
                </div>
                <Switch on={!!prefs.marketingNews}
                        onChange={(v) => onPrefChange?.('marketingNews', v)} />
              </div>
              <div className="t-meta" style={{ marginTop: 8 }}>
                Changes save locally for this session. The backend endpoint
                <code className="t-mono"> PATCH /api/profile/preferences </code>
                will persist these to your <code className="t-mono">users</code> row (architecture §4.8).
              </div>
            </>
          )}

          {tab === 'security' && (
            <>
              <div className="k-profile-row">
                <div className="k-profile-row-label">Auth method</div>
                <div className="k-profile-row-value">
                  <Chip variant="info">{provider.badge}</Chip>
                </div>
              </div>
              <div className="k-profile-row">
                <div className="k-profile-row-label">Password &amp; MFA</div>
                <div className="k-profile-row-value">
                  <span>Managed by your identity provider</span>
                </div>
              </div>
              <div className="k-profile-row">
                <div className="k-profile-row-label">Session</div>
                <div className="k-profile-row-value">
                  <StatusDot kind="success" />
                  <span>Active · short-lived JWT (architecture §4.4)</span>
                </div>
              </div>
              <div className="t-meta" style={{ marginTop: 8 }}>
                KOVA never stores your password. To rotate credentials or enable MFA, use the
                {' '}{provider.label} admin console.
              </div>
              <div style={{ display: 'flex', gap: 8, marginTop: 8 }}>
                <Btn variant="reject" icon="cross" onClick={onSignOut}>Sign out</Btn>
              </div>
            </>
          )}
        </div>

        <div className="k-profile-foot">
          <button className="k-profile-tab" style={{ paddingLeft: 0 }} onClick={onOpenShortcuts}>
            View keyboard shortcuts <Kbd>?</Kbd>
          </button>
          <Btn variant="ghost" onClick={onClose}>Close</Btn>
        </div>
      </div>
    </div>
  );
};


/* ============================================================
   WORKSPACE SWITCHER — tenant + per-module workspaces
   Architecture §1.2 (tenant isolation, subdomain → tenant) and §4.8
   (user_workspaces). In production, switching tenant is a redirect to
   `{tenantId}.kova.app`; locally it rewrites `?tenant=`.
   ============================================================ */
const WorkspaceSwitcher = ({
  open, onClose,
  currentTenantId,
  tenants = [],            // [{ id, name, persona, role }]
  workspaces = [],         // [{ id, name, module, scope }]
  onPickTenant,            // (tenant) => void
  onPickWorkspace,         // (workspace) => void
}) => {
  useEscape(open, onClose);
  return (
    <div className={`k-wsw-portal${open ? ' is-open' : ''}`} onClick={onClose}>
      <div className="k-wsw" onClick={(e) => e.stopPropagation()} role="dialog" aria-label="Switch workspace">
        <div className="k-wsw-head">
          <div>
            <div className="t-eyebrow" style={{ marginBottom: 4 }}>Switch</div>
            <div className="t-h2">Workspaces &amp; tenants</div>
          </div>
          <IconBtn icon="cross" onClick={onClose} label="Close" />
        </div>

        <div className="k-wsw-body">
          <div className="k-wsw-group-label">Tenants</div>
          {tenants.length === 0 && (
            <div className="k-wsw-empty">You have no tenants assigned.</div>
          )}
          {tenants.map(t => {
            const isCurrent = t.id === currentTenantId;
            return (
              <button key={t.id}
                      className={`k-wsw-row${isCurrent ? ' is-current' : ''}`}
                      onClick={() => !isCurrent && onPickTenant?.(t)}
                      aria-current={isCurrent ? 'true' : undefined}>
                <span className="k-wsw-row-mark">
                  {(t.name || t.id).slice(0, 2).toUpperCase()}
                </span>
                <span className="k-wsw-row-text">
                  <span className="k-wsw-row-name">{t.name}</span>
                  <span className="k-wsw-row-meta">
                    {t.persona ? `${t.persona} · ` : ''}{t.role || 'CEO'} · {t.id}.kova.app
                  </span>
                </span>
                <span className="k-wsw-row-right">
                  {isCurrent
                    ? <Chip variant="success" dot>Current</Chip>
                    : <Kbd>↵</Kbd>}
                </span>
              </button>
            );
          })}

          {workspaces.length > 0 && (
            <>
              <div className="k-wsw-group-label" style={{ marginTop: 8 }}>Workspaces</div>
              {workspaces.map(w => (
                <button key={w.id}
                        className="k-wsw-row"
                        onClick={() => onPickWorkspace?.(w)}>
                  <span className="k-wsw-row-mark" style={{ color: `var(--m-${w.module})`, borderColor: `var(--m-${w.module})` }}>
                    {(w.module || w.name || '').slice(0, 2).toUpperCase()}
                  </span>
                  <span className="k-wsw-row-text">
                    <span className="k-wsw-row-name">{w.name}</span>
                    <span className="k-wsw-row-meta">{w.module?.toUpperCase()} · {w.scope || 'private'}</span>
                  </span>
                  <span className="k-wsw-row-right"><Kbd>↵</Kbd></span>
                </button>
              ))}
            </>
          )}
        </div>

        <div className="k-wsw-foot">
          <span className="t-meta">Architecture §1.2 · subdomain &rarr; tenant resolution</span>
          <Btn variant="ghost" onClick={onClose}>Close <Kbd>esc</Kbd></Btn>
        </div>
      </div>
    </div>
  );
};


const Toast = ({ kind = 'success', title, body }) => {
  const cls = ['k-toast',
    kind === 'warn'  && 'is-warn',
    kind === 'error' && 'is-error',
    kind === 'info'  && 'is-info',
  ].filter(Boolean).join(' ');
  const icon = { success: '✓', warn: '!', error: '✕', info: 'i' }[kind];
  return (
    <div className={cls}>
      <span className="k-toast-icon">{icon}</span>
      <div className="k-toast-body">
        <div className="k-toast-title">{title}</div>
        {body && <div className="k-toast-meta">{body}</div>}
      </div>
    </div>
  );
};

const ToastStack = ({ toasts }) => (
  <div className="k-toast-portal">
    {toasts.map(t => <Toast key={t.id} {...t} />)}
  </div>
);


/* ============================================================
   HOOKS
   ============================================================ */

function useEscape(active, onClose) {
  useEffect(() => {
    if (!active) return;
    const onKey = (e) => { if (e.key === 'Escape') onClose?.(); };
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, [active, onClose]);
}

/* ============================================================
   EXPORT to window
   ============================================================ */
Object.assign(window.K = window.K || {}, {
  Icon, Btn, IconBtn, Input, Textarea, Checkbox, Switch, Chip, StatusDot, Kbd, Avatar, Spinner, Skeleton,
  Field, Tabs, Seg, Search, Crumb, KPITile, ConfidenceMeter, NotificationRow,
  ApprovalStep, ApprovalChain, RunBadge, StatusBadge, VerificationStamp, PageHead, Card,
  EmptyState, RestrictedState, ErrorState, LoadingBlock,
  TopBar, Rail, RAIL_ITEMS,
  Drawer, Modal, CommandPalette, NotificationsDrawer, ShortcutsOverlay,
  ProfileOverlay, WorkspaceSwitcher,
  Toast, ToastStack,
  useEscape,
});
