// Sheets: AddHoldingSheet + RuleSheet — controlled forms in side-sheet style.
// Both use shared sheet primitives (overlay, header, fields, chips, footer).

const { useState: useStateS, useMemo: useMemoS, useEffect: useEffectS } = React;
const PS = window.PALETTE;

// ─── Sheet shell ─────────────────────────────────────────
function SheetOverlay({ onClose, children, width = 520 }) {
  // Escape closes
  useEffectS(() => {
    const onKey = e => { if (e.key === 'Escape') onClose(); };
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, [onClose]);
  return (
    <div style={shStyles.overlay} onClick={onClose}>
      <div style={{ ...shStyles.sheet, width }} onClick={e => e.stopPropagation()}>
        {children}
      </div>
    </div>
  );
}

function SheetHeader({ kicker, title, onClose }) {
  return (
    <div style={shStyles.head}>
      <div>
        <div style={shStyles.kicker}>{kicker}</div>
        <div style={shStyles.title}>{title}</div>
      </div>
      <button style={shStyles.closeBtn} onClick={onClose} title="Close (Esc)">✕</button>
    </div>
  );
}

function SheetFooter({ children }) {
  return <div style={shStyles.foot}>{children}</div>;
}

function Field({ label, required, hint, children }) {
  return (
    <div style={shStyles.field}>
      <label style={shStyles.fieldLbl}>
        {label}
        {required && <span style={{ color: PS.bad, marginLeft: 4 }}>*</span>}
      </label>
      {children}
      {hint && <div style={shStyles.hint}>{hint}</div>}
    </div>
  );
}

function TextInput({ value, onChange, placeholder, type = 'text', style }) {
  return (
    <input
      type={type}
      value={value}
      placeholder={placeholder}
      onChange={e => onChange(e.target.value)}
      style={{ ...shStyles.input, ...style }}
    />
  );
}

function ChipSelect({ options, value, onChange, allowAdd = true }) {
  const [draft, setDraft] = useStateS('');
  const items = options.filter(Boolean);
  return (
    <div style={shStyles.chipRow}>
      {items.map(o => (
        <button key={o} type="button"
          onClick={() => onChange(o)}
          style={{
            ...shStyles.chip,
            background: o === value ? PS.bg3 : 'transparent',
            color: o === value ? PS.inkHi : PS.inkMid,
            borderColor: o === value ? PS.borderHi : PS.border,
            fontWeight: o === value ? 600 : 400,
          }}>{o}</button>
      ))}
      {allowAdd && (
        <input type="text" value={draft}
          placeholder="+ add new"
          onChange={e => setDraft(e.target.value)}
          onKeyDown={e => {
            if (e.key === 'Enter' && draft.trim()) {
              e.preventDefault();
              onChange(draft.trim());
              setDraft('');
            }
          }}
          style={shStyles.chipInput} />
      )}
    </div>
  );
}

// ─── Add / Edit Holding Sheet ────────────────────────────
function AddHoldingSheet({ existingPositions, blueprint, onSave, onDelete, onClose, initialHolding, editIndex }) {
  const isEdit = initialHolding != null;
  const [form, setForm] = useStateS(isEdit ? {
    ticker:      initialHolding.ticker      || '',
    company:     initialHolding.company     || '',
    shares:      initialHolding.shares > 0 ? String(initialHolding.shares) : '',
    amount_usd:  initialHolding.amount_usd  > 0 ? String(initialHolding.amount_usd) : '',
    sector:      initialHolding.sector      || '',
    theme:       initialHolding.theme       || '',
    strategy:    initialHolding.strategy    || 'Growth',
    risk_bucket: initialHolding.risk_bucket || 'Core',
    account:     initialHolding.account     || 'Brokerage',
    custom_tags: initialHolding.custom_tags || '',
    notes:       initialHolding.notes       || '',
  } : {
    ticker: '', company: '', shares: '', amount_usd: '',
    sector: '', theme: '', strategy: 'Growth', risk_bucket: 'Core',
    account: 'Brokerage', custom_tags: '', notes: '',
  });
  const [price, setPrice] = useStateS(null);
  const [priceError, setPriceError] = useStateS(null);
  const [fetching, setFetching] = useStateS(false);

  const isCash = isEdit && initialHolding.ticker === 'CASH';

  const sectors    = useMemoS(() => {
    const fromBlueprint = blueprint.filter(r => r.group_type === 'sector' && r.group_name !== 'Cash').map(r => r.group_name);
    const fromPositions = existingPositions.filter(p => p.ticker !== 'CASH').map(p => p.sector).filter(Boolean);
    return [...new Set([...fromBlueprint, ...fromPositions])].sort();
  }, [existingPositions, blueprint]);

  const strategies = useMemoS(() => {
    const fromBlueprint = blueprint.filter(r => r.group_type === 'strategy' && r.group_name !== 'Cash').map(r => r.group_name);
    const fromPositions = existingPositions.filter(p => p.ticker !== 'CASH').map(p => p.strategy).filter(Boolean);
    return [...new Set([...fromBlueprint, ...fromPositions])].sort();
  }, [existingPositions, blueprint]);

  // If user types a ticker that already exists, pre-fill from it
  const set = (k, v) => setForm(f => ({ ...f, [k]: v }));
  const setTicker = (v) => {
    const upper = v.toUpperCase();
    const existing = existingPositions.find(p => p.ticker === upper);
    if (existing && form.ticker !== upper) {
      setForm(f => ({
        ...f, ticker: upper,
        company: f.company || existing.company || '',
        sector: f.sector || existing.sector || '',
        theme:  f.theme  || existing.theme  || '',
        strategy: f.strategy === 'Growth' && existing.strategy ? existing.strategy : f.strategy,
        risk_bucket: f.risk_bucket === 'Core' && existing.risk_bucket ? existing.risk_bucket : f.risk_bucket,
        account: existing.account || f.account,
      }));
    } else {
      set('ticker', upper);
    }
  };

  async function getPrice() {
    if (!form.ticker) return;
    setFetching(true); setPriceError(null);
    try {
      const p = await window.fetchTickerPrice(form.ticker);
      setPrice(p);
    } catch (e) {
      setPriceError(e.message || 'price unavailable');
    } finally {
      setFetching(false);
    }
  }

  // Computed value: shares × price (if available); falls back to manual amount
  const sharesNum  = Number(form.shares) || 0;
  const manualAmt  = Number(form.amount_usd) || 0;
  const computed   = price && sharesNum > 0 ? price * sharesNum : null;
  const effective  = computed != null ? computed : manualAmt;
  const usingComputed = computed != null;

  // Blueprint impact preview
  const totalNow = useMemoS(() => existingPositions.reduce((s, p) => s + p.amount_usd, 0), [existingPositions]);
  const previewChecks = useMemoS(() => {
    if (!effective || !form.ticker) return null;
    const template = {
      ticker: form.ticker.toUpperCase(),
      sector: form.sector || 'Uncategorized',
      theme: form.theme || 'Uncategorized',
      strategy: form.strategy || 'Growth',
      risk_bucket: form.risk_bucket || 'Core',
    };
    const next = [...existingPositions, { ...template, amount_usd: effective, shares: sharesNum, company: form.company || '' }];
    const before = window.evaluateBlueprint(existingPositions, blueprint, null);
    const after  = window.evaluateBlueprint(next, blueprint, null);
    return { before, after };
  }, [existingPositions, blueprint, form, effective, sharesNum]);

  const impactRows = useMemoS(() => {
    if (!previewChecks) return [];
    return previewChecks.after.map((a, i) => {
      const b = previewChecks.before[i];
      const delta = a.pct - b.pct;
      if (Math.abs(delta) < 0.05) return null;
      return { rule: a, delta, before: b };
    }).filter(Boolean).sort((a, b) => Math.abs(b.delta) - Math.abs(a.delta)).slice(0, 4);
  }, [previewChecks]);

  const canSave = form.ticker && (sharesNum > 0 || manualAmt > 0);

  function submit() {
    if (!canSave) return;
    const item = {
      ticker: form.ticker.toUpperCase(),
      company: form.company,
      shares: sharesNum,
      amount_usd: effective,
      sector: form.sector || 'Uncategorized',
      theme: form.theme || '',
      strategy: form.strategy || 'Growth',
      risk_bucket: form.risk_bucket || 'Core',
      account: form.account || 'Brokerage',
      custom_tags: form.custom_tags || '',
      notes: form.notes || '',
    };
    onSave(item, isEdit ? editIndex : null);
    onClose();
  }

  function confirmDelete() {
    if (window.confirm(`Remove ${form.ticker} from your holdings?`)) {
      onDelete(editIndex);
      onClose();
    }
  }

  // ── Cash: simplified single-field form ──────────────────
  if (isCash) {
    const cashAmt = window.toNum(form.amount_usd);
    return (
      <SheetOverlay onClose={onClose}>
        <SheetHeader kicker="cash position" title="Cash Balance" onClose={onClose} />
        <div style={shStyles.body}>
          <Field label="cash balance (USD)" required hint="Enter your total uninvested cash">
            <TextInput
              type="number"
              value={form.amount_usd}
              onChange={v => set('amount_usd', v)}
              placeholder="0"
              style={{ fontFamily: 'IBM Plex Mono, monospace', fontSize: 18 }}
            />
          </Field>
          {cashAmt > 0 && (
            <div style={{ fontFamily: 'IBM Plex Mono, monospace', fontSize: 13, color: PS.ok }}>
              ✓ {window.fmtMoney(cashAmt)}
            </div>
          )}
        </div>
        <SheetFooter>
          <button
            style={{ ...shStyles.btnPrimary, opacity: cashAmt >= 0 ? 1 : 0.5 }}
            onClick={() => { onSave({ ...initialHolding, amount_usd: cashAmt }, editIndex); onClose(); }}
          >
            save
          </button>
          <div style={{ flex: 1 }} />
          <button style={shStyles.btnGhost} onClick={onClose}>cancel</button>
        </SheetFooter>
      </SheetOverlay>
    );
  }

  return (
    <SheetOverlay onClose={onClose}>
      <SheetHeader kicker={isEdit ? 'edit holding' : 'new entry'} title={isEdit ? form.ticker : '+ Add Holding'} onClose={onClose} />
      <div style={shStyles.body}>
        <Field label="ticker" required>
          <TextInput value={form.ticker} onChange={setTicker} placeholder="AAPL" style={{ textTransform: 'uppercase', fontFamily: 'IBM Plex Mono, monospace' }} />
        </Field>
        <Field label="company">
          <TextInput value={form.company} onChange={v => set('company', v)} placeholder="Apple Inc." />
        </Field>

        <PriceCard
          ticker={form.ticker}
          price={price}
          fetching={fetching}
          error={priceError}
          onFetch={getPrice}
          shares={form.shares}
          onSharesChange={v => set('shares', v)}
          manualAmount={form.amount_usd}
          onManualChange={v => set('amount_usd', v)}
          effective={effective}
          usingComputed={usingComputed}
        />

        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 10 }}>
          <Field label="sector">
            <ChipSelect options={sectors} value={form.sector} onChange={v => set('sector', v)} allowAdd={false} />
          </Field>
          <Field label="strategy">
            <ChipSelect options={strategies} value={form.strategy} onChange={v => set('strategy', v)} allowAdd={false} />
          </Field>
        </div>

        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 10 }}>
          <Field label="account">
            <TextInput value={form.account} onChange={v => set('account', v)} placeholder="Brokerage" />
          </Field>
        </div>

        <Field label="notes">
          <TextInput value={form.notes} onChange={v => set('notes', v)} placeholder="Optional notes" />
        </Field>

        {effective > 0 && impactRows.length > 0 && (
          <div style={shStyles.impactCard}>
            <div style={shStyles.impactLabel}>blueprint impact (preview)</div>
            <div style={shStyles.impactRow}>
              <span>total value</span>
              <span><b style={{ color: PS.inkHi }}>{window.fmtMoney(totalNow)} → {window.fmtMoney(totalNow + effective)}</b></span>
            </div>
            {impactRows.map(({ rule, delta, before }) => {
              const flipped = rule.status !== before.status;
              const color = rule.status === 'over' ? PS.bad : rule.status === 'under' ? PS.warn : PS.ok;
              return (
                <div key={rule.group_type + ':' + rule.group_name} style={shStyles.impactRow}>
                  <span>{rule.group_type === 'risk_bucket' ? 'risk' : rule.group_type}: {rule.group_name}</span>
                  <span style={{ color: flipped ? color : PS.inkMid }}>
                    {before.pct.toFixed(1)}% → <b style={{ color }}>{rule.pct.toFixed(1)}%</b>
                    {flipped && <span style={{ color, marginLeft: 6 }}>→ {rule.status.toUpperCase()}</span>}
                  </span>
                </div>
              );
            })}
          </div>
        )}
      </div>
      <SheetFooter>
        <button style={{ ...shStyles.btnPrimary, opacity: canSave ? 1 : 0.5, cursor: canSave ? 'pointer' : 'not-allowed' }}
          onClick={submit} disabled={!canSave}>
          {isEdit ? 'save changes' : 'save holding'}
        </button>
        {isEdit && (
          <button style={shStyles.btnDanger} onClick={confirmDelete}>remove</button>
        )}
        <div style={{ flex: 1 }} />
        <button style={shStyles.btnGhost} onClick={onClose}>cancel</button>
      </SheetFooter>
    </SheetOverlay>
  );
}

