> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sfcompute.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Limits

> Account resource limits

export const CapacityChart = props => {
  const VIEW_W = 720;
  const VIEW_H = 292;
  const PX0 = 22;
  const PX1 = 654;
  const PY0 = 40;
  const PY1 = 258;
  const AXIS_FONT = 11.5;
  const CHIP_FONT = 12;
  const slug = s => String(s || "capacity").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/(^-|-$)/g, "");
  const stepFn = (orders, xMin, xMax) => {
    const bounds = new Set([xMin, xMax]);
    for (const o of orders) {
      if (o.start > xMin && o.start < xMax) bounds.add(o.start);
      if (o.end > xMin && o.end < xMax) bounds.add(o.end);
    }
    const xs = [...bounds].sort((a, b) => a - b);
    const segs = [];
    for (let i = 0; i < xs.length - 1; i++) {
      const x0 = xs[i];
      const x1 = xs[i + 1];
      let v = 0;
      for (const o of orders) {
        if (o.start <= x0 && o.end >= x1) v += o.side === "sell" ? -o.nodes : o.nodes;
      }
      segs.push({
        x0,
        x1,
        v: Math.max(0, v)
      });
    }
    return segs;
  };
  const filled = (orders, side) => orders.filter(o => o.side === side && (o.status ?? "filled") === "filled");
  const standing = orders => orders.filter(o => o.side === "sell" && o.status === "standing");
  const valueAt = (segs, x) => {
    for (const s of segs) if (x >= s.x0 && x < s.x1) return s.v;
    return segs.length ? segs[segs.length - 1].v : 0;
  };
  const areaPath = (upper, lower, sx, sy) => {
    const bounds = new Set();
    for (const s of [...upper, ...lower]) {
      bounds.add(s.x0);
      bounds.add(s.x1);
    }
    const xs = [...bounds].sort((a, b) => a - b);
    const cells = [];
    for (let i = 0; i < xs.length - 1; i++) {
      const mid = (xs[i] + xs[i + 1]) / 2;
      cells.push({
        x0: xs[i],
        x1: xs[i + 1],
        u: valueAt(upper, mid),
        l: valueAt(lower, mid)
      });
    }
    let d = "";
    let run = [];
    const flush = () => {
      if (!run.length) return;
      let p = `M ${sx(run[0].x0)} ${sy(run[0].l)}`;
      for (const c of run) p += ` L ${sx(c.x0)} ${sy(c.u)} L ${sx(c.x1)} ${sy(c.u)}`;
      for (let i = run.length - 1; i >= 0; i--) {
        p += ` L ${sx(run[i].x1)} ${sy(run[i].l)} L ${sx(run[i].x0)} ${sy(run[i].l)}`;
      }
      d += `${p} Z `;
      run = [];
    };
    for (const c of cells) {
      if (c.u > c.l) run.push(c); else flush();
    }
    flush();
    return d.trim();
  };
  const topEdgePath = (upper, lower, sx, sy) => {
    const bounds = new Set();
    for (const s of [...upper, ...lower]) {
      bounds.add(s.x0);
      bounds.add(s.x1);
    }
    const xs = [...bounds].sort((a, b) => a - b);
    let d = "";
    let prev = null;
    for (let i = 0; i < xs.length - 1; i++) {
      const mid = (xs[i] + xs[i + 1]) / 2;
      const u = valueAt(upper, mid);
      const l = valueAt(lower, mid);
      if (u <= l) {
        prev = null;
        continue;
      }
      if (prev === null) d += ` M ${sx(xs[i])} ${sy(l)} L ${sx(xs[i])} ${sy(u)}`; else if (prev !== u) d += ` L ${sx(xs[i])} ${sy(u)}`;
      d += ` L ${sx(xs[i + 1])} ${sy(u)}`;
      const nextMid = (xs[i + 1] + (xs[i + 2] ?? xs[i + 1] + 1)) / 2;
      const closes = i === xs.length - 2 || valueAt(upper, nextMid) <= valueAt(lower, nextMid);
      if (closes) {
        d += ` L ${sx(xs[i + 1])} ${sy(l)}`;
        prev = null;
      } else prev = u;
    }
    return d.trim();
  };
  const nodeLines = yMax => {
    const out = [];
    for (let v = 0; v <= yMax; v++) out.push(v);
    return out;
  };
  const nodeTicks = yMax => {
    const step = yMax <= 5 ? 1 : Math.ceil(yMax / 4);
    const out = [];
    for (let v = step; v <= yMax; v += step) out.push(v);
    return out;
  };
  const timeTicks = (xMin, xMax) => {
    const span = xMax - Math.max(0, xMin);
    const step = span <= 5 ? 1 : span <= 12 ? 2 : Math.ceil(span / 4);
    const out = [Math.max(0, xMin)];
    for (let t = Math.max(step, xMin + step); t < xMax - step * 0.55; t += step) out.push(t);
    out.push(xMax);
    return out;
  };
  const hoverStep = (xMin, xMax) => {
    const span = xMax - xMin;
    for (const step of [0.25, 0.5, 1, 2, 5, 10]) {
      if (span / step <= 64) return step;
    }
    return span / 64;
  };
  const formatTime = (t, step, unit) => {
    if (Math.abs(t) < step / 2) return "now";
    const digits = step < 1 ? 1 : 0;
    return `${t < 0 ? "-" : "+"}${Math.abs(t).toFixed(digits)}${unit}`;
  };
  const plural = (n, word) => `${n} ${word}${n === 1 ? "" : "s"}`;
  const laneState = (lane, unit) => {
    const ends = lane.ends ?? "runs";
    if (ends === "runs") return "running";
    const when = unit === "h" ? `at hour ${lane.end}` : `on day ${lane.end}`;
    return ends === "auto" ? `SF Compute terminated it ${when}` : `you terminated it ${when}`;
  };
  const shapes = (phase, opts) => {
    const orders = phase.orders ?? [];
    const {xMin, xMax} = opts;
    const gross = stepFn(filled(orders, "buy"), xMin, xMax);
    const settled = [...filled(orders, "buy"), ...filled(orders, "sell")];
    const net = stepFn(settled, xMin, xMax);
    const peak = Math.max(1, ...gross.map(s => s.v), ...net.map(s => s.v));
    const yMax = opts.yMax ?? peak + Math.max(1, Math.round(peak * 0.2));
    const sx = t => PX0 + (t - xMin) / (xMax - xMin) * (PX1 - PX0);
    const sy = v => PY1 - v / yMax * (PY1 - PY0);
    const standingBands = standing(orders).map(o => {
      const upper = net.flatMap(s => s.x1 > o.start && s.x0 < o.end ? [{
        x0: Math.max(s.x0, o.start),
        x1: Math.min(s.x1, o.end),
        v: s.v
      }] : []);
      const lower = upper.map(s => ({
        ...s,
        v: Math.max(0, s.v - o.nodes)
      }));
      return {
        d: areaPath(upper, lower, sx, sy)
      };
    });
    const zero = [{
      x0: xMin,
      x1: xMax,
      v: 0
    }];
    return {
      gross,
      net,
      yMax,
      sx,
      sy,
      standingBands,
      zero,
      soldArea: areaPath(gross, net, sx, sy),
      heldArea: areaPath(net, zero, sx, sy)
    };
  };
  const panelSvg = (phase, prev, opts, uid) => {
    const orders = phase.orders ?? [];
    const lanes = phase.lanes ?? [];
    const {xMin, xMax, xUnit, nowAt} = opts;
    const {gross, net, yMax, sx, sy, standingBands, zero, soldArea, heldArea} = shapes(phase, opts);
    const before = prev ? shapes(prev, opts) : null;
    const reveal = changed => changed ? "sfc-cap-reveal" : undefined;
    const soldChanged = before ? soldArea !== before.soldArea : false;
    const bandChanged = d => before ? !before.standingBands.some(b => b.d === d) : false;
    const laneKey = (lane, i) => `${i}:${lane.label ?? ""}`;
    const prevLanes = new Map((prev?.lanes ?? []).map((l, i) => [laneKey(l, i), JSON.stringify(l)]));
    const laneChanged = (lane, i) => before ? prevLanes.get(laneKey(lane, i)) !== JSON.stringify(lane) : false;
    const cutouts = [...standingBands.map(b => b.d), soldArea].filter(Boolean);
    const cellW = (PX1 - PX0) / (xMax - xMin);
    const cellH = (PY1 - PY0) / yMax;
    const lattice = cellW >= 10 && cellH >= 10;
    const laneRow = i => {
      const top = sy(i + 1);
      const bottom = sy(i);
      const inset = Math.min(5, (bottom - top) * 0.32);
      return {
        y: top + inset,
        h: bottom - top - inset * 2
      };
    };
    return <svg viewBox={`0 0 ${VIEW_W} ${VIEW_H}`} className="sfc-cap-svg" role="img" aria-label={phase.alt ?? [`${opts.title ?? "Pool"} allocation over time`, phase.label, phase.caption].filter(Boolean).join(". ")}>
        <defs>
          <pattern id={`${uid}-sold`} width="7" height="7" patternTransform="rotate(45)" patternUnits="userSpaceOnUse">
            <line x1="0" y1="0" x2="0" y2="7" className="sfc-cap-sold-hatch" />
          </pattern>
          {cutouts.length > 0 && <mask id={`${uid}-edge-mask`} maskUnits="userSpaceOnUse">
              <rect x="0" y="0" width={VIEW_W} height={VIEW_H} fill="#fff" />
              {cutouts.map(d => <path key={d} d={d} fill="none" stroke="#000" strokeWidth={3} />)}
            </mask>}
          {lattice && <pattern id={`${uid}-lattice`} width={cellW} height={cellH} x={sx(0)} y={PY1} patternUnits="userSpaceOnUse">
              <line x1={0.5} y1={0} x2={0.5} y2={cellH} className="sfc-cap-lattice" />
              <line x1={0} y1={0.5} x2={cellW} y2={0.5} className="sfc-cap-lattice" />
            </pattern>}
          {lattice && <clipPath id={`${uid}-held-clip`}>
              <path d={heldArea} />
            </clipPath>}
          <marker id={`${uid}-arrow-axis`} viewBox="0 0 8 8" refX="6.5" refY="4" markerWidth="5" markerHeight="5" orient="auto-start-reverse">
            <path d="M 0.5 1 L 7 4 L 0.5 7 z" className="sfc-cap-arrow-axis" />
          </marker>
        </defs>

        {nodeLines(yMax).map(v => <line key={`g${v}`} x1={PX0} y1={sy(v)} x2={PX1} y2={sy(v)} className="sfc-cap-grid" />)}

        {}
        {nowAt !== null && nowAt >= xMin && nowAt <= xMax && <line x1={sx(nowAt)} y1={PY0 - 8} x2={sx(nowAt)} y2={PY1} className="sfc-cap-now" />}

        <path d={soldArea} fill={`url(#${uid}-sold)`} className={reveal(soldChanged)} />
        <path d={soldArea} className={["sfc-cap-sold-edge", reveal(soldChanged)].filter(Boolean).join(" ")} />

        <path d={heldArea} className="sfc-cap-area" />
        {lattice && <rect x={PX0} y={PY0} width={PX1 - PX0} height={PY1 - PY0} fill={`url(#${uid}-lattice)`} clipPath={`url(#${uid}-held-clip)`} />}
        <path d={topEdgePath(net, zero, sx, sy)} className="sfc-cap-area-edge" mask={cutouts.length ? `url(#${uid}-edge-mask)` : undefined} />

        {standingBands.map(b => <path key={b.d} d={b.d} className={["sfc-cap-offered", reveal(bandChanged(b.d))].filter(Boolean).join(" ")} />)}

        {lanes.map((lane, i) => {
      const row = laneRow(i);
      const x0 = sx(Math.max(lane.start ?? xMin, xMin));
      const x1 = sx(Math.min(lane.end ?? xMax, xMax));
      const ends = lane.ends ?? "runs";
      return <g key={lane.label ?? i}>
              <rect x={x0} y={row.y} width={Math.max(0, x1 - x0)} height={row.h} rx={2} className="sfc-cap-lane" />
              {ends !== "runs" && <line x1={x1} y1={row.y - 1} x2={x1} y2={row.y + row.h + 1} className={[ends === "auto" ? "sfc-cap-lane-cut-auto" : "sfc-cap-lane-cut", reveal(laneChanged(lane, i))].filter(Boolean).join(" ")} />}
              {lane.label && <text x={x0} y={row.y + row.h / 2} textAnchor="middle" dominantBaseline="central" fontSize={AXIS_FONT - 1} className="sfc-cap-lane-label">
                  {lane.label}
                </text>}
            </g>;
    })}

        <line x1={PX0} y1={PY1} x2={PX1 + 30} y2={PY1} className="sfc-cap-axis" markerEnd={`url(#${uid}-arrow-axis)`} />
        <line x1={PX0} y1={PY1} x2={PX0} y2={PY0 - 12} className="sfc-cap-axis" markerEnd={`url(#${uid}-arrow-axis)`} />
        <text x={PX0} y={PY0 - 18} textAnchor="middle" fontSize={AXIS_FONT} className="sfc-cap-axis-label">
          nodes
        </text>

        {lanes.length === 0 && nodeTicks(yMax).map(v => <text key={`yt${v}`} x={PX0 - 8} y={sy(v)} textAnchor="end" dominantBaseline="central" fontSize={AXIS_FONT} className="sfc-cap-tick">
              {v}
            </text>)}

        {timeTicks(xMin, xMax).map(t => <g key={`xt${t}`}>
            <line x1={sx(t)} y1={PY1} x2={sx(t)} y2={PY1 + 4} className="sfc-cap-axis" />
            <text x={sx(t)} y={PY1 + 17} textAnchor="middle" fontSize={AXIS_FONT} className="sfc-cap-tick">
              {t === 0 ? "now" : `+${t}${xUnit}`}
            </text>
          </g>)}

        {}
        <g className="sfc-cap-hover">
          {(() => {
      const step = hoverStep(xMin, xMax);
      const cols = [];
      const first = Math.ceil(xMin / step);
      const last = Math.floor(xMax / step);
      for (let k = first; k <= last; k++) {
        const mid = k * step;
        const t = Math.max(xMin, mid - step / 2);
        const end = Math.min(xMax, mid + step / 2);
        const held = valueAt(net, mid);
        const soldNow = Math.max(0, valueAt(gross, mid) - held);
        const offeredNow = standing(orders).reduce((n, o) => mid >= o.start && mid < o.end ? n + Math.min(o.nodes, held) : n, 0);
        const parts = [formatTime(mid, step, xUnit), plural(held, "node")];
        if (soldNow > 0) parts.push(`${soldNow} sold`);
        if (offeredNow > 0) parts.push(`${offeredNow} offered`);
        cols.push({
          t,
          end,
          mid,
          held,
          label: parts.join("  ·  ")
        });
      }
      return cols.map(c => {
        const cx = sx(c.mid);
        return <g key={`hov${c.t}`}>
                  <rect x={sx(c.t)} y={PY0 - 10} width={Math.max(1, sx(c.end) - sx(c.t))} height={PY1 - PY0 + 10} className="sfc-cap-hit" />
                  <g className="sfc-cap-readout">
                    <line x1={cx} y1={PY0 - 10} x2={cx} y2={PY1} className="sfc-cap-cross" />
                    <circle cx={cx} cy={sy(c.held)} r={3} className="sfc-cap-dot" />
                    <text x={PX1} y={PY0 + 2} textAnchor="end" dominantBaseline="central" fontSize={CHIP_FONT} className="sfc-cap-readout-text">
                      {c.label}
                    </text>
                  </g>
                </g>;
      });
    })()}

          {lanes.map((lane, i) => {
      const row = laneRow(i);
      const x0 = sx(Math.max(lane.start ?? xMin, xMin));
      const x1 = sx(Math.min(lane.end ?? xMax, xMax));
      const label = `${lane.label ?? `instance ${i + 1}`}  ·  ${laneState(lane, xUnit)}`;
      return <g key={`lh${lane.label ?? i}`} className="sfc-cap-lane-hit">
                <rect x={x0} y={row.y} width={Math.max(0, x1 - x0)} height={row.h} className="sfc-cap-hit" />
                <rect x={x0} y={row.y} width={Math.max(0, x1 - x0)} height={row.h} rx={2} className="sfc-cap-lane-glow" />
                <text x={PX1} y={PY0 + 2} textAnchor="end" dominantBaseline="central" fontSize={CHIP_FONT} className="sfc-cap-tip sfc-cap-readout-text">
                  {label}
                </text>
              </g>;
    })}
        </g>
      </svg>;
  };
  const legendKeys = phase => {
    const orders = phase.orders ?? [];
    const lanes = phase.lanes ?? [];
    const capacity = [{
      cls: "sfc-cap-key-retained",
      label: "Retained allocation"
    }];
    if (filled(orders, "sell").length) capacity.push({
      cls: "sfc-cap-key-sold",
      label: "Sold"
    });
    if (standing(orders).length) capacity.push({
      cls: "sfc-cap-key-offered",
      label: "Offered for sale"
    });
    const instance = [];
    if (lanes.length) instance.push({
      cls: "sfc-cap-key-lane",
      label: "Instance runtime"
    });
    if (lanes.some(l => (l.ends ?? "runs") !== "runs")) instance.push({
      cls: "sfc-cap-key-cut",
      label: "Terminated"
    });
    const keys = instance.length ? [...capacity, {
      rule: true,
      label: "rule"
    }, ...instance] : capacity;
    return keys.reverse();
  };
  const legendRow = keys => <div className="sfc-cap-legend">
      {keys.map(k => k.rule ? <span key={k.label} className="sfc-cap-key-rule" aria-hidden="true" /> : <span key={k.label}>
            <i className={k.cls} />
            {k.label}
          </span>)}
    </div>;
  const stepperCss = (uid, count) => {
    let css = "";
    for (let i = 1; i <= count; i++) {
      if (i > 1) {
        css += `#${uid} .sfc-cap-radio:nth-of-type(${i}):checked ~ .sfc-cap-stack .sfc-cap-panel:first-of-type{opacity:0;visibility:hidden;}`;
      }
      css += `#${uid} .sfc-cap-radio:nth-of-type(${i}):checked ~ .sfc-cap-tabs .sfc-cap-tab:nth-child(${i}){color:var(--sfc-cap-fg);background:var(--sfc-cap-tab-on);box-shadow:inset 0 0 0 1px var(--sfc-cap-border-strong);}`;
      css += `#${uid} .sfc-cap-radio:nth-of-type(${i}):focus-visible ~ .sfc-cap-tabs .sfc-cap-tab:nth-child(${i}){outline:2px solid var(--sfc-cap-accent);outline-offset:2px;}`;
      css += `#${uid} .sfc-cap-radio:nth-of-type(${i}):checked ~ .sfc-cap-stack .sfc-cap-panel:nth-child(${i}){opacity:1;visibility:visible;}`;
      css += `#${uid} .sfc-cap-radio:nth-of-type(${i}):checked ~ .sfc-cap-stack .sfc-cap-panel:nth-child(${i}) .sfc-cap-reveal{opacity:1;}`;
    }
    css += `#${uid} .sfc-cap-reveal{opacity:0;transition:opacity .26s var(--sfc-cap-ease-out) .09s;}`;
    css += `@media (prefers-reduced-motion:reduce){#${uid} .sfc-cap-reveal{transition:none;}}`;
    return css;
  };
  const BASE_CSS = `
  .sfc-cap{
    --sfc-cap-inset-right:${((VIEW_W - PX1) / VIEW_W * 100).toFixed(4)}%;
    --sfc-cap-fg:#18181B;
    --sfc-cap-muted:#52525B;
    --sfc-cap-faint:#71717A;
    --sfc-cap-border-strong:rgba(0,0,0,0.14);
    --sfc-cap-grid:rgba(0,0,0,0.06);
    --sfc-cap-accent:#2563EB;
    --sfc-cap-area:rgba(59,130,246,0.11);
    --sfc-cap-lane:#2563EB;
    --sfc-cap-sold:#E11D48;
    --sfc-cap-tab-on:#FFFFFF;
    --sfc-cap-tab-track:rgba(0,0,0,0.04);
    --sfc-cap-tip-bg:#FFFFFF;
    --sfc-cap-halo:var(--background,#FFFFFF);
    --sfc-cap-ease-out:cubic-bezier(0.23,1,0.32,1);
    margin:1.25rem 0;
    font-size:14px;
  }
  .dark .sfc-cap{
    --sfc-cap-fg:#F4F4F5;
    --sfc-cap-muted:#A1A1AA;
    --sfc-cap-faint:#71717A;
    --sfc-cap-border-strong:rgba(255,255,255,0.20);
    --sfc-cap-grid:rgba(255,255,255,0.07);
    --sfc-cap-accent:#93C5FD;
    --sfc-cap-area:rgba(96,165,250,0.18);
    --sfc-cap-lane:#93C5FD;
    --sfc-cap-sold:#FB7185;
    --sfc-cap-tab-on:rgba(255,255,255,0.10);
    --sfc-cap-tab-track:rgba(255,255,255,0.04);
    --sfc-cap-tip-bg:#27272A;
    --sfc-cap-halo:var(--background,#0A0A0A);
  }
  .sfc-cap-title{
    display:block;
    color:var(--sfc-cap-muted);
    font-size:13px;
    letter-spacing:0.01em;
    margin-bottom:6px;
  }
  .sfc-cap-title code{font-size:13px;}
  /* Only matches an unstepped chart: the stepped one puts its radios and tab
     row between the two, and those already carry the gap. */
  .sfc-cap-title + .sfc-cap-stack{margin-top:14px;}
  .sfc-cap-radio{position:absolute;opacity:0;pointer-events:none;width:1px;height:1px;}
  .sfc-cap-tabs{display:inline-flex;flex-wrap:wrap;gap:2px;margin-bottom:14px;padding:2px;border-radius:8px;background:var(--sfc-cap-tab-track);counter-reset:sfc-cap-step;}
  .sfc-cap-tab{
    cursor:pointer;
    padding:4px 10px;
    border-radius:6px;
    font-size:13px;
    line-height:1.5;
    color:var(--sfc-cap-faint);
    user-select:none;
    transition:color .15s ease,background .15s ease;
    text-align:center;
  }
  /* Wrapped flex rows leave a ragged track at phone widths, so the tabs become
     a full-width two-column grid instead. */
  @media (max-width:640px){
    .sfc-cap-tabs{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));width:100%;}
    .sfc-cap-tab{min-width:0;padding:5px 6px;font-size:12px;overflow-wrap:anywhere;}
  }
  .sfc-cap-tab::before{counter-increment:sfc-cap-step;content:counter(sfc-cap-step) ". ";font-variant-numeric:tabular-nums;opacity:0.65;}
  .sfc-cap-tab:hover{color:var(--sfc-cap-muted);}
  .sfc-cap-stack{display:grid;}
  /* No cross-fade: the panels share one grid cell, so fading paints two step
     functions over each other and the figure visibly dims mid-transition. */
  .sfc-cap-panel{
    grid-area:1/1;
    opacity:0;
    visibility:hidden;
    margin:0;
  }
  /* Selecting a phase hides phase 1 rather than revealing itself, so the chart
     still shows a panel if the checked radio doesn't survive to the browser. */
  .sfc-cap-panel:first-of-type{opacity:1;visibility:visible;}
  .sfc-cap-svg{display:block;width:100%;height:auto;overflow:visible;font-family:inherit;}
  .sfc-cap-caption{
    margin:8px 0 0;
    color:var(--sfc-cap-muted);
    font-size:13px;
    line-height:1.5;
  }
  .sfc-cap-plot{position:relative;}
  .sfc-cap-legend{
    position:absolute;
    top:0;
    right:var(--sfc-cap-inset-right);
    display:flex;
    align-items:center;
    gap:16px;
    font-size:12.5px;
    line-height:1;
    color:var(--sfc-cap-muted);
  }
  .sfc-cap-legend span{display:inline-flex;align-items:center;gap:6px;white-space:nowrap;}
  .sfc-cap-legend i{width:11px;height:11px;border-radius:2px;display:inline-block;}
  .sfc-cap-key-retained{background:var(--sfc-cap-area);box-shadow:inset 0 0 0 1px var(--sfc-cap-accent);}
  .sfc-cap-key-sold{background:repeating-linear-gradient(45deg,var(--sfc-cap-sold) 0 1px,transparent 1px 4px);box-shadow:inset 0 0 0 1px var(--sfc-cap-sold);}
  /* Each edge starts its dash run at a corner; a CSS dashed border draws the
     corners as gaps. */
  .sfc-cap-legend i.sfc-cap-key-offered{
    border-radius:0;
    background-image:
      repeating-linear-gradient(to right,var(--sfc-cap-sold) 0 3px,transparent 3px 5.5px),
      repeating-linear-gradient(to bottom,var(--sfc-cap-sold) 0 3px,transparent 3px 5.5px),
      repeating-linear-gradient(to left,var(--sfc-cap-sold) 0 3px,transparent 3px 5.5px),
      repeating-linear-gradient(to top,var(--sfc-cap-sold) 0 3px,transparent 3px 5.5px);
    background-size:100% 1px,1px 100%,100% 1px,1px 100%;
    background-position:left top,right top,left bottom,left top;
    background-repeat:no-repeat;
  }
  .sfc-cap-legend i.sfc-cap-key-lane{background:color-mix(in srgb,var(--sfc-cap-lane) 20%,transparent);box-shadow:inset 0 0 0 1px var(--sfc-cap-lane);}
  .sfc-cap-legend i.sfc-cap-key-cut{width:3px;border-radius:1px;background:var(--sfc-cap-sold);}
  .sfc-cap-legend span.sfc-cap-key-rule{width:1px;height:11px;background:var(--sfc-cap-border-strong);}
  /* The SVG scales with the column, so its type shrinks with it. Phone widths
     render at roughly half scale, and these sizes read back at that scale. */
  @media (max-width:640px){
    .sfc-cap-legend{position:static;flex-wrap:wrap;gap:10px 14px;margin-top:10px;font-size:12px;}
    .sfc-cap-tick,.sfc-cap-axis-label{font-size:19px;}
    /* Held back from the tick size: the name is centred on the lane's start, so
       a wider string runs off the left of the figure. */
    .sfc-cap-lane-label{font-size:13px;stroke-width:3px;}
    .sfc-cap-readout-text{font-size:19px;}
  }

  .sfc-cap-grid{stroke:var(--sfc-cap-grid);stroke-width:1;}
  .sfc-cap-axis{stroke:var(--sfc-cap-border-strong);stroke-width:1;fill:none;}
  .sfc-cap-arrow-axis{fill:var(--sfc-cap-border-strong);}
  .sfc-cap-axis-label{fill:var(--sfc-cap-faint);}
  .sfc-cap-tick{fill:var(--sfc-cap-faint);}
  .sfc-cap-now{stroke:var(--sfc-cap-muted);stroke-width:1.25;stroke-dasharray:4 4;}
  .sfc-cap-area{fill:var(--sfc-cap-area);}
  .sfc-cap-lattice{stroke:var(--sfc-cap-accent);stroke-width:1;stroke-opacity:0.3;}
  .sfc-cap-area-edge{fill:none;stroke:var(--sfc-cap-accent);stroke-width:1.5;}
  .sfc-cap-sold-hatch{stroke:var(--sfc-cap-sold);stroke-width:1;opacity:0.5;}
  .sfc-cap-sold-edge{fill:none;stroke:var(--sfc-cap-sold);stroke-width:1.25;}
  .sfc-cap-offered{fill:var(--sfc-cap-sold);fill-opacity:0.07;stroke:var(--sfc-cap-sold);stroke-width:1.25;stroke-dasharray:5 4;}
  /* Solid: a hatched lane inside a sold window cross-hatches into mush. */
  .sfc-cap-lane{fill:var(--sfc-cap-lane);fill-opacity:0.2;stroke:var(--sfc-cap-lane);stroke-width:1;stroke-opacity:0.55;}
  /* The name straddles the lane's start, half of it over the bar and half over
     the page, so it carries a halo of the page colour drawn behind the glyphs.
     SVG text takes the halo from stroke, not -webkit-text-stroke. */
  .sfc-cap-lane-label{fill:var(--sfc-cap-muted);stroke:var(--sfc-cap-halo);stroke-width:2px;stroke-linejoin:round;paint-order:stroke;}
  .sfc-cap-lane-cut{stroke:var(--sfc-cap-muted);stroke-width:2.5;stroke-linecap:round;}
  .sfc-cap-lane-cut-auto{stroke:var(--sfc-cap-sold);stroke-width:2.5;stroke-linecap:round;}
  /* The hit rects are transparent but must still take pointer events; with no
     hover (touch) the layer stands down rather than swallowing taps. */
  .sfc-cap-hit{fill:transparent;stroke:none;}
  .sfc-cap-readout{opacity:0;pointer-events:none;}

  .sfc-cap-tip,.sfc-cap-lane-glow{opacity:0;pointer-events:none;transition:opacity .15s ease-out;}
  .sfc-cap-hit:hover + .sfc-cap-readout{opacity:1;}
  .sfc-cap-lane-hit:hover .sfc-cap-tip,.sfc-cap-lane-hit:hover .sfc-cap-lane-glow{opacity:1;}
  .sfc-cap-cross{stroke:var(--sfc-cap-accent);stroke-width:1;stroke-opacity:0.5;}
  .sfc-cap-dot{fill:var(--sfc-cap-accent);}
  .sfc-cap-lane-glow{fill:var(--sfc-cap-lane);fill-opacity:0.2;stroke:var(--sfc-cap-lane);stroke-width:1;}
  .sfc-cap-readout-text{fill:var(--sfc-cap-fg);font-variant-numeric:tabular-nums;paint-order:stroke;stroke:var(--sfc-cap-tip-bg);stroke-width:3;stroke-linejoin:round;}
  @media (hover:none){
    .sfc-cap-hover{display:none;}
  }
  @media (prefers-reduced-motion:reduce){
    .sfc-cap-tab,.sfc-cap-tip,.sfc-cap-lane-glow{transition:none;}
  }
  `;
  const uid = `sfc-cap-${slug(props.id ?? props.title)}`;
  const phases = props.phases ?? [{
    label: props.label,
    orders: props.orders,
    lanes: props.lanes,
    caption: props.caption,
    alt: props.alt
  }];
  const opts = {
    title: props.title,
    xMin: props.xMin ?? -(props.xMax ?? 14) * 0.07,
    xMax: props.xMax ?? 14,
    xUnit: props.xUnit ?? "d",
    nowAt: props.nowAt === undefined ? 0 : props.nowAt,
    yMax: props.yMax
  };
  const steps = phases.map((p, i) => ({
    phase: p,
    id: `${uid}-${slug(p.label ?? `step ${i + 1}`)}`,
    tab: p.label ?? `Step ${i + 1}`,
    keys: legendKeys(p)
  }));
  const stepped = steps.length > 1;
  return <div className="sfc-cap" id={uid}>
      {}
      <style dangerouslySetInnerHTML={{
    __html: BASE_CSS + (stepped ? stepperCss(uid, steps.length) : "")
  }} />
      {props.title && <span className="sfc-cap-title">
          Pool: <code>{props.title}</code>
        </span>}
      {stepped && steps.map(s => <input key={s.id} type="radio" name={`${uid}-phase`} id={s.id} className="sfc-cap-radio" defaultChecked={s === steps[0]} />)}
      {stepped && <div className="sfc-cap-tabs">
          {steps.map(s => <label key={s.id} className="sfc-cap-tab" htmlFor={s.id}>
              {s.tab}
            </label>)}
        </div>}
      <div className="sfc-cap-stack">
        {steps.map((s, i) => <figure key={s.id} className="sfc-cap-panel" style={stepped ? undefined : {
    opacity: 1,
    visibility: "visible"
  }}>
            <div className="sfc-cap-plot">
              {panelSvg(s.phase, steps[i - 1]?.phase, opts, s.id)}
              {props.legend !== false && s.keys.length > 1 && legendRow(s.keys)}
            </div>
            {s.phase.caption && <figcaption className="sfc-cap-caption">
                {s.phase.caption}
              </figcaption>}
          </figure>)}
      </div>
    </div>;
};

Every account has limits on how much compute it can commit to at once. An order that would take you
past a limit is refused, and nothing is placed. Selling is never refused by a compute limit, because
an order that sells compute you already hold lowers your commitment.

```bash theme={null}
sf limits
```

## The limits

`compute_max_total_node_hours` caps the node-hours your account holds in total across all pools.
That total is the area under your allocation schedule, so buying further ahead spends the cap the
same way buying wider does.

<CapacityChart id="limits-node-hours" title="node-hours committed" xMax={14} yMax={8} caption="3 nodes for 8 days is 576 node-hours." orders={[{ side: "buy", start: 2, end: 10, nodes: 3 }]} />

`compute_node_hours_free_window_seconds` sets how far ahead the cap starts counting. An order that
starts inside the free window counts only from the edge of the window onward, and one that fits
entirely inside it does not count at all. Nothing bounds the far end, so every order you hold
counts, however far out it starts.

`credits_max_credit` is the largest credit line SF Compute will extend to your account. It bounds
the credit limit shown in `sf billing balance`.

## Raising your limits

Verifying your organization raises your limits. Complete verification in the
[dashboard](https://sfcompute.com/dashboard/settings).

To discuss a higher limit than verification gives you, contact SF Compute.
