/* Shared UI components for LE200 configurator. Workshop/engineering vocabulary. */

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

// ───────────────────────────────────────────────────── format helpers
const fmtUSD = (n) => "$" + Math.round(n).toLocaleString("en-US");
const fmtInches = (n) => {
  const whole = Math.floor(n);
  const frac = n - whole;
  if (Math.abs(frac) < 0.05) return whole + '"';
  if (Math.abs(frac - 0.5) < 0.05) return whole + '½"';
  if (Math.abs(frac - 0.25) < 0.05) return whole + '¼"';
  if (Math.abs(frac - 0.75) < 0.05) return whole + '¾"';
  return n.toFixed(2).replace(/\.?0+$/, "") + '"';
};

// ───────────────────────────────────────────────────── Logo (Laguna signature)
function LagunaSig({ size = 28, alt = 'Laguna' }) {
  // Render the actual signature logo PNG. The PNG has transparent background
  // and is already cyan, so we size by height and let width auto.
  return (
    <img
      src="assets/laguna-logo.png"
      alt={alt}
      style={{ ...{
          height: size,

          display: 'inline-block',
          verticalAlign: 'middle', width: "50px"
        }, padding: "0px", objectFit: "fill", width: "100px", height: "100px", margin: "-6px 0px 0px" }} />);

}

// ───────────────────────────────────────────────────── Crosshairs
function Crosshairs() {
  return (
    <>
      <span className="cross-tl" />
      <span className="cross-tr" />
      <span className="cross-bl" />
      <span className="cross-br" />
    </>);

}

// ───────────────────────────────────────────────────── Top nav with stepper
function TopNav({ step, onStep, model }) {
  // step: 0=landing, 1=size, 2=configure, 3=fit, 4=review
  const steps = [
  { id: "size", label: "01 · Select size" },
  { id: "config", label: "02 · Configure" },
  { id: "fit", label: "03 · Fit check" },
  { id: "review", label: "04 · Review & order" }];

  return (
    <nav className="topnav">
      <div className="topnav-inner">
        <div className="brand">
          <span style={{ fontFamily: 'var(--font-display)', fontSize: 22, margin: "0px", padding: "0px 0px 29px" }}>LE200</span>
          <span style={{ fontSize: 11, fontFamily: 'var(--font-mono)', letterSpacing: '0.1em', color: 'var(--ink-3)', textTransform: 'uppercase', margin: "0px", padding: "0px 0px 58px" }}>by</span>
          <LagunaSig size={32} />
        </div>
        {step > 0 &&
        <div className="crumbs">
            {steps.map((s, i) => {
            const idx = i + 1;
            const status = idx < step ? "done" : idx === step ? "active" : "";
            return (
              <React.Fragment key={s.id}>
                  <button
                  className={`crumb ${status}`}
                  onClick={() => idx <= step && onStep(idx)}
                  disabled={idx > step}
                  style={{
                    background: 'transparent',
                    cursor: idx <= step ? 'pointer' : 'not-allowed',
                    color: 'inherit',
                    fontFamily: 'inherit',
                    letterSpacing: 'inherit',
                    textTransform: 'inherit',
                    fontSize: 'inherit'
                  }}>
                  {s.label}</button>
                  {i < steps.length - 1 && <span className="crumb-sep" />}
                </React.Fragment>);

          })}
          </div>
        }
        {step === 0 &&
        <div className="crumbs">
            <span className="crumb">Front-loading gas kilns · ETL certified · made to order in California</span>
          </div>
        }
      </div>
    </nav>);

}

// ───────────────────────────────────────────────────── Section header
function SectionHeader({ tag, title, sub, action }) {
  return (
    <div className="rule" style={{ paddingTop: 24, marginBottom: 24 }}>
      <div className="flex between items-baseline" style={{ gap: 32 }}>
        <div>
          <div className="sec-tag" style={{ marginBottom: 12 }}>{tag}</div>
          <h2 className="display" style={{ margin: 0, fontSize: 40 }}>{title}</h2>
          {sub && <p style={{ marginTop: 12, maxWidth: 560, color: 'var(--ink-2)', lineHeight: 1.5 }}>{sub}</p>}
        </div>
        {action}
      </div>
    </div>);

}