// ─── Price card inside Add Holding ───────────────────────
function PriceCard({ ticker, price, fetching, error, onFetch, shares, onSharesChange, manualAmount, onManualChange, effective, usingComputed }) {
  return (
    <div style={shStyles.priceCard}>
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 10 }}>
        <span style={shStyles.fieldLbl}>position size</span>
        <button onClick={onFetch} disabled={!ticker || fetching} style={{
          ...shStyles.miniBtn,
          opacity: !ticker || fetching ? 0.4 : 1,
          cursor: !ticker || fetching ? 'not-allowed' : 'pointer',
        }}>
          {fetching ? '↻ fetching…' : price != null ? '↻ refresh price' : '↻ get price'}
        </button>
      </div>

      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 10 }}>
        <Field label="shares">
          <TextInput type="number" value={shares} onChange={onSharesChange} placeholder="0" />
        </Field>
        <Field label={usingComputed ? 'value · computed' : 'or manual value (USD)'}>
          {usingComputed ? (
            <div style={{ ...shStyles.input, color: PS.inkHi, fontFamily: 'IBM Plex Mono, monospace', background: PS.bg2, border: `1px solid ${PS.borderHi}` }}>
              {window.fmtMoney(effective)}
            </div>
          ) : (
            <TextInput type="number" value={manualAmount} onChange={onManualChange} placeholder="0" />
          )}
        </Field>
      </div>

      {price != null && (
        <div style={{ marginTop: 8, fontFamily: 'IBM Plex Mono, monospace', fontSize: 11, color: PS.ok, display: 'flex', justifyContent: 'space-between' }}>
          <span>✓ price ${price.toFixed(2)} · {ticker.toUpperCase()}</span>
          {Number(shares) > 0 && (
            <span style={{ color: PS.inkMid }}>{shares} × ${price.toFixed(2)} = <b style={{ color: PS.inkHi }}>{window.fmtMoney(effective)}</b></span>
          )}
        </div>
      )}
      {error && (
        <div style={{ marginTop: 8, fontFamily: 'IBM Plex Mono, monospace', fontSize: 11, color: PS.warn }}>
          ⚠ {error} · use manual value below
        </div>
      )}
    </div>
  );
}

