/* Aster Prototype — shared helpers, loaded after store.js and before persona screens. */

const {
  Button, Card, Badge, IconButton, Avatar, AlertLevel, AlertBanner, Tooltip,
  Stat, SignalGauge, Input, Select, Switch, Checkbox,
} = window.AsterDesignSystem_f19232;

function Ic(name, props) { return <i data-lucide={name} {...(props || {})}></i>; }

const LEVEL_LABEL = { calm: 'Calm', watch: 'Watch', warning: 'Warning', severe: 'Severe' };
const DOMAIN_LABEL = { climate: 'Climate', economic: 'Economic', conflict: 'Conflict' };
const DOMAIN_ICON = { climate: 'cloud-sun', economic: 'trending-up', conflict: 'shield-alert' };
const LEVEL_COLOR = { calm: 'var(--calm)', watch: 'var(--watch)', warning: 'var(--warning)', severe: 'var(--severe)' };
const CALL_STATUS_LABEL = {
  submitted: 'Submitted',
  reviewed: 'Under review',
  auto_pending: 'Auto-trigger pending',
  matched: 'Matched',
  triggered: 'Triggered — funds moved',
  declined: 'Declined',
};
const CALL_STATUS_TONE = {
  submitted: 'watch', reviewed: 'watch', auto_pending: 'warning',
  matched: 'watch', triggered: 'calm', declined: 'severe',
};

function fmtMMK(n) {
  return (Math.round(n)).toLocaleString('en-US') + ' MMK';
}
function fmtUSD(n) {
  return '$' + Math.round(n).toLocaleString('en-US');
}
function fmtDate(d) {
  if (!d) return '—';
  var dt = new Date(d);
  if (isNaN(dt.getTime())) return d;
  return dt.toISOString().slice(0, 10);
}
function fmtDateTime(d) {
  if (!d) return '—';
  var dt = new Date(d);
  if (isNaN(dt.getTime())) return d;
  return dt.toISOString().slice(0, 16).replace('T', ' ') + 'Z';
}
function fmtRelative(d) {
  if (!d) return '—';
  var dt = new Date(d);
  if (isNaN(dt.getTime())) return d;
  var diff = Date.now() - dt.getTime();
  if (diff < 0) diff = 0;
  var m = Math.floor(diff / 60000);
  if (m < 1) return 'just now';
  if (m < 60) return m + 'm ago';
  var h = Math.floor(m / 60);
  if (h < 24) return h + 'h ago';
  var days = Math.floor(h / 24);
  if (days < 14) return days + 'd ago';
  return fmtDate(d);
}

/* ---------- Icon rendering: automatic ----------
   A debounced MutationObserver replaces the per-component useIcons() chore, so any
   newly rendered [data-lucide] node gets its SVG without screens having to remember. */
(function setupIconObserver() {
  var pending = null;
  function render() {
    pending = null;
    // Only run when un-rendered <i data-lucide> tags exist — lucide swaps them for
    // <svg>, so this guard prevents an observer/replace feedback loop.
    if (window.lucide && document.querySelector('i[data-lucide]')) window.lucide.createIcons();
  }
  function schedule() {
    if (pending) return;
    pending = window.requestAnimationFrame ? requestAnimationFrame(render) : setTimeout(render, 40);
  }
  function attach() {
    var root = document.getElementById('root');
    if (!root || !window.MutationObserver) return;
    new MutationObserver(schedule).observe(root, { childList: true, subtree: true });
    schedule();
  }
  // Babel-standalone runs this after DOMContentLoaded, so attach immediately when possible.
  if (document.readyState === 'loading') window.addEventListener('DOMContentLoaded', attach);
  else attach();
})();
/* Kept for backwards compatibility — now a no-op wrapper over the observer. */
function useIcons(deps) {
  React.useEffect(function () { window.lucide && window.lucide.createIcons(); }, deps || []);
}

/* ---------- Small reusable pieces ---------- */
function SectionHeading({ eyebrow, title, hint, right }) {
  return (
    <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12, flexWrap: 'wrap', marginBottom: 'var(--space-4)' }}>
      <div>
        {eyebrow && <div style={{ font: '600 11px var(--font-text)', letterSpacing: '0.08em', textTransform: 'uppercase', color: 'var(--text-subtle)', marginBottom: 4 }}>{eyebrow}</div>}
        <h2 style={{ margin: 0, font: '600 20px var(--font-display)', color: 'var(--text-strong)' }}>{title}</h2>
        {hint && <div style={{ font: '12px var(--font-text)', color: 'var(--text-subtle)', marginTop: 3 }}>{hint}</div>}
      </div>
      {right}
    </div>
  );
}