// ───────────────────────────────────────────────────── Choice button
function Choice({ active, onClick, label, sub, delta, children }) {
  return (
    <button
      type="button"
      className="choice"
      aria-checked={active}
      onClick={onClick}>
      
      {active && <span className="stripe" />}
      <div className="label">
        <span style={{
          display: 'inline-flex',
          width: 14, height: 14,
          border: '1.5px solid var(--ink)',
          borderRadius: '50%',
          alignItems: 'center', justifyContent: 'center',
          flex: '0 0 14px'
        }}>
          {active && <span style={{ width: 6, height: 6, background: 'var(--accent)', borderRadius: '50%' }} />}
        </span>
        {label}
      </div>
      {sub && <div className="sub" style={{ paddingLeft: 22 }}>{sub}</div>}
      {children && <div style={{ paddingLeft: 22, marginTop: 8 }}>{children}</div>}
      {typeof delta === 'number' && delta !== 0 &&
      <span className="delta">+{fmtUSD(delta)}</span>
      }
      {delta === 0 && <span className="delta muted">incl.</span>}
    </button>);

}

// ───────────────────────────────────────────────────── Kiln image with dimension overlays
function DimensionedKiln({ model, config, openDoor, showDims = true }) {
  // Pick best image: open door if applicable, else front
  const src = openDoor && model.open ? model.open : model.front;
  const flipDoor = config?.door === 'right';
  const flipPanel = config?.controls === 'left';
  // Single front image — both hinge side and panel side are visually represented by horizontal flip
  // The renders are "left hinge + right panel" by default
  const flipHorizontal = config?.door === 'right'; // mirror entire image for right-hinge
  const [w, d, h] = model.footprint; // width, depth, height
  const isDowndraft = config?.airflow === 'downdraft';
  const depthDisplay = isDowndraft ? d + 6 : d;

  return (
    <div style={{ position: 'relative', width: '100%', maxWidth: 560, margin: '0 auto', padding: '40px 60px 60px' }}>
      {/* Crosshairs */}
      <Crosshairs />

      {/* Kiln image */}
      <div style={{ position: 'relative', aspectRatio: '1 / 1' }}>
        <img
          src={src}
          alt={model.sku}
          style={{
            width: '100%', height: '100%', objectFit: 'contain',
            transform: flipHorizontal ? 'scaleX(-1)' : 'none',
            transition: 'transform 0.4s ease',
            filter: 'drop-shadow(0 30px 40px rgba(14, 53, 61, 0.18))'
          }} />
        

        {showDims &&
        <>
            {/* Width dimension — below */}
            <div className="dim-h" style={{
            position: 'absolute',
            left: '6%', right: '6%', bottom: -28
          }}>
              <span className="dim">W · {fmtInches(w)}</span>
            </div>
            {/* Height dimension — right side */}
            <div className="dim-v" style={{
            position: 'absolute',
            top: '4%', bottom: '4%', right: -28
          }}>
              <span className="dim">H · {fmtInches(h)}</span>
            </div>
            {/* SKU label top-left */}
            <div style={{
            position: 'absolute', top: 0, left: 0,
            fontFamily: 'var(--font-mono)', fontSize: 11,
            letterSpacing: '0.1em',
            color: 'var(--ink-3)',
            textTransform: 'uppercase'
          }}>
              [Model] {model.sku}
            </div>
            {/* depth callout top-right */}
            <div style={{
            position: 'absolute', top: 0, right: 0,
            fontFamily: 'var(--font-mono)', fontSize: 11,
            letterSpacing: '0.1em',
            color: 'var(--ink-3)',
            textTransform: 'uppercase',
            textAlign: 'right'
          }}>
              [Depth] {fmtInches(depthDisplay)}{isDowndraft && <span style={{ color: 'var(--accent-deep)' }}> ▲</span>}
            </div>
          </>
        }
      </div>

      {/* Bottom annotation */}
      {showDims &&
      <div style={{
        marginTop: 36,
        display: 'flex', justifyContent: 'space-between',
        fontFamily: 'var(--font-mono)', fontSize: 10,
        color: 'var(--ink-4)', textTransform: 'uppercase', letterSpacing: '0.1em'
      }}>
          <span>Fig. {model.id} · front elevation</span>
          <span>{config?.airflow || 'updraft'} · {config?.gas === 'lpg' ? 'propane' : 'natural gas'}</span>
        </div>
      }
    </div>);

}