// ─── Rule Sheet (add + edit) ──────────────────────────────
function RuleSheet({ initialRule, initialIndex, positions, blueprint, onSave, onDelete, onClose }) {
  const isEdit = initialRule != null;
  const [form, setForm] = useStateS(initialRule || {
    group_type: 'sector', group_name: '', target_pct: 10, min_pct: 0, max_pct: 20, notes: '',
  });
  const set = (k, v) => setForm(f => ({ ...f, [k]: v }));

  // Live preview using this rule's settings
  const preview = useMemoS(() => {
    if (!form.group_name) return null;
    const ruleArr = [{
      ...form,
      target_pct: Number(form.target_pct) || 0,
      min_pct: Number(form.min_pct) || 0,
      max_pct: Number(form.max_pct) || 0,
    }];
    return window.evaluateBlueprint(positions, ruleArr, null)[0];
  }, [form, positions]);

  const canSave = form.group_name && form.group_type;
  const groupTypes = ['position', 'sector', 'strategy'];

  function submit() {
    if (!canSave) return;
    onSave({
      ...form,
      target_pct: Number(form.target_pct) || 0,
      min_pct: Number(form.min_pct) || 0,
      max_pct: Number(form.max_pct) || 0,
    }, initialIndex);
    onClose();
  }

  function confirmDelete() {
    if (window.confirm(`Delete rule for ${form.group_name}?`)) {
      onDelete(initialIndex);
      onClose();
    }
  }

  return (
    <SheetOverlay onClose={onClose}>
      <SheetHeader
        kicker={isEdit ? 'editing rule' : 'new rule'}
        title={isEdit ? form.group_name : '+ Add Rule'}
        onClose={onClose}
      />
      <div style={shStyles.body}>
        <Field label="group type">
          <ChipSelect options={groupTypes.map(t => t === 'risk_bucket' ? 'risk_bucket' : t)}
            value={form.group_type} onChange={v => set('group_type', v)} allowAdd={false} />
        </Field>

        <Field label="group name">
          <TextInput value={form.group_name} onChange={v => set('group_name', v)} placeholder="e.g. Technology" />
        </Field>

        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: 10 }}>
          <Field label="min %">
            <TextInput type="number" value={form.min_pct} onChange={v => set('min_pct', v)} placeholder="0" style={{ fontFamily: 'IBM Plex Mono, monospace' }} />
          </Field>
          <Field label="target %">
            <TextInput type="number" value={form.target_pct} onChange={v => set('target_pct', v)} placeholder="10" style={{ fontFamily: 'IBM Plex Mono, monospace' }} />
          </Field>
          <Field label="max %">
            <TextInput type="number" value={form.max_pct} onChange={v => set('max_pct', v)} placeholder="20" style={{ fontFamily: 'IBM Plex Mono, monospace' }} />
          </Field>
        </div>

        <Field label="notes">
          <TextInput value={form.notes || ''} onChange={v => set('notes', v)} placeholder="Why this rule exists" />
        </Field>

        {preview && (
          <div style={shStyles.bandPreview}>
            <div style={shStyles.impactLabel}>band preview · live</div>
            <BandViz check={preview} />
            <div style={{ marginTop: 12, fontFamily: 'IBM Plex Mono, monospace', fontSize: 12,
              color: preview.status === 'over' ? PS.bad : preview.status === 'under' ? PS.warn : PS.ok }}>
              {window.strictHeadline(preview)}
            </div>
          </div>
        )}
      </div>
      <SheetFooter>
        <button style={{ ...shStyles.btnPrimary, opacity: canSave ? 1 : 0.5, cursor: canSave ? 'pointer' : 'not-allowed' }}
          onClick={submit} disabled={!canSave}>
          {isEdit ? 'save changes' : 'create rule'}
        </button>
        {isEdit && (
          <button style={shStyles.btnDanger} onClick={confirmDelete}>delete rule</button>
        )}
        <div style={{ flex: 1 }} />
        <button style={shStyles.btnGhost} onClick={onClose}>cancel</button>
      </SheetFooter>
    </SheetOverlay>
  );
}