/* Accessible modal: ESC closes, focus moves in on open and returns on close,
   backdrop click closes, animated entry, standardized footer slot. */
function Modal({ open, onClose, title, subtitle, children, footer, width }) {
  const panelRef = React.useRef(null);
  const restoreRef = React.useRef(null);

  React.useEffect(function () {
    if (!open) return;
    restoreRef.current = document.activeElement;
    function onKey(e) { if (e.key === 'Escape') onClose && onClose(); }
    document.addEventListener('keydown', onKey);
    // Move focus into the dialog so keyboard users land in context.
    setTimeout(function () {
      if (!panelRef.current) return;
      var target = panelRef.current.querySelector('input, textarea, select, button:not([data-modal-close])') || panelRef.current;
      target.focus && target.focus();
    }, 60);
    return function () {
      document.removeEventListener('keydown', onKey);
      restoreRef.current && restoreRef.current.focus && restoreRef.current.focus();
    };
  }, [open]);

  if (!open) return null;
  return (
    <div className="ap-backdrop" role="presentation"
      style={{ position: 'fixed', inset: 0, background: 'rgba(24,28,39,0.45)', display: 'flex', alignItems: 'center', justifyContent: 'center', zIndex: 1000, padding: 20 }}
      onClick={onClose}>
      <div ref={panelRef} className="ap-dialog" role="dialog" aria-modal="true" aria-label={typeof title === 'string' ? title : 'Dialog'} tabIndex={-1}
        style={{ width: width || 500, maxWidth: '100%', maxHeight: '86vh', display: 'flex', flexDirection: 'column', background: 'var(--surface-card)', borderRadius: 'var(--radius-panel)', boxShadow: 'var(--shadow-xl)', outline: 'none' }}
        onClick={function (e) { e.stopPropagation(); }}>
        <div style={{ display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between', gap: 12, padding: 'var(--space-6) var(--space-6) 0' }}>
          <div>
            <h3 style={{ margin: 0, font: '600 17px var(--font-display)', color: 'var(--text-strong)' }}>{title}</h3>
            {subtitle && <div style={{ font: '12px var(--font-text)', color: 'var(--text-subtle)', marginTop: 3 }}>{subtitle}</div>}
          </div>
          <IconButton label="Close dialog" variant="ghost" data-modal-close onClick={onClose}>{Ic('x', { width: 16, height: 16 })}</IconButton>
        </div>
        <div className="ap-scroll" style={{ padding: 'var(--space-5) var(--space-6)', overflow: 'auto', flex: 1 }}>
          {children}
        </div>
        {footer && (
          <div style={{ display: 'flex', justifyContent: 'flex-end', alignItems: 'center', gap: 8, padding: 'var(--space-4) var(--space-6)', borderTop: '1px solid var(--border-subtle)' }}>
            {footer}
          </div>
        )}
      </div>
    </div>
  );
}

/* Confirmation dialog for consequential / destructive actions. */
function ConfirmDialog({ open, onClose, onConfirm, title, body, children, confirmLabel, cancelLabel, tone, busy }) {
  return (
    <Modal open={open} onClose={onClose} title={title} width={440}
      footer={
        <React.Fragment>
          <Button variant="secondary" onClick={onClose}>{cancelLabel || 'Cancel'}</Button>
          <Button variant={tone === 'danger' ? 'danger' : 'primary'} disabled={busy} onClick={onConfirm}>
            {busy ? 'Working…' : (confirmLabel || 'Confirm')}
          </Button>
        </React.Fragment>
      }>
      {body && <div style={{ font: '14px/1.6 var(--font-text)', color: 'var(--text-body)' }}>{body}</div>}
      {children}
    </Modal>
  );
}

/* Underline tabs with optional count badges. items: [{id,label,count,icon}] */
function Tabs({ items, active, onChange }) {
  return (
    <div role="tablist" style={{ display: 'flex', gap: 22, marginBottom: 'var(--space-5)', borderBottom: '1px solid var(--border-subtle)', overflowX: 'auto' }}>
      {items.map(function (t) {
        const isActive = t.id === active;
        return (
          <button key={t.id} role="tab" aria-selected={isActive} className="ap-tab" data-active={isActive}
            onClick={function () { onChange(t.id); }}
            style={{
              display: 'flex', alignItems: 'center', gap: 7, padding: '10px 2px', border: 'none', background: 'none', cursor: 'pointer', whiteSpace: 'nowrap',
              font: (isActive ? '600 ' : '500 ') + '13px var(--font-text)',
              color: isActive ? 'var(--brand)' : 'var(--text-muted)',
            }}>
            {t.icon && Ic(t.icon, { width: 14, height: 14 })}
            {t.label}
            {t.alert && <span title="Needs attention" style={{ width: 7, height: 7, borderRadius: '50%', background: 'var(--warning)', flexShrink: 0 }} />}
            {typeof t.count === 'number' && (
              <span style={{
                font: '600 11px var(--font-mono)', padding: '1px 7px', borderRadius: 'var(--radius-pill)',
                background: isActive ? 'var(--surface-brand-soft)' : 'var(--surface-sunken)',
                color: isActive ? 'var(--brand)' : 'var(--text-subtle)',
              }}>{t.count}</span>
            )}
          </button>
        );
      })}
    </div>
  );
}

/* Pill filter chips. items: [{id,label,count,color}] */
function FilterChips({ items, active, onChange, size }) {
  return (
    <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap' }}>
      {items.map(function (f) {
        const isActive = f.id === active;
        return (
          <button key={f.id} className="ap-chip" aria-pressed={isActive}
            onClick={function () { onChange(f.id); }}
            style={{
              display: 'flex', alignItems: 'center', gap: 6,
              padding: size === 'sm' ? '4px 10px' : '6px 12px', borderRadius: 'var(--radius-pill)', cursor: 'pointer',
              border: '1px solid ' + (isActive ? 'var(--brand)' : 'var(--border-default)'),
              background: isActive ? 'var(--surface-brand-soft)' : 'var(--surface-card)',
              color: isActive ? 'var(--brand)' : 'var(--text-muted)', font: '12px var(--font-text)',
            }}>
            {f.color && <span style={{ width: 7, height: 7, borderRadius: '50%', background: f.color, flexShrink: 0 }} />}
            {f.label}
            {typeof f.count === 'number' && <span style={{ font: '600 11px var(--font-mono)', opacity: 0.75 }}>{f.count}</span>}
          </button>
        );
      })}
    </div>
  );
}

/* Inline SVG sparkline for 12-week trend series. */
function Sparkline({ points, color, width, height, fill }) {
  const w = width || 120, h = height || 34, pad = 3;
  if (!points || points.length < 2) return null;
  const min = Math.min.apply(null, points), max = Math.max.apply(null, points);
  const span = (max - min) || 1;
  const step = (w - pad * 2) / (points.length - 1);
  const xy = points.map(function (p, i) {
    return [pad + i * step, h - pad - ((p - min) / span) * (h - pad * 2)];
  });
  const line = xy.map(function (p, i) { return (i === 0 ? 'M' : 'L') + p[0].toFixed(1) + ' ' + p[1].toFixed(1); }).join(' ');
  const area = line + ' L' + xy[xy.length - 1][0].toFixed(1) + ' ' + (h - pad) + ' L' + xy[0][0].toFixed(1) + ' ' + (h - pad) + ' Z';
  const c = color || 'var(--brand)';
  const last = xy[xy.length - 1];
  return (
    <svg width={w} height={h} viewBox={'0 0 ' + w + ' ' + h} aria-hidden="true" style={{ display: 'block', overflow: 'visible' }}>
      {fill !== false && <path d={area} fill={c} opacity="0.12" />}
      <path d={line} fill="none" stroke={c} strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" />
      <circle cx={last[0]} cy={last[1]} r="2.6" fill={c} />
    </svg>
  );
}

/* Domain accent colors for indicator charts. */
const DOMAIN_COLOR = { climate: '#3A7BD5', economic: '#C9821A', conflict: '#C64B50' };

/* Interactive indicator chart: line / area / bars, optional dashed norm series,
   hover tooltip with per-week values. Data shape comes from store.indicators. */
function IndicatorChart({ indicator, labels, color }) {
  const [hover, setHover] = React.useState(null);
  const svgRef = React.useRef(null);
  const w = 300, h = 132, padL = 8, padR = 8, padT = 14, padB = 20;
  const pts = indicator.points, n = pts.length;
  const all = indicator.norm ? pts.concat(indicator.norm) : pts;
  let min = Math.min.apply(null, all), max = Math.max.apply(null, all);
  if (max - min < 1) { max += 1; min -= 1; }
  const span = max - min;
  min -= span * 0.12; max += span * 0.12;
  const x = function (i) { return padL + i * (w - padL - padR) / (n - 1); };
  const y = function (v) { return padT + (1 - (v - min) / (max - min)) * (h - padT - padB); };
  const c = color || 'var(--brand)';

  function pathOf(series) {
    return series.map(function (p, i) { return (i === 0 ? 'M' : 'L') + x(i).toFixed(1) + ' ' + y(p).toFixed(1); }).join(' ');
  }

  function onMove(e) {
    if (!svgRef.current) return;
    const rect = svgRef.current.getBoundingClientRect();
    const px = (e.clientX - rect.left) * (w / rect.width);
    let i = Math.round((px - padL) / ((w - padL - padR) / (n - 1)));
    i = Math.max(0, Math.min(n - 1, i));
    setHover(i);
  }

  const last = pts[n - 1];
  const fmtVal = function (v) { return (Math.abs(v) >= 1000 ? Math.round(v).toLocaleString('en-US') : v); };
  const barW = (w - padL - padR) / n * 0.62;

  return (
    <div style={{ border: '1px solid var(--border-subtle)', borderRadius: 'var(--radius-card)', padding: '12px 14px', background: 'var(--surface-card)' }}>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', gap: 8, marginBottom: 2 }}>
        <span style={{ font: '600 12px var(--font-text)', color: 'var(--text-strong)' }}>{indicator.label}</span>
        <span style={{ font: '700 14px var(--font-mono)', color: c, whiteSpace: 'nowrap' }}>{fmtVal(last)}<span style={{ font: '10px var(--font-mono)', color: 'var(--text-subtle)' }}> {indicator.unit}</span></span>
      </div>
      <div style={{ position: 'relative' }}>
        <svg ref={svgRef} viewBox={'0 0 ' + w + ' ' + h} style={{ width: '100%', height: 'auto', display: 'block', cursor: 'crosshair' }}
          onMouseMove={onMove} onMouseLeave={function () { setHover(null); }}
          role="img" aria-label={indicator.label + ', last 12 weeks, currently ' + last + ' ' + indicator.unit}>
          {/* gridlines */}
          {[0.25, 0.5, 0.75].map(function (f) {
            const gy = padT + f * (h - padT - padB);
            return <line key={f} x1={padL} x2={w - padR} y1={gy} y2={gy} stroke="var(--border-subtle)" strokeWidth="1" />;
          })}
          {/* norm series (dashed) */}
          {indicator.norm && <path d={pathOf(indicator.norm)} fill="none" stroke="var(--text-subtle)" strokeWidth="1.3" strokeDasharray="4 4" opacity="0.8" />}
          {/* main series */}
          {indicator.type === 'bars' && pts.map(function (p, i) {
            return <rect key={i} x={x(i) - barW / 2} y={y(p)} width={barW} height={Math.max(1, h - padB - y(p))} rx="1.5"
              fill={c} opacity={hover === i ? 1 : 0.75} />;
          })}
          {indicator.type === 'area' && <path d={pathOf(pts) + ' L' + x(n - 1).toFixed(1) + ' ' + (h - padB) + ' L' + x(0).toFixed(1) + ' ' + (h - padB) + ' Z'} fill={c} opacity="0.14" />}
          {indicator.type !== 'bars' && <path d={pathOf(pts)} fill="none" stroke={c} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />}
          {indicator.type !== 'bars' && <circle cx={x(n - 1)} cy={y(last)} r="3" fill={c} />}
          {/* hover marker */}
          {hover != null && <line x1={x(hover)} x2={x(hover)} y1={padT} y2={h - padB} stroke="var(--text-subtle)" strokeWidth="1" strokeDasharray="2 3" />}
          {hover != null && indicator.type !== 'bars' && <circle cx={x(hover)} cy={y(pts[hover])} r="3.5" fill={c} stroke="#fff" strokeWidth="1.5" />}
          {/* x labels */}
          <text x={padL} y={h - 6} style={{ font: '9px var(--font-mono)', fill: 'var(--text-subtle)' }}>{labels ? labels[0] : ''}</text>
          <text x={w - padR} y={h - 6} textAnchor="end" style={{ font: '9px var(--font-mono)', fill: 'var(--text-subtle)' }}>{labels ? labels[n - 1] : 'now'}</text>
        </svg>
        {hover != null && (
          <div style={{
            position: 'absolute', top: 0, left: (100 * x(hover) / w) + '%', transform: 'translateX(' + (hover > n / 2 ? '-105%' : '5%') + ')',
            background: 'var(--surface-inverse)', color: 'var(--text-on-dark)', borderRadius: 'var(--radius-card)', padding: '6px 9px',
            font: '11px var(--font-text)', pointerEvents: 'none', whiteSpace: 'nowrap', boxShadow: 'var(--shadow-md)', zIndex: 5,
          }}>
            <div style={{ font: '600 10px var(--font-mono)', opacity: 0.7 }}>wk of {labels ? labels[hover] : hover + 1}</div>
            <div><span style={{ color: c }}>●</span> {fmtVal(pts[hover])} {indicator.unit}</div>
            {indicator.norm && <div style={{ opacity: 0.75 }}>◌ {indicator.normLabel}: {fmtVal(indicator.norm[hover])}</div>}
          </div>
        )}
      </div>
      <div style={{ display: 'flex', justifyContent: 'space-between', gap: 8, marginTop: 4 }}>
        <span style={{ font: '10px var(--font-text)', color: 'var(--text-subtle)' }}>{indicator.source}</span>
        {indicator.norm && <span style={{ font: '10px var(--font-text)', color: 'var(--text-subtle)', whiteSpace: 'nowrap' }}>- - {indicator.normLabel}</span>}
      </div>
    </div>
  );
}

/* Trend arrow for a series (compares last point to the average of the first half). */
function TrendArrow({ points }) {
  if (!points || points.length < 4) return null;
  const half = points.slice(0, Math.floor(points.length / 2));
  const base = half.reduce(function (s, p) { return s + p; }, 0) / half.length;
  const last = points[points.length - 1];
  const rising = last > base + 2, falling = last < base - 2;
  const icon = rising ? 'trending-up' : falling ? 'trending-down' : 'minus';
  const color = rising ? 'var(--severe-strong)' : falling ? 'var(--calm-strong)' : 'var(--text-subtle)';
  const label = rising ? 'Rising' : falling ? 'Easing' : 'Steady';
  return (
    <span title={label + ' over the last 12 weeks'} style={{ display: 'inline-flex', alignItems: 'center', gap: 4, color: color, font: '600 11px var(--font-text)' }}>
      {Ic(icon, { width: 13, height: 13 })}{label}
    </span>
  );
}

/* Horizontal status stepper for call-for-help lifecycle. */
function CallStepper({ call }) {
  var steps;
  if (call.status === 'declined') {
    steps = [
      { id: 'submitted', label: 'Submitted', at: call.submittedAt },
      { id: 'reviewed', label: 'Reviewed', at: call.reviewedAt },
      { id: 'declined', label: 'Declined', at: call.resolvedAt, tone: 'severe' },
    ];
  } else {
    steps = [
      { id: 'submitted', label: 'Submitted', at: call.submittedAt },
      { id: 'reviewed', label: 'Risk desk review', at: call.reviewedAt },
      { id: 'decision', label: call.status === 'auto_pending' ? 'Org review window' : 'Org decision', at: call.status === 'auto_pending' ? call.reviewedAt : (call.status === 'triggered' ? call.resolvedAt : null) },
      { id: 'triggered', label: 'Funds moved', at: call.status === 'triggered' ? call.resolvedAt : null, tone: 'calm' },
    ];
  }
  var doneCount = steps.filter(function (s) { return !!s.at; }).length;
  return (
    <div style={{ display: 'flex', alignItems: 'flex-start', marginTop: 10 }} aria-label="Request progress">
      {steps.map(function (s, i) {
        const done = !!s.at;
        const isCurrent = !done && i === doneCount;
        const color = done ? (s.tone === 'severe' ? 'var(--severe)' : s.tone === 'calm' ? 'var(--calm)' : 'var(--brand)') : 'var(--border-default)';
        return (
          <React.Fragment key={s.id}>
            {i > 0 && <div style={{ flex: 1, height: 2, background: done ? color : 'var(--border-subtle)', marginTop: 7, minWidth: 14 }} />}
            <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', width: 84, flexShrink: 0 }}>
              <div style={{
                width: 15, height: 15, borderRadius: '50%', boxSizing: 'border-box',
                background: done ? color : 'var(--surface-card)',
                border: '2px solid ' + (done ? color : isCurrent ? 'var(--brand)' : 'var(--border-default)'),
                display: 'flex', alignItems: 'center', justifyContent: 'center',
              }}>
                {done && Ic(s.tone === 'severe' ? 'x' : 'check', { width: 9, height: 9, style: { color: '#fff', strokeWidth: 3.4 } })}
              </div>
              <div style={{ font: (done || isCurrent ? '600 ' : '400 ') + '10px var(--font-text)', color: done || isCurrent ? 'var(--text-strong)' : 'var(--text-subtle)', textAlign: 'center', marginTop: 4, lineHeight: 1.3 }}>{s.label}</div>
              {s.at && <div style={{ font: '9px var(--font-mono)', color: 'var(--text-subtle)', marginTop: 1 }}>{fmtRelative(s.at)}</div>}
            </div>
          </React.Fragment>
        );
      })}
    </div>
  );
}

/* Styled textarea consistent with design-system inputs. */
function Textarea({ label, hint, value, onChange, rows, placeholder, maxLength }) {
  return (
    <div>
      {label && <label style={{ display: 'block', font: '600 12px var(--font-text)', color: 'var(--text-muted)', marginBottom: 6 }}>{label}</label>}
      <textarea value={value} onChange={onChange} rows={rows || 3} placeholder={placeholder} maxLength={maxLength}
        style={{ width: '100%', boxSizing: 'border-box', padding: 10, borderRadius: 'var(--radius-input)', border: '1px solid var(--border-default)', font: '14px/1.5 var(--font-text)', resize: 'vertical', background: 'var(--surface-card)', color: 'var(--text-body)' }} />
      <div style={{ display: 'flex', justifyContent: 'space-between', marginTop: 3 }}>
        {hint ? <div style={{ font: '11px var(--font-text)', color: 'var(--text-subtle)' }}>{hint}</div> : <span />}
        {maxLength && <div style={{ font: '10px var(--font-mono)', color: 'var(--text-subtle)' }}>{(value || '').length}/{maxLength}</div>}
      </div>
    </div>
  );
}

function EmptyState({ icon, text, action }) {
  return (
    <div style={{ padding: 'var(--space-8)', textAlign: 'center', color: 'var(--text-subtle)', border: '1px dashed var(--border-default)', borderRadius: 'var(--radius-card)' }}>
      <div style={{ display: 'flex', justifyContent: 'center', marginBottom: 8 }}>{Ic(icon || 'inbox', { width: 22, height: 22 })}</div>
      <div style={{ font: '13px var(--font-text)', marginBottom: action ? 12 : 0 }}>{text}</div>
      {action}
    </div>
  );
}

/* Toast with tones. setToast('msg') or setToast({ message, tone: 'success'|'info'|'error' }) */
const TOAST_STYLE = {
  success: { icon: 'check-circle', color: 'var(--calm)' },
  info: { icon: 'info', color: 'var(--watch)' },
  error: { icon: 'alert-circle', color: 'var(--severe)' },
};
function Toast({ toast, onDone }) {
  React.useEffect(function () {
    if (!toast) return;
    var t = setTimeout(onDone, 3400);
    return function () { clearTimeout(t); };
  }, [toast]);
  if (!toast) return null;
  const conf = TOAST_STYLE[toast.tone] || TOAST_STYLE.success;
  return (
    <div className="ap-toast" role="status" style={{ position: 'fixed', bottom: 22, left: '50%', transform: 'translateX(-50%)', background: 'var(--surface-inverse)', color: 'var(--text-on-dark)', padding: '10px 18px', borderRadius: 'var(--radius-pill)', font: '13px var(--font-text)', boxShadow: 'var(--shadow-lg)', zIndex: 1100, display: 'flex', alignItems: 'center', gap: 8, maxWidth: '86vw' }}>
      {Ic(conf.icon, { width: 15, height: 15, style: { color: conf.color, flexShrink: 0 } })} {toast.message}
    </div>
  );
}
function useToast() {
  const [toast, setToastRaw] = React.useState(null);
  const setToast = React.useCallback(function (m) {
    setToastRaw(typeof m === 'string' ? { message: m, tone: 'success' } : m);
  }, []);
  return [toast, setToast, <Toast toast={toast} onDone={function () { setToastRaw(null); }} />];
}