// ───────────────────────────────────────────────────── Running total (sticky)
function RunningTotal({ subtotal, crating, deposit, lead, configured }) {
  const total = subtotal + crating;
  return (
    <div style={{
      borderTop: '1px solid var(--rule)',
      background: 'var(--field)',
      padding: '20px 0'
    }}>
      <div style={{ display: 'flex', alignItems: 'baseline', gap: 24, flexWrap: 'wrap' }}>
        <div style={{ flex: 1, minWidth: 160 }}>
          <div className="mono upper" style={{ fontSize: 10, color: 'var(--ink-3)', letterSpacing: '0.12em', marginBottom: 6 }}>Running total</div>
          <div className="display" style={{ fontSize: 36, letterSpacing: '-0.01em' }}>{fmtUSD(total)}</div>
          <div className="mono" style={{ fontSize: 11, color: 'var(--ink-3)', marginTop: 4 }}>
            {fmtUSD(subtotal)} kiln + {fmtUSD(crating)} crate
          </div>
        </div>
        <div style={{ minWidth: 120 }}>
          <div className="mono upper" style={{ fontSize: 10, color: 'var(--ink-3)', letterSpacing: '0.12em', marginBottom: 6 }}>Deposit today</div>
          <div className="display" style={{ fontSize: 24 }}>{fmtUSD(deposit)}</div>
          <div className="mono" style={{ fontSize: 11, color: 'var(--ink-3)', marginTop: 4 }}>20% to start build</div>
        </div>
        <div style={{ minWidth: 120 }}>
          <div className="mono upper" style={{ fontSize: 10, color: 'var(--ink-3)', letterSpacing: '0.12em', marginBottom: 6 }}>Lead time</div>
          <div className="display" style={{ fontSize: 24 }}>{lead}</div>
          <div className="mono" style={{ fontSize: 11, color: 'var(--ink-3)', marginTop: 4 }}>weeks from deposit</div>
        </div>
      </div>
    </div>);

}