// ─── Band preview viz (used in RuleSheet) ────────────────
function BandViz({ check }) {
  const c = check;
  const hi = Math.max(Number(c.max_pct) || 0, c.pct, 10) * 1.15;
  const px = pos => `${Math.min(98, Math.max(0, (pos / hi) * 100))}%`;
  const color = c.status === 'over' ? PS.bad : c.status === 'under' ? PS.warn : PS.ok;
  return (
    <>
      <div style={{ position: 'relative', height: 12, background: PS.bg3, borderRadius: 3, marginTop: 8 }}>
        <div style={{ position: 'absolute', top: 0, bottom: 0,
          left: px(Number(c.min_pct) || 0),
          width: `calc(${px(Number(c.max_pct) - Number(c.min_pct) || 0)})`,
          background: 'rgba(125,211,252,0.12)',
          borderLeft: '1px solid rgba(125,211,252,0.4)',
          borderRight: '1px solid rgba(125,211,252,0.4)' }} />
        <div style={{ position: 'absolute', top: -2, bottom: -2, left: px(Number(c.target_pct) || 0), width: 1, background: PS.inkMid }} />
        <div style={{ position: 'absolute', top: -3, bottom: -3, left: px(c.pct), width: 3, background: color, borderRadius: 1 }} />
      </div>
      <div style={{ display: 'flex', justifyContent: 'space-between', fontFamily: 'IBM Plex Mono, monospace', fontSize: 10, color: PS.inkLo, marginTop: 6 }}>
        <span>{Number(c.min_pct) || 0}% min</span>
        <span>target {Number(c.target_pct) || 0}%</span>
        <span>{Number(c.max_pct) || 0}% max</span>
      </div>
    </>
  );
}

