// "Price your launch" — a three-step builder.
//   1. Your product: what it costs you and the shelf price you have in mind.
//   2. The road to the shelf: every cost between the factory and the shopper lands
//      one by one on a stack, so the brand sees what cost-plus pricing hides.
//   3. Working with blyzr: services and monthly volume, spread over each unit.
// Numbers come from price-model.js (the founder's TikTok tab) and the website's
// plan-builder fees (US_PLAN in screens-6.jsx). English only for now.

const { useState: pbS, useEffect: pbE, useMemo: pbM, useRef: pbR } = React;

const PB_REDUCED = typeof window !== 'undefined' && window.matchMedia
  && window.matchMedia('(prefers-reduced-motion: reduce)').matches;

// [lightness, chroma, hue] per group; sub-layers alternate lightness so neighbours read apart.
const PB_COL = {
  product: [0.36, 0.012, 80],
  import:  [0.72, 0.13, 240],
  deliver: [0.74, 0.14, 300],
  sell:    [0.80, 0.15, 60],
  blyzr:   [0.25, 0.05, 140],
  keep:    [0.86, 0.21, 135],
};
const pbColor = (group, i = 0) => {
  const [L, C, H] = PB_COL[group];
  return `oklch(${(L + (i % 2) * 0.06).toFixed(3)} ${C} ${H})`;
};

const pbMoney = (usdValue, cur, plus) => {
  const v = usdValue * (cur === 'SAR' ? PRICE_MODEL.SAR_PER_USD : 1);
  if (!isFinite(v)) return '—';
  const abs = Math.abs(v);
  const d = abs >= 1000 ? 0 : 2;
  const s = abs.toLocaleString('en-US', { minimumFractionDigits: d, maximumFractionDigits: d });
  const sym = cur === 'SAR' ? 'SAR ' : '$';
  return (v < -0.004 ? '−' : plus && v > 0.004 ? '+' : '') + sym + s;
};
const pbPct = (f) => `${Math.round(f * 1000) / 10}%`;
const pbNum = (v) => Math.round(v).toLocaleString('en-US');

// a number that eases to its new value
const PbNum = ({ value, format, ms = 520 }) => {
  const [shown, setShown] = pbS(value);
  const from = pbR(value);
  const raf = pbR(0);
  pbE(() => {
    if (PB_REDUCED || !isFinite(value) || !isFinite(from.current)) { setShown(value); from.current = value; return undefined; }
    const a = from.current, b = value, t0 = performance.now();
    const tick = (t) => {
      const p = Math.min(1, (t - t0) / ms), e = 1 - Math.pow(1 - p, 3);
      const cur = a + (b - a) * e;
      from.current = cur; setShown(cur);
      if (p < 1) raf.current = requestAnimationFrame(tick);
    };
    raf.current = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf.current);
  }, [value]);
  return <span>{format(shown)}</span>;
};

// text box that keeps what the person is typing; commits on every valid keystroke
const PbInput = ({ value, onValue, suffix, prefix, width, label, id }) => {
  const [txt, setTxt] = pbS(null);
  const fmt = (v) => String(Math.round(v * 100) / 100);
  return (
    <span className="pb-input" style={width ? { width } : undefined}>
      {prefix && <i>{prefix}</i>}
      <input id={id} aria-label={label} inputMode="decimal" value={txt != null ? txt : fmt(value)}
        onFocus={(e) => { setTxt(fmt(value)); e.target.select(); }}
        onChange={(e) => { setTxt(e.target.value); const v = parseFloat(e.target.value); if (isFinite(v) && v >= 0) onValue(v); }}
        onBlur={() => setTxt(null)} />
      {suffix && <i>{suffix}</i>}
    </span>
  );
};

const PbSlider = ({ label, hint, value, min, max, step, onValue, display, input }) => (
  <div className="pb-field">
    <div className="pb-field-top">
      <label className="pb-field-label">{label}</label>
      {input}
    </div>
    <input type="range" className="calc-slider" min={min} max={max} step={step} value={Math.min(max, Math.max(min, value))}
      aria-label={label} onChange={(e) => onValue(Number(e.target.value))} />
    <div className="pb-field-foot"><span>{display(min)}</span>{hint && <em>{hint}</em>}<span>{display(max)}</span></div>
  </div>
);