// ───────────────────────────────────────────────────── Footprint plan (top-down with door swing)
function FootprintPlan({ model, config, studio }) {
  // Render a top-down floor plan: kiln rectangle + door swing arc + control panel
  // studio: { ceiling, wallL, wallR, wallB, doorway }
  const [w, d] = model.footprint;
  const downDraft = config?.airflow === 'downdraft';
  const depth = downDraft ? d + 6 : d;

  // SVG units — 1in = 1 unit, then scale
  const padding = 60; // inches of margin around kiln
  const totalW = w + (studio?.wallL ?? 36) + (studio?.wallR ?? 36);
  const totalD = depth + (studio?.wallB ?? 24) + padding;
  const scale = Math.min(560 / totalW, 380 / totalD);

  const kilnX = studio?.wallL ?? 36;
  const kilnY = studio?.wallB ?? 24;

  const hingeRight = config?.door === 'right';
  const panelRight = config?.controls === 'right';

  // Door swing arc — door is the front face (top in plan view), opens 180°
  const doorPivotX = hingeRight ? kilnX + w : kilnX;
  const doorPivotY = kilnY;
  const doorWidth = w * 0.85;

  const wallLOK = (studio?.wallL ?? 36) >= 18;
  const wallROK = (studio?.wallR ?? 36) >= 18;
  const wallBOK = (studio?.wallB ?? 24) >= 12;
  const swingOK = doorWidth <= (hingeRight ? (studio?.wallR ?? 36) + w : (studio?.wallL ?? 36) + w);

  return (
    <div style={{ position: 'relative', width: '100%' }}>
      <svg
        viewBox={`0 0 ${totalW * scale} ${totalD * scale}`}
        width="100%"
        style={{ display: 'block', maxWidth: 560 }}>
        
        <defs>
          <pattern id="grid" x="0" y="0" width={6 * scale} height={6 * scale} patternUnits="userSpaceOnUse">
            <path d={`M ${6 * scale} 0 L 0 0 0 ${6 * scale}`} fill="none" stroke="var(--field-line)" strokeWidth="0.5" opacity="0.5" />
          </pattern>
          <pattern id="hatch" patternUnits="userSpaceOnUse" width="6" height="6" patternTransform="rotate(45)">
            <line x1="0" y1="0" x2="0" y2="6" stroke="var(--ink-4)" strokeWidth="1" />
          </pattern>
        </defs>

        {/* Grid */}
        <rect x="0" y="0" width={totalW * scale} height={totalD * scale} fill="url(#grid)" />

        {/* Walls (hatched edges) */}
        <rect x="0" y="0" width="6" height={totalD * scale} fill="url(#hatch)" />
        <rect x={totalW * scale - 6} y="0" width="6" height={totalD * scale} fill="url(#hatch)" />
        <rect x="0" y={totalD * scale - 6} width={totalW * scale} height="6" fill="url(#hatch)" />

        {/* Door swing arc */}
        <path
          d={`M ${(doorPivotX + (hingeRight ? -doorWidth : doorWidth)) * scale} ${doorPivotY * scale}
              A ${doorWidth * scale} ${doorWidth * scale} 0 0 ${hingeRight ? 1 : 0} ${doorPivotX * scale} ${(doorPivotY - doorWidth) * scale}`}
          fill="none"
          stroke="var(--accent)"
          strokeWidth="1"
          strokeDasharray="4 3"
          opacity="0.8" />
        
        <line
          x1={doorPivotX * scale}
          y1={doorPivotY * scale}
          x2={(doorPivotX + (hingeRight ? -doorWidth : doorWidth)) * scale}
          y2={doorPivotY * scale}
          stroke="var(--accent)"
          strokeWidth="1.5" />
        
        <line
          x1={doorPivotX * scale}
          y1={doorPivotY * scale}
          x2={doorPivotX * scale}
          y2={(doorPivotY - doorWidth) * scale}
          stroke="var(--accent)"
          strokeWidth="1.5"
          strokeDasharray="3 2"
          opacity="0.6" />
        

        {/* Kiln body */}
        <rect
          x={kilnX * scale}
          y={kilnY * scale}
          width={w * scale}
          height={depth * scale}
          fill="var(--ink)"
          opacity="0.92" />
        
        {/* Cyan stripe on front (door) */}
        <rect
          x={(kilnX + w * 0.55) * scale}
          y={kilnY * scale}
          width={3}
          height={depth * 0.4 * scale}
          fill="var(--accent)" />
        
        {/* Control panel (small box on side) */}
        <rect
          x={(panelRight ? kilnX + w : kilnX - 10) * scale}
          y={(kilnY + depth * 0.35) * scale}
          width={10 * scale}
          height={12 * scale}
          fill="var(--ink-2)" />
        

        {/* Dimension labels */}
        <text x={(kilnX + w / 2) * scale} y={(kilnY + depth + 16) * scale} textAnchor="middle"
        fontFamily="var(--font-mono)" fontSize="9" fill="var(--ink-3)">
          W {fmtInches(w)}
        </text>
        <text x={(kilnX + w + 14) * scale} y={(kilnY + depth / 2) * scale} textAnchor="middle"
        fontFamily="var(--font-mono)" fontSize="9" fill="var(--ink-3)"
        transform={`rotate(90 ${(kilnX + w + 14) * scale} ${(kilnY + depth / 2) * scale})`}>
          D {fmtInches(depth)}
        </text>

        {/* Door swing label */}
        <text
          x={(doorPivotX + (hingeRight ? -doorWidth / 2 : doorWidth / 2)) * scale}
          y={(doorPivotY - doorWidth / 2) * scale}
          textAnchor="middle"
          fontFamily="var(--font-mono)" fontSize="9" fill="var(--accent-deep)">
          
          swing {fmtInches(doorWidth)}
        </text>

        {/* Wall clearance dimensions */}
        {studio?.wallL != null &&
        <>
            <line x1="0" y1={(kilnY + depth + 30) * scale} x2={kilnX * scale} y2={(kilnY + depth + 30) * scale}
          stroke="var(--field-line)" strokeWidth="1" />
            <text x={kilnX / 2 * scale} y={(kilnY + depth + 28) * scale} textAnchor="middle"
          fontFamily="var(--font-mono)" fontSize="8" fill={wallLOK ? "var(--ink-3)" : "var(--warn)"}>
              L {fmtInches(studio.wallL)}
            </text>
          </>
        }
      </svg>
      <div style={{ marginTop: 12, display: 'flex', gap: 8, flexWrap: 'wrap' }}>
        <span className={`chip ${wallLOK ? 'ok' : 'warn'}`}>Left wall {wallLOK ? '✓' : '✕'}</span>
        <span className={`chip ${wallROK ? 'ok' : 'warn'}`}>Right wall {wallROK ? '✓' : '✕'}</span>
        <span className={`chip ${wallBOK ? 'ok' : 'warn'}`}>Behind {wallBOK ? '✓' : '✕'}</span>
        <span className={`chip ${swingOK ? 'ok' : 'warn'}`}>Door swing {swingOK ? '✓' : '✕'}</span>
      </div>
    </div>);

}