// ─── Styles ──────────────────────────────────────────────
const shStyles = {
  overlay: {
    position: 'fixed', inset: 0, background: 'rgba(6,8,11,0.6)', backdropFilter: 'blur(3px)',
    display: 'flex', justifyContent: 'flex-end', zIndex: 1000,
  },
  sheet: {
    height: '100%', background: PS.bg1, borderLeft: `1px solid ${PS.borderHi}`,
    display: 'flex', flexDirection: 'column', boxShadow: '-12px 0 40px rgba(0,0,0,0.4)',
    overflow: 'hidden',
  },
  head: { display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', padding: '16px 20px', borderBottom: `1px solid ${PS.border}` },
  kicker: { fontFamily: 'IBM Plex Mono, monospace', fontSize: 10, color: PS.inkLo, textTransform: 'uppercase', letterSpacing: '0.12em' },
  title: { fontSize: 20, fontWeight: 600, color: PS.inkHi, marginTop: 4 },
  closeBtn: { width: 32, height: 32, background: 'transparent', border: 'none', color: PS.inkLo, fontSize: 16, cursor: 'pointer', borderRadius: 6 },
  body: { padding: 20, display: 'flex', flexDirection: 'column', gap: 14, overflowY: 'auto', flex: 1 },
  foot: { display: 'flex', gap: 10, padding: '14px 20px', borderTop: `1px solid ${PS.border}`, background: PS.bg0 },

  field: { display: 'flex', flexDirection: 'column', gap: 5 },
  fieldLbl: { fontFamily: 'IBM Plex Mono, monospace', fontSize: 10, color: PS.inkLo, textTransform: 'uppercase', letterSpacing: '0.1em', whiteSpace: 'nowrap' },
  hint: { fontFamily: 'IBM Plex Mono, monospace', fontSize: 10, color: PS.inkLo, marginTop: 2 },
  input: {
    background: PS.bg0, border: `1px solid ${PS.border}`, borderRadius: 6,
    padding: '9px 12px', color: PS.inkHi, fontFamily: 'Inter, sans-serif', fontSize: 13, outline: 'none',
    width: '100%', boxSizing: 'border-box',
  },

  chipRow: { display: 'flex', flexWrap: 'wrap', gap: 6, padding: '4px 0' },
  chip: {
    padding: '5px 11px', border: '1px solid', borderRadius: 14,
    fontFamily: 'IBM Plex Mono, monospace', fontSize: 11, cursor: 'pointer', whiteSpace: 'nowrap',
    background: 'transparent',
  },
  chipInput: {
    padding: '5px 11px', border: `1px dashed ${PS.border}`, borderRadius: 14,
    fontFamily: 'IBM Plex Mono, monospace', fontSize: 11, background: 'transparent',
    color: PS.inkLo, outline: 'none', width: 90,
  },

  priceCard: { padding: 14, background: PS.bg0, border: `1px solid ${PS.border}`, borderRadius: 8 },
  miniBtn: { background: PS.bg2, color: PS.inkHi, border: `1px solid ${PS.border}`, padding: '5px 10px', borderRadius: 6, fontFamily: 'IBM Plex Mono, monospace', fontSize: 11, cursor: 'pointer', whiteSpace: 'nowrap' },

  impactCard: { padding: 14, background: PS.bg0, border: `1px dashed ${PS.border}`, borderRadius: 8, display: 'flex', flexDirection: 'column', gap: 6 },
  impactLabel: { fontFamily: 'IBM Plex Mono, monospace', fontSize: 10, color: PS.inkLo, textTransform: 'uppercase', letterSpacing: '0.1em', marginBottom: 4 },
  impactRow: { display: 'flex', justifyContent: 'space-between', fontFamily: 'IBM Plex Mono, monospace', fontSize: 11, color: PS.inkMid },

  bandPreview: { padding: 14, background: PS.bg0, border: `1px solid ${PS.border}`, borderRadius: 8 },

  btnPrimary: { background: PS.phosphor, color: PS.bg0, border: 'none', padding: '9px 16px', borderRadius: 6, fontFamily: 'IBM Plex Mono, monospace', fontSize: 12, fontWeight: 600, whiteSpace: 'nowrap' },
  btnGhost: { background: 'transparent', color: PS.inkMid, border: `1px solid ${PS.border}`, padding: '9px 16px', borderRadius: 6, fontFamily: 'IBM Plex Mono, monospace', fontSize: 12, cursor: 'pointer', whiteSpace: 'nowrap' },
  btnDanger: { background: 'transparent', color: PS.bad, border: `1px solid ${PS.bad}`, padding: '9px 16px', borderRadius: 6, fontFamily: 'IBM Plex Mono, monospace', fontSize: 12, cursor: 'pointer', whiteSpace: 'nowrap' },
};

Object.assign(window, { AddHoldingSheet, RuleSheet });