const PriceBuilder = ({ onLead }) => {
  const [step, setStep] = pbS(1);
  const [cost, setCost] = pbS(3);
  const [price, setPrice] = pbS(10);
  const [profitPct, setProfitPct] = pbS(10);
  const [adj, setAdj] = pbS({});
  const [volume, setVolume] = pbS(1000);
  const [sel, setSel] = pbS(() => { const o = {}; US_ITEMS.forEach((it) => { o[it.id] = !!it.on; }); return o; });
  const [containers, setContainers] = pbS(2);
  const [cur, setCur] = pbS('USD');
  const [hot, setHot] = pbS(null);
  const [revealN, setRevealN] = pbS(1);
  const [shownBlyzr, setShownBlyzr] = pbS(false);
  const [openAdj, setOpenAdj] = pbS(false);
  const rootRef = pbR(null);
  const fx = cur === 'SAR' ? PRICE_MODEL.SAR_PER_USD : 1;
  const M = (v, plus) => pbMoney(v, cur, plus);

  // the journey lines in the order they land; storage is priced in step 3
  const revealable = PRICE_MODEL.LINES.map((l) => l.id).filter((id) => id !== 'storage');

  pbE(() => {
    if (step === 1) { setRevealN(1); return undefined; }
    if (PB_REDUCED) { setRevealN(revealable.length); return undefined; }
    if (revealN >= revealable.length) return undefined;
    const t = setInterval(() => setRevealN((n) => (n >= revealable.length ? n : n + 1)), 240);
    return () => clearInterval(t);
  }, [step, revealN >= revealable.length]);

  pbE(() => {
    if (step < 3) { setShownBlyzr(false); return undefined; }
    const t = setTimeout(() => setShownBlyzr(true), PB_REDUCED ? 0 : 420);
    return () => clearTimeout(t);
  }, [step]);

  const usesBlyzrStorage = !!(sel.storage || sel.fulfil);
  const services = pbM(() => PRICE_MODEL.resolveServices(US_PLAN, sel, containers), [sel, containers]);
  const overrides = { ...adj };
  if (step >= 3 && usesBlyzrStorage) overrides.storage = 0;
  const r = PRICE_MODEL.compute({
    cost, price, profitPct: profitPct / 100, overrides,
    blyzr: step >= 3 ? { units: volume, services } : null,
  });

  const shown = new Set(step === 1 ? ['cost'] : revealable.slice(0, revealN));
  if (step >= 2) shown.add('storage');
  const allIn = step >= 2 && revealN >= revealable.length;

  // ---- the stack ----
  const order = ['product', 'import', 'deliver', 'sell'];
  const segs = [];
  order.forEach((gid) => r.lines.filter((l) => l.group === gid).forEach((l, i) => {
    segs.push({ id: l.id, group: gid, i, amount: shown.has(l.id) ? l.amount : 0 });
  }));
  segs.push({ id: 'blyzr', group: 'blyzr', i: 0, amount: step >= 3 && shownBlyzr ? r.blyzrPerUnit : 0 });
  const shownSum = segs.reduce((a, s) => a + s.amount, 0);
  const target = allIn ? r.targetProfit : 0;
  const scale = Math.max(r.price, shownSum + target, 0.5) * 1.08;
  const pct = (v) => `${Math.max(0, (v / scale) * 100)}%`;
  let cum = 0;
  const placed = segs.map((s) => { const b = cum; cum += s.amount; return { ...s, bottom: b }; });
  const keepAmt = Math.max(0, r.price - shownSum);
  const short = allIn && r.price < shownSum + r.targetProfit - 1e-9;
  const over = shownSum > r.price;

  // ---- what to say ----
  const below = r.net < -0.004;
  const losing = r.profit < -0.004;
  const afterFees = step >= 3 ? ' after our fees' : '';
  const verdict = step === 1
    ? null
    : !allIn ? 'Watch what each stop adds…'
    : !below ? `At ${M(r.price)} you keep ${M(r.profit)} a unit${afterFees}, which meets your ${pbPct(r.profitPct)} target.`
    : isFinite(r.targetPrice)
      ? `At ${M(r.price)} you're ${M(-r.net)} a unit short of your ${pbPct(r.profitPct)} target${step >= 3 ? ` once our fees are in, at ${pbNum(volume)} units a month` : ''}. The lowest price that pays for everything and leaves it is ${M(r.targetPrice)}.`
      : 'These rates add up to more than the whole price, so no shelf price can cover them. Lower a rate in the assumptions.';

  const setRate = (id, v) => setAdj((a) => ({ ...a, [id]: v }));
  const rateOf = (id) => (adj[id] != null ? adj[id] : PRICE_MODEL.LINES.find((l) => l.id === id).value);
  const fixPrice = () => { if (isFinite(r.targetPrice)) setPrice(Math.ceil(r.targetPrice * 100) / 100); };

  const verdictBox = (
    <div className={`pb-verdict ${below ? (losing ? 'neg' : 'mid') : 'ok'}`} role="status" aria-live="polite">
      <p>{verdict}</p>
      {allIn && below && isFinite(r.targetPrice) && (
        <button className="pill pill-lime" onClick={fixPrice}>Set my price to {M(Math.ceil(r.targetPrice * 100) / 100)}</button>
      )}
    </div>
  );

  const priceMax = Math.max(30, Math.ceil((cost * 10) / 10) * 10);
  const costMax = 100;

  const basis = (l) => {
    if (l.id === 'cost') return 'per unit, ex-factory';
    if (l.id === 'storage') return step < 3 ? 'priced in step 3' : usesBlyzrStorage ? 'we handle it, see below' : 'your own cost per unit';
    if (l.kind === 'pctCost') return `${pbPct(l.value)} of your cost`;
    if (l.kind === 'pctPrice') return `${pbPct(l.value)} of the shelf price`;
    return 'per unit';
  };

  const lineRows = [];
  order.forEach((gid) => {
    const g = r.groups.find((x) => x.id === gid);
    r.lines.filter((l) => l.group === gid).forEach((l, i) => {
      lineRows.push({ key: l.id, head: i === 0 ? g.label : null, group: gid, i, id: l.id, label: l.label, basis: basis(l), amount: l.amount, in: shown.has(l.id) });
    });
  });
  if (step >= 3) {
    lineRows.push({ key: 'blyzr', head: 'Working with blyzr', group: 'blyzr', i: 0, id: 'blyzr', label: 'Our fees, per unit',
      basis: r.monthly ? `${M(r.monthly.blyzrBill)} a month over ${pbNum(volume)} units` : '', amount: r.blyzrPerUnit, in: shownBlyzr });
  }

  // .canvas is the scroller on this site, so scroll the builder into view, not the window
  const goStep = (s) => {
    setStep(s);
    requestAnimationFrame(() => {
      if (rootRef.current) rootRef.current.scrollIntoView({ block: 'start', behavior: PB_REDUCED ? 'auto' : 'smooth' });
    });
  };

  const sendPlan = () => {
    const m = r.monthly;
    const names = services.map((s) => s.name).join(', ') || 'none selected';
    const L = (id) => r.byId[id].amount;
    const lines = [
      'Price your launch (TikTok Shop), figures in USD',
      `• Product cost ${PRICE_MODEL_USD(cost)} · shelf price ${PRICE_MODEL_USD(price)} · profit target ${pbPct(r.profitPct)}`,
      `• Per unit: duty ${PRICE_MODEL_USD(L('duty'))}, shipping ${PRICE_MODEL_USD(L('intl'))}, importer ${PRICE_MODEL_USD(L('ior'))}, delivery ${PRICE_MODEL_USD(L('domestic'))}, marketplace and marketing ${PRICE_MODEL_USD(r.pctOfPrice * price)}`,
      `• Volume: ${pbNum(volume)} units a month`,
      `• blyzr services: ${names}`,
      `• blyzr cost: ${PRICE_MODEL_USD(m.setup)} once, then ${PRICE_MODEL_USD(m.blyzrBill)} a month (${PRICE_MODEL_USD(r.blyzrPerUnit)} a unit)`,
      `• You keep: ${PRICE_MODEL_USD(r.profit)} a unit, ${PRICE_MODEL_USD(m.profit)} a month`,
    ];
    onLead({ title: 'Request your US plan', interest: 'Sell in the US', kind: 'quote', summary: lines.join('\n') });
  };

  const resultBox = step === 3 && r.monthly ? (
    <div className="pb-result" aria-live="polite">
                  <p>
                    {r.monthly.profit >= 0
                      ? <>At <b>{pbNum(volume)}</b> units a month you keep about <b>{M(r.monthly.profit)}</b> a month after our fees.</>
                      : <>At <b>{pbNum(volume)}</b> units a month this loses about <b>{M(-r.monthly.profit)}</b> a month.</>}
                    {' '}
                    {r.monthly.profit < 0
                      ? (isFinite(r.monthly.breakEvenUnits)
                          ? <>You break even from about <b>{pbNum(r.monthly.breakEvenUnits)}</b> units a month, or at a shelf price of <b>{M(r.breakEvenPrice)}</b>.</>
                          : <>Raise the shelf price to at least <b>{M(r.breakEvenPrice)}</b> to break even at this volume.</>)
                      : isFinite(r.monthly.paybackMonths) && r.monthly.setup > 0
                        ? <>The one-time setup of <b>{M(r.monthly.setup)}</b> pays back in about <b>{Math.max(1, Math.ceil(r.monthly.paybackMonths))}</b> {Math.ceil(r.monthly.paybackMonths) <= 1 ? 'month' : 'months'}.</>
                        : null}
                  </p>
                  <button className="pill pill-ink" onClick={sendPlan} disabled={services.length === 0}>Send me this plan</button>
                  <small>Indicative. A person on the team goes through the real numbers with you.</small>
                </div>
  ) : null;

  const stepsMeta = [['Your product', 1], ['The road to the shelf', 2], ['Working with us', 3]];
  const keepClass = step === 1 ? 'ok' : losing ? 'neg' : below ? 'mid' : 'ok';

  return (
    <div className="pb" data-step={step} ref={rootRef}>
      <div className="pb-top">
        <ol className="pb-steps" aria-label="Steps">
          {stepsMeta.map(([label, n]) => (
            <li key={n} className={step === n ? 'on' : step > n ? 'done' : ''}>
              <button onClick={() => goStep(n)} aria-current={step === n ? 'step' : undefined}>
                <b>{n}</b><span>{label}</span>
              </button>
            </li>
          ))}
        </ol>
        <div className="pb-cur" role="group" aria-label="Currency">
          {['USD', 'SAR'].map((c) => (
            <button key={c} className={cur === c ? 'on' : ''} onClick={() => setCur(c)} aria-pressed={cur === c}>{c}</button>
          ))}
        </div>
      </div>

      <div className="pb-grid">
        <div className="pb-left">
          {step === 1 && (
            <section className="pb-step" key="s1">
              <p className="eyebrow">Step 1 · your product</p>
              <h2 className="pb-h">Start with what it <em>costs you.</em></h2>
              <p className="pb-sub">What does one unit cost to make and hand to a shipper, and what shelf price do you have in mind? The numbers start from a $3 product at $10. Change both.</p>
              <PbSlider label="Cost per unit" hint="ex-factory" value={cost * fx} min={0.5 * fx} max={costMax * fx} step={0.25 * fx}
                onValue={(v) => setCost(v / fx)} display={(v) => M(v / fx)}
                input={<PbInput id="pb-cost" label="Cost per unit" prefix={cur === 'SAR' ? 'SAR' : '$'} value={cost * fx} onValue={(v) => setCost(v / fx)} width={104} />} />
              <PbSlider label="Your shelf price in the US" hint="what a shopper pays" value={price * fx} min={0.5 * fx} max={priceMax * fx} step={0.25 * fx}
                onValue={(v) => setPrice(v / fx)} display={(v) => M(v / fx)}
                input={<PbInput id="pb-price" label="Shelf price" prefix={cur === 'SAR' ? 'SAR' : '$'} value={price * fx} onValue={(v) => setPrice(v / fx)} width={104} />} />
              <p className="pb-aside">
                Cost-plus says you keep <b><PbNum value={Math.max(0, price - cost)} format={(v) => M(v)} /></b> a unit. <em>That is before the road to the shelf.</em>
              </p>
              <div className="pb-nav">
                <button className="pill pill-ink" onClick={() => goStep(2)}>Show me what gets added</button>
              </div>
            </section>
          )}

          {step === 2 && (
            <section className="pb-step" key="s2">
              <p className="eyebrow">Step 2 · the road to the shelf</p>
              <h2 className="pb-h">Now see what the road <em>adds.</em></h2>
              <p className="pb-sub">Every line is a cost someone charges between your factory and the shopper. They land one at a time. Rates are a starting point for TikTok Shop; yours can differ.</p>

              {verdictBox}

              <PbSlider label="Your shelf price" value={price * fx} min={0.5 * fx} max={priceMax * fx} step={0.25 * fx}
                onValue={(v) => setPrice(v / fx)} display={(v) => M(v / fx)}
                input={<PbInput id="pb-price2" label="Shelf price" prefix={cur === 'SAR' ? 'SAR' : '$'} value={price * fx} onValue={(v) => setPrice(v / fx)} width={104} />} />
              <PbSlider label="Profit you want to keep" value={profitPct} min={0} max={40} step={1}
                onValue={setProfitPct} display={(v) => `${v}%`}
                input={<PbInput id="pb-profit" label="Profit percent" suffix="%" value={profitPct} onValue={(v) => setProfitPct(Math.min(60, v))} width={84} />} />

              <button className="pb-disclose" aria-expanded={openAdj} onClick={() => setOpenAdj((o) => !o)}>
                {openAdj ? 'Hide the assumptions' : 'Adjust the assumptions'}
              </button>
              {openAdj && (
                <div className="pb-assume">
                  {PRICE_MODEL.LINES.filter((l) => l.kind !== 'input' && l.id !== 'storage').map((l) => (
                    <label key={l.id} className="pb-assume-row">
                      <span>{l.label}<small>{l.kind === 'pctCost' ? 'of your cost' : l.kind === 'pctPrice' ? 'of the shelf price' : 'per unit'}</small></span>
                      {l.kind === 'perUnit'
                        ? <PbInput id={`pb-a-${l.id}`} label={l.label} prefix={cur === 'SAR' ? 'SAR' : '$'} value={rateOf(l.id) * fx} onValue={(v) => setRate(l.id, v / fx)} width={104} />
                        : <PbInput id={`pb-a-${l.id}`} label={l.label} suffix="%" value={rateOf(l.id) * 100} onValue={(v) => setRate(l.id, Math.min(95, v) / 100)} width={92} />}
                    </label>
                  ))}
                  <button className="pb-link" onClick={() => setAdj({})}>Back to the starting rates</button>
                </div>
              )}

              <div className="pb-nav">
                <button className="pb-link" onClick={() => goStep(1)}>← Your product</button>
                <button className="pill pill-ink" onClick={() => goStep(3)} disabled={!allIn}>Choose how we work together</button>
              </div>
            </section>
          )}

          {step === 3 && (
            <section className="pb-step" key="s3">
              <p className="eyebrow">Step 3 · working with us</p>
              <h2 className="pb-h">Then choose how we work <em>together.</em></h2>
              <p className="pb-sub">Pick what you want us to handle and how much you expect to sell. The monthly part is spread over every unit, so more volume means less on each one.</p>

              {verdictBox}

              <PbSlider label="Units you expect to sell a month" value={volume} min={50} max={10000} step={50}
                onValue={setVolume} display={(v) => pbNum(v)}
                input={<PbInput id="pb-volume" label="Units a month" value={volume} onValue={(v) => setVolume(Math.max(1, Math.round(v)))} width={104} />} />

              {US_PLAN.map((g) => (
                <fieldset className="pb-svc-group" key={g.id} style={{ '--h': g.hue }}>
                  <legend><span className="pb-svc-dot" />{g.label}</legend>
                  {g.items.map((it) => {
                    const price = it.monthly ? `${usd(it.monthly)} a month` : `${usd(it.setup)} once`;
                    const extra = it.unit ? (it.unit.money ? ' + 15% of ad spend' : it.unit.key === 'orders' ? ` + ${usd(it.unit.per)} an order` : ` + ${usd(it.unit.per)} a container`) : '';
                    return (
                      <label key={it.id} className={`pb-svc ${sel[it.id] ? 'on' : ''}`}>
                        <input type="checkbox" checked={!!sel[it.id]} onChange={() => setSel((s) => ({ ...s, [it.id]: !s[it.id] }))} />
                        <span className="pb-svc-box" aria-hidden="true">{Icon.check({})}</span>
                        <span className="pb-svc-t"><b>{it.name}</b><small>{it.sub}</small></span>
                        <span className="pb-svc-p">{price}{extra}</span>
                      </label>
                    );
                  })}
                </fieldset>
              ))}

              {sel.ship && (
                <div className="pb-inline">
                  <span>Containers in your first shipment</span>
                  <span className="pb-stepper">
                    <button onClick={() => setContainers((c) => Math.max(1, c - 1))} aria-label="One fewer container">−</button>
                    <b>{containers}</b>
                    <button onClick={() => setContainers((c) => Math.min(12, c + 1))} aria-label="One more container">+</button>
                  </span>
                </div>
              )}
              {!usesBlyzrStorage && (
                <div className="pb-inline">
                  <span>Your own storage and fulfilment, per unit</span>
                  <PbInput id="pb-own" label="Own storage per unit" prefix={cur === 'SAR' ? 'SAR' : '$'} value={rateOf('storage') * fx} onValue={(v) => setRate('storage', v / fx)} width={104} />
                </div>
              )}

              {resultBox}

              <div className="pb-nav">
                <button className="pb-link" onClick={() => goStep(2)}>← The road to the shelf</button>
              </div>
            </section>
          )}
        </div>

        <aside className="pb-right" aria-label="Your price, built up">
          <div className="pb-score">
            <div className="pb-score-main">
              <span className="pb-score-k">You keep per unit</span>
              <span className={`pb-score-v ${keepClass}`}><PbNum value={step === 1 ? Math.max(0, price - cost) : r.profit} format={(v) => M(v)} /></span>
              {step >= 2 && allIn && (
                <span className={`pb-chip ${keepClass}`}>{losing ? `Losing ${M(-r.profit)} a unit` : below ? `${M(-r.net)} short of target` : 'On target'}</span>
              )}
              {step === 1 && <span className="pb-chip">before the road to the shelf</span>}
            </div>
            <dl className="pb-score-grid">
              <div><dt>Shelf price</dt><dd><PbNum value={price} format={(v) => M(v)} /></dd></div>
              {step >= 2 && allIn && <div><dt>Break-even price</dt><dd><PbNum value={r.breakEvenPrice} format={(v) => M(v)} /></dd></div>}
              {step >= 2 && allIn && <div><dt>Price for {pbPct(r.profitPct)} profit</dt><dd><PbNum value={r.targetPrice} format={(v) => M(v)} /></dd></div>}
              {step >= 3 && r.monthly && <div><dt>Our fees</dt><dd><PbNum value={r.monthly.blyzrBill} format={(v) => `${M(v)}/mo`} /></dd></div>}
              {step >= 3 && r.monthly && <div><dt>Setup, once</dt><dd><PbNum value={r.monthly.setup} format={(v) => M(v)} /></dd></div>}
              {step >= 3 && r.monthly && <div><dt>Your profit</dt><dd className={r.monthly.profit < 0 ? 'neg' : ''}><PbNum value={r.monthly.profit} format={(v) => `${M(v)}/mo`} /></dd></div>}
            </dl>
          </div>

          <div className={`pb-viz ${hot ? 'has-hot' : ''}`}>
            <div className="pb-bar" role="img" aria-label={`Stack of costs against a shelf price of ${M(r.price)}`}>
              {placed.map((s) => (
                <div key={s.id} className={`pb-seg ${hot === s.id ? 'hot' : ''}`}
                  style={{ bottom: pct(s.bottom), height: pct(s.amount), background: pbColor(s.group, s.i) }} />
              ))}
              <div className="pb-seg keep" style={{ bottom: pct(shownSum), height: pct(keepAmt), background: pbColor('keep') }} />
              {short && <div className="pb-target" style={{ bottom: pct(shownSum), height: pct(r.targetProfit) }} />}
              {over && <div className="pb-over" style={{ bottom: pct(r.price), height: pct(shownSum - r.price) }} />}
              <div className="pb-priceline" style={{ bottom: pct(r.price) }}><span>{M(r.price)}</span></div>
            </div>

            <ol className="pb-receipt">
              {lineRows.map((row) => (
                <React.Fragment key={row.key}>
                  {row.head && <li className={`pb-gh ${row.in ? 'in' : ''}`}>{row.head}</li>}
                  <li className={`pb-row ${row.in ? 'in' : ''} ${hot === row.id ? 'hot' : ''}`}
                    onMouseEnter={() => setHot(row.id)} onMouseLeave={() => setHot(null)} onFocus={() => setHot(row.id)} onBlur={() => setHot(null)} tabIndex={row.in ? 0 : -1}>
                    <span className="pb-dot" style={{ background: pbColor(row.group, row.i) }} />
                    <span className="pb-row-t"><b>{row.label}</b><small>{row.basis}</small></span>
                    <span className="pb-row-v">{row.amount > 0 || row.id === 'storage' ? M(row.amount) : M(0)}</span>
                  </li>
                </React.Fragment>
              ))}
              <li className="pb-sum">
                <span>Everything above</span>
                <span><PbNum value={shownSum} format={(v) => M(v)} /></span>
              </li>
            </ol>
          </div>

        </aside>
      </div>
    </div>
  );
};

// plain USD for the text that goes to the team, whatever currency is on screen
const PRICE_MODEL_USD = (v) => {
  const a = Math.abs(v);
  const s = a.toLocaleString('en-US', { minimumFractionDigits: a >= 1000 ? 0 : 2, maximumFractionDigits: a >= 1000 ? 0 : 2 });
  return (v < -0.004 ? '−' : '') + '$' + s;
};

window.PriceBuilder = PriceBuilder;