// ───────────────────────────────────────────────────── Volume viz (mug/bowl count)
function VolumeViz({ model, item = 'mug' }) {
  // Simple grid of stylized mug silhouettes
  // Estimate: a mug ≈ 6"x4"x4" plus packing = 96 cu in/mug → cuft/96
  const cuIn = model.capacity * 1728;
  const counts = {
    mug: Math.floor(cuIn / 240),
    bowl: Math.floor(cuIn / 380),
    plate: Math.floor(cuIn / 200),
    teapot: Math.floor(cuIn / 720)
  };
  const n = counts[item];
  const cols = 14;
  const rows = Math.ceil(Math.min(n, 280) / cols);
  const cells = Math.min(n, 280);

  return (
    <div>
      <div className="flex between items-baseline" style={{ marginBottom: 14 }}>
        <div className="mono upper" style={{ fontSize: 10, letterSpacing: '0.12em', color: 'var(--ink-3)' }}>
          Approx. load capacity
        </div>
        <div className="display" style={{ fontSize: 28 }}>
          {n.toLocaleString()} <span style={{ fontSize: 14, color: 'var(--ink-3)', fontFamily: 'var(--font-mono)' }}>{item}s</span>
        </div>
      </div>
      <svg viewBox={`0 0 ${cols * 22} ${rows * 22 + 4}`} width="100%">
        {Array.from({ length: cells }).map((_, i) => {
          const x = i % cols * 22 + 4;
          const y = Math.floor(i / cols) * 22 + 4;
          return (
            <g key={i} transform={`translate(${x},${y})`} opacity={0.85}>
              {item === 'mug' &&
              <>
                  <rect x="2" y="3" width="9" height="12" rx="1" fill="var(--ink-2)" />
                  <path d="M 11 5 Q 15 5 15 9 Q 15 13 11 13" fill="none" stroke="var(--ink-2)" strokeWidth="1.5" />
                </>
              }
              {item === 'bowl' &&
              <path d="M 1 6 Q 8 16 15 6 Z" fill="var(--ink-2)" />
              }
              {item === 'plate' &&
              <>
                  <ellipse cx="8" cy="9" rx="7" ry="2" fill="var(--ink-2)" />
                  <ellipse cx="8" cy="8" rx="5" ry="1" fill="var(--field)" />
                </>
              }
              {item === 'teapot' &&
              <>
                  <ellipse cx="8" cy="10" rx="6" ry="5" fill="var(--ink-2)" />
                  <path d="M 14 9 L 17 7 L 17 11 Z" fill="var(--ink-2)" />
                  <path d="M 2 9 Q -1 12 2 14" stroke="var(--ink-2)" fill="none" strokeWidth="1.5" />
                </>
              }
            </g>);

        })}
        {cells < n &&
        <text x={cols * 22 - 4} y={rows * 22 - 4} textAnchor="end"
        fontFamily="var(--font-mono)" fontSize="10" fill="var(--ink-3)">
            + {(n - cells).toLocaleString()} more
          </text>
        }
      </svg>
      <div className="mono" style={{ fontSize: 10, color: 'var(--ink-4)', marginTop: 8, letterSpacing: '0.08em' }}>
        Estimate · assumes ~80% packing efficiency · varies by shelf layout
      </div>
    </div>);

}

// ───────────────────────────────────────────────────── Footer
function Footer() {
  return (
    <footer className="footer">
      <div className="container">
        <div className="footer-grid">
          <div>
            <div style={{ fontFamily: 'var(--font-display)', fontSize: 28, color: 'var(--ink)', textTransform: 'none', letterSpacing: 'normal' }}>
              LE200 series</div>
            <div style={{ marginTop: 4, display: 'flex', alignItems: 'baseline', gap: 8 }}>
              <span style={{ fontSize: 12, color: 'var(--ink-3)', textTransform: 'uppercase', letterSpacing: '0.1em', fontFamily: 'var(--font-mono)' }}>by</span>
              <LagunaSig size={36} />
            </div>
            <p style={{ marginTop: 16, color: 'var(--ink-3)', textTransform: 'none', letterSpacing: 'normal', fontFamily: 'var(--font-body)', fontSize: 13, maxWidth: 320 }}>
              Front-loading gas kilns. Designed, fabricated, and crated in California since 1976. Precision made, built to last.
            </p>
          </div>
          <div>
            <div style={{ marginBottom: 10 }}>Configure</div>
            <div className="col gap-2" style={{ fontFamily: 'var(--font-body)', textTransform: 'none', letterSpacing: 'normal', fontSize: 13, color: 'var(--ink-2)' }}>
              <a>Size guide</a>
              <a>Fuel & insulation</a>
              <a>Upgrades</a>
              <a>Custom builds</a>
            </div>
          </div>
          <div>
            <div style={{ marginBottom: 10 }}>Resources</div>
            <div className="col gap-2" style={{ fontFamily: 'var(--font-body)', textTransform: 'none', letterSpacing: 'normal', fontSize: 13, color: 'var(--ink-2)' }}>
              <a>Installation manual</a>
              <a>Firing guides</a>
              <a>Warranty</a>
              <a>Service & parts</a>
            </div>
          </div>
          <div>
            <div style={{ marginBottom: 10 }}>Talk to us</div>
            <div className="col gap-2" style={{ fontFamily: 'var(--font-body)', textTransform: 'none', letterSpacing: 'normal', fontSize: 13, color: 'var(--ink-2)' }}>
              <a>800.4.LAGUNA</a>
              <a>kilns@lagunaclay.com</a>
              <a>Mon–Fri · 8a–5p PT</a>
            </div>
          </div>
        </div>
        <div className="rule-soft" style={{ marginTop: 40, paddingTop: 20, display: 'flex', justifyContent: 'space-between' }}>
          <span>© 2026 Laguna Clay Co. · ETL Intertek certified · AGA I-94 · C.S.A. C22.2</span>
          <span>Made in City of Industry, CA</span>
        </div>
      </div>
    </footer>);

}

// Pricing helpers ────────────────────────────────────────────
function computePrice(config, data) {
  const model = data.MODELS.find((m) => m.id === config.size);
  if (!model) return { subtotal: 0, crating: data.CRATING, total: data.CRATING, items: [] };

  const items = [];
  items.push({ label: model.sku + " base kiln", amount: model.price });

  for (const [groupId, group] of Object.entries(data.OPTIONS)) {
    if (group.onlyFor && !group.onlyFor.includes(config.size)) continue;
    const selId = config[groupId];
    const choice = group.choices.find((c) => c.id === selId);
    if (choice && choice.delta) {
      items.push({ label: `${group.label}: ${choice.label}`, amount: choice.delta });
    }
  }

  for (const up of data.UPGRADES) {
    if (config.upgrades?.[up.id]) {
      const amount = up.pricing[config.size] || 0;
      items.push({ label: up.label, amount });
    }
  }

  const subtotal = items.reduce((s, i) => s + i.amount, 0);
  return {
    subtotal,
    crating: data.CRATING,
    total: subtotal + data.CRATING,
    deposit: Math.round((subtotal + data.CRATING) * 0.2),
    items
  };
}

function leadTime(config, data) {
  // Base 12 weeks, +2 for downdraft, +2 for fiber, +1 for hood, +2 for forced air, +1 for programmable
  let weeks = 12;
  if (config.airflow === 'downdraft') weeks += 2;
  if (config.insulation === 'fiber') weeks += 2;
  if (config.insulation === 'b26') weeks += 1;
  if (config.upgrades?.hood) weeks += 1;
  if (config.upgrades?.forcedAir) weeks += 2;
  if (config.upgrades?.programmable) weeks += 1;
  return weeks + "-" + (weeks + 2);
}

// Export to window for cross-script access
Object.assign(window, {
  fmtUSD, fmtInches,
  LagunaSig, Crosshairs, TopNav, SectionHeader, Choice,
  DimensionedKiln, RunningTotal, FootprintPlan, VolumeViz, Footer,
  computePrice, leadTime
});