/* Timeless Totes — Quote builder */
const { useState, useRef, useEffect } = React;

/* ── Constants ──────────────────────────────────────────── */
const MIN_TOTAL      = 50;
const VOL_THRESHOLD  = 200;
const MAX_FILE_BYTES = 16 * 1024 * 1024; // 16 MB
const RASTER_EXTS    = ['PNG', 'JPG', 'JPEG'];
const RUSH_FEE       = 200;

const US_STATES = [
  'AL','AK','AZ','AR','CA','CO','CT','DE','DC','FL','GA',
  'HI','ID','IL','IN','IA','KS','KY','LA','ME','MD',
  'MA','MI','MN','MS','MO','MT','NE','NV','NH','NJ',
  'NM','NY','NC','ND','OH','OK','OR','PA','RI','SC',
  'SD','TN','TX','UT','VT','VA','WA','WV','WI','WY'
];

/* ── Helpers ─────────────────────────────────────────────── */
function lookupPrice(variantCode) {
  if (!variantCode || typeof VARIANT_PRICES === 'undefined') return null;
  var p = VARIANT_PRICES[variantCode];
  return typeof p === 'number' ? p : null;
}
function isValidEmail(v) {
  return /^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(v);
}
function fmtUSD(n) {
  return '$' + Number(n).toFixed(2);
}
function fileExt(name) {
  return name ? name.split('.').pop().toUpperCase() : null;
}
function isValidPantoneHex(v) {
  if (!v || !v.trim()) return true;
  var t = v.trim();
  return (
    /#[0-9A-Fa-f]{3,6}/.test(t) ||
    /(?:pms|pantone)\s*\d+/i.test(t) ||
    /\b\d+\s*c\b/i.test(t)
  );
}
function isFutureDate(v) {
  if (!v) return true;
  return new Date(v + 'T00:00:00') > new Date();
}
function isValidZip(v) {
  return /^\d{5}(-\d{4})?$/.test((v || '').trim());
}

/* ── buildQuoteData ──────────────────────────────────────── */
function buildQuoteData(items, spec) {
  var now      = new Date();
  var stdStart = new Date(now); stdStart.setDate(now.getDate() + 42);
  var stdEnd   = new Date(now); stdEnd.setDate(now.getDate() + 56);
  var fmtD = function(d) {
    return d.toLocaleDateString('en-US', { month: 'long', day: 'numeric', year: 'numeric' });
  };
  var artworkFileType = fileExt(spec.file);
  var isRaster = artworkFileType && RASTER_EXTS.includes(artworkFileType);

  var mappedItems = items.map(function(item) {
    var isCustom = item.slug === 'custom-bag';
    var uPrice   = isCustom ? null : lookupPrice(item.size);
    var lTotal   = uPrice !== null ? uPrice * item.qty : null;
    var isPocket = item.size && item.size.toLowerCase().includes('pocket');
    return {
      productFamily:           isCustom ? 'Custom Bag' : item.name,
      productVariant:          isCustom ? 'Custom' : (item.size || item.name),
      sizeMeasurement:         isCustom ? null : item.size,
      quantity:                item.qty,
      trimColor:               item.trimMatchZipper
                                 ? ('Match zipper (' + item.zipperColor + ')')
                                 : (item.trimNotes || ('Match zipper (' + item.zipperColor + ')')),
      printColorCount:         item.colors,
      pantoneColors:           item.pantone || null,
      printPosition:           item.placement,
      printPlacementNotes:     item.printAreaNotes || null,
      pocketOption:            item.slug === 'craft-case' ? (isPocket ? true : false) : null,
      zipperOption:            item.zipperColor,
      doubleSided:             item.doubleSided,
      estimatedUnitPrice:      uPrice,
      estimatedLineTotal:      lTotal,
      itemNotes:               item.notes || null,
      customDescription:       item.customDescription || null,
      customDimensions:        item.customDimensions  || null,
      customIntendedUse:       item.customIntendedUse || null,
      customConstructionNotes: item.customConstructionNotes || null,
    };
  });

  var totalQty    = items.reduce(function(s, i) { return s + i.qty; }, 0);
  var skuOver200  = items.some(function(i) { return i.qty > VOL_THRESHOLD; });
  var pricedLines = mappedItems.filter(function(mi) {
    return mi.productFamily !== 'Custom Bag' && mi.estimatedLineTotal !== null;
  });
  var anyUnpriced = mappedItems.some(function(mi) {
    return mi.productFamily !== 'Custom Bag' && mi.estimatedLineTotal === null;
  });
  var estSubtotal = pricedLines.reduce(function(s, mi) { return s + mi.estimatedLineTotal; }, 0);

  var shipParts = [spec.shipStreet, spec.shipCity, spec.shipState, spec.shipZip].filter(Boolean);
  var billParts = [spec.billStreet, spec.billCity, spec.billState, spec.billZip].filter(Boolean);

  return {
    customerName:            spec.name,
    companyName:             spec.business || null,
    customerEmail:           spec.email,
    customerPhone:           spec.phone,
    shippingAddress:         shipParts.join(', '),
    billingSameAsShipping:   spec.billingSameAsShipping !== false,
    billingAddress:          spec.billingSameAsShipping !== false ? null : billParts.join(', '),
    standardWindow:          fmtD(stdStart) + ' - ' + fmtD(stdEnd),
    hasRequiredDeadline:     !!spec.rush,
    requiredDate:            spec.date || null,
    timingNotes:             spec.deadlineNotes || null,
    rushTimelineFlag:        !!spec.rush,
    rushFeeEstimate:         spec.rush ? RUSH_FEE : 0,
    /* order-level artwork */
    artworkUploaded:         !!spec.file,
    artworkFileName:         spec.file || null,
    artworkFileType:         artworkFileType,
    artworkAttached:         !!spec.fileObj,
    artworkAttachmentData:   null,   /* filled in at submit by FileReader */
    artworkPrepFlag:         !!isRaster,
    artworkPlacementNotes:   spec.globalNotes || null,
    /* items */
    items:                   mappedItems,
    totalQuantity:           totalQty,
    minimumMet:              totalQty >= MIN_TOTAL,
    skuOver200Flag:          skuOver200,
    discountFlag:            skuOver200,
    estimatedSubtotal:       anyUnpriced ? null : estSubtotal,
    subtotalIncomplete:      anyUnpriced,
    artworkPrepEstimateFlag: !!isRaster,
    additionalNotes:         spec.additionalNotes || null,
  };
}

/* ── blankItem ───────────────────────────────────────────── */
function blankItem(product) {
  if (product.itemId) return product;
  if (product.slug === 'custom-bag') {
    return {
      slug: 'custom-bag',
      name: 'Custom Bag / Custom Size Request',
      accent: 'navy',
      cardImg: null,
      size: 'custom',
      qty: 100,
      colors: 1,
      zipperColor: 'Black',
      trimMatchZipper: false,
      trimNotes: '',
      placement: 'Centered',
      pantone: '',
      doubleSided: false,
      printAreaNotes: '',
      customDescription: '',
      customDimensions: '',
      customIntendedUse: '',
      customConstructionNotes: '',
      notes: '',
    };
  }
  var prod = PRODUCTS.find(function(p) { return p.slug === product.slug; }) || PRODUCTS[0];
  var firstVariant = prod.variants ? prod.variants[0].code : '';
  return {
    itemId: Date.now() + Math.random(),
    slug: product.slug,
    name: product.name,
    accent: product.accent,
    cardImg: product.cardImg,
    size: firstVariant,
    qty: 10,
    colors: 1,
    zipperColor: 'Black',
    trimMatchZipper: false,
    trimNotes: '',
    placement: 'Centered',
    pantone: '',
    doubleSided: false,
    printAreaNotes: '',
    notes: '',
  };
}

/* ── Stepper ─────────────────────────────────────────────── */
function Stepper({ steps, current }) {
  return (
    <div style={{ display: "flex", alignItems: "center", gap: 6, flexWrap: "wrap" }}>
      {steps.map(function(s, i) {
        var done = i < current, active = i === current;
        return (
          <React.Fragment key={s}>
            <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
              <span style={{
                width: 26, height: 26, borderRadius: "50%", flexShrink: 0,
                display: "flex", alignItems: "center", justifyContent: "center",
                fontSize: ".78rem", fontWeight: 700,
                background: done ? "var(--teal)" : active ? "var(--navy)" : "var(--white)",
                color: done || active ? "#fff" : "var(--ink-faint)",
                border: "1.5px solid " + (done ? "var(--teal)" : active ? "var(--navy)" : "var(--line)"),
              }}>{done ? <Icon name="check" size={14} /> : i + 1}</span>
              <span style={{ fontSize: ".85rem", fontWeight: 600, color: active ? "var(--ink)" : "var(--ink-faint)" }} className="step-label">{s}</span>
            </div>
            {i < steps.length - 1 && <span style={{ flex: 1, minWidth: 14, height: 1.5, background: done ? "var(--teal)" : "var(--line)" }} />}
          </React.Fragment>
        );
      })}
    </div>
  );
}

/* ── UploadZone ──────────────────────────────────────────── */
function UploadZone({ file, onFile }) {
  var [drag, setDrag] = useState(false);
  var [uploadError, setUploadError] = useState('');
  var ref = useRef();

  function validateAndAccept(files) {
    setUploadError('');
    if (!files || files.length === 0) return;
    if (files.length > 1) {
      setUploadError('Please upload one logo/artwork file per quote. Timeless Totes will use this logo across the selected products.');
      return;
    }
    var f = files[0];
    if (f.size > MAX_FILE_BYTES) {
      setUploadError('Maximum artwork file size is 16 MB. If your file is larger, please submit the quote without attaching it and contact Timeless Totes about sending the artwork separately.');
      return;
    }
    onFile(f.name, f);
  }

  return (
    <div>
      <div
        onDragOver={function(e) { e.preventDefault(); setDrag(true); }}
        onDragLeave={function() { setDrag(false); }}
        onDrop={function(e) { e.preventDefault(); setDrag(false); validateAndAccept(e.dataTransfer.files); }}
        onClick={function() { ref.current.click(); }}
        style={{
          border: "2px dashed " + (drag ? "var(--teal)" : uploadError ? "#FCA5A5" : "var(--line)"),
          borderRadius: "var(--r-md)", padding: "34px 24px", textAlign: "center",
          cursor: "pointer", background: drag ? "var(--teal-tint)" : "var(--cream)",
          transition: "border-color .15s, background .15s",
        }}>
        <input ref={ref} type="file" hidden accept=".ai,.eps,.pdf,.svg,.png,.jpg,.jpeg"
          onChange={function(e) { validateAndAccept(e.target.files); e.target.value = ''; }} />
        <div style={{ color: file ? "var(--forest)" : "var(--navy-300)", display: "flex", justifyContent: "center", marginBottom: 12 }}>
          <Icon name={file ? "check" : "upload"} size={32} stroke={1.5} />
        </div>
        {file ? (
          <div><strong>{file}</strong><div style={{ fontSize: ".84rem", color: "var(--ink-soft)", marginTop: 4 }}>Click to replace</div></div>
        ) : (
          <div>
            <strong style={{ fontSize: "1rem" }}>Drop your logo here or click to browse</strong>
            <div style={{ fontSize: ".86rem", color: "var(--ink-soft)", marginTop: 6 }}>SVG, PDF, AI, EPS, PNG, JPG &middot; One file &middot; Up to 16 MB</div>
          </div>
        )}
      </div>
      {uploadError && (
        <div style={{ marginTop: 10, padding: "10px 14px", background: "#FEE2E2", borderRadius: 8, border: "1px solid #FCA5A5", fontSize: ".86rem", color: "#991B1B", lineHeight: 1.5 }}>
          {uploadError}
        </div>
      )}
      <p style={{ fontSize: ".82rem", color: "var(--ink-soft)", margin: "10px 0 0", lineHeight: 1.55 }}>
        Upload one logo/artwork file up to 16 MB. Vector files are preferred (.ai, .eps, .pdf, .svg). If your production file is larger, submit the quote without attaching it and Timeless Totes will request the artwork separately.
      </p>
    </div>
  );
}

/* ── Toggle ──────────────────────────────────────────────── */
function Toggle({ label, hint, on, onChange, accent }) {
  var ac = accent || "teal";
  return (
    <button onClick={function() { onChange(!on); }} style={{ display: "flex", alignItems: "center", gap: 14, width: "100%", textAlign: "left", background: on ? ("var(--" + ac + "-tint)") : "#fff", border: "1.5px solid " + (on ? ("var(--" + ac + ")") : "var(--line)"), borderRadius: 12, padding: "14px 16px", transition: "all .15s", fontFamily: "var(--sans)", cursor: "pointer" }}>
      <span style={{ width: 44, height: 26, borderRadius: 100, background: on ? ("var(--" + ac + ")") : "var(--line)", flexShrink: 0, position: "relative", transition: "background .18s" }}>
        <span style={{ position: "absolute", top: 3, left: on ? 21 : 3, width: 20, height: 20, borderRadius: "50%", background: "#fff", transition: "left .18s", boxShadow: "0 1px 3px rgba(0,0,0,.2)" }} />
      </span>
      <span style={{ flex: 1 }}><strong style={{ fontSize: ".95rem", display: "block" }}>{label}</strong>{hint && <span style={{ fontSize: ".82rem", color: "var(--ink-soft)" }}>{hint}</span>}</span>
    </button>
  );
}

/* ── StepHead ────────────────────────────────────────────── */
function StepHead({ t, d }) {
  return (
    <div style={{ marginBottom: 26 }}>
      <h2 style={{ fontSize: "1.7rem", marginBottom: 8 }}>{t}</h2>
      <p style={{ color: "var(--ink-soft)", margin: 0 }}>{d}</p>
    </div>
  );
}

/* ── LineItemCard ────────────────────────────────────────── */
function LineItemCard({ item, idx, onUpdate, onRemove, ctx }) {
  var isCustomBag = item.slug === "custom-bag";
  var prod = !isCustomBag ? (PRODUCTS.find(function(p) { return p.slug === item.slug; }) || PRODUCTS[0]) : null;
  var isCraftCase = item.slug === "craft-case";
  var hasVariants = prod && prod.variants && prod.variants.length > 0;
  var sizeOptions = hasVariants
    ? prod.variants.map(function(v) { return v.code; })
    : (prod && prod.sizes ? prod.sizes : ["Standard", "Large"]);
  var colorHint = item.colors === 1
    ? "1 color included in base setup"
    : ((item.colors - 1) + " additional color" + (item.colors > 2 ? "s" : "") + " — upcharge to be reviewed");

  var uPrice = !isCustomBag ? lookupPrice(item.size) : null;
  var lTotal = uPrice !== null ? uPrice * item.qty : null;
  var pantoneInvalid = item.pantone && !isValidPantoneHex(item.pantone);

  return (
    <div className="card" style={{ padding: "20px 24px", marginBottom: 14 }}>
      <div style={{ display: "flex", alignItems: "flex-start", gap: 12, marginBottom: 16 }}>
        {!isCustomBag && (
          <ProductImage src={item.cardImg} label="" accent={item.accent} compact
            style={{ width: 52, height: 52, borderRadius: 10, flexShrink: 0 }} />
        )}
        {isCustomBag && (
          <span style={{ width: 52, height: 52, borderRadius: 10, background: "var(--navy)", color: "#fff", display: "flex", alignItems: "center", justifyContent: "center", flexShrink: 0 }}>
            <Icon name="pencil" size={24} />
          </span>
        )}
        <div style={{ flex: 1 }}>
          <strong style={{ fontSize: "1.05rem" }}>{item.name}</strong>
        </div>
        <button onClick={function() { ctx.navigate("#/design-lab"); }}
          style={{ fontSize: ".82rem", background: "var(--cream)", border: "1px solid var(--line)", borderRadius: 8, padding: "6px 11px", color: "var(--navy)", fontWeight: 600, fontFamily: "var(--sans)", cursor: "pointer", display: "flex", alignItems: "center", gap: 6 }}>
          <Icon name="image" size={14} /> View Mockup
        </button>
        <button onClick={function() { onRemove(idx); }}
          style={{ background: "none", border: "none", color: "var(--ink-faint)", cursor: "pointer", padding: 4 }}>
          <Icon name="x" size={18} />
        </button>
      </div>

      {isCraftCase && item.size && (
        <div style={{ fontSize: ".85rem", color: "var(--ink-soft)", marginBottom: 10, padding: "8px 12px", background: "var(--cream)", borderRadius: 8, border: "1px solid var(--line)" }}>
          Selected: <strong>{item.size}</strong>{item.size.toLowerCase().includes("pocket") ? " (with pocket)" : " (no pocket)"}
        </div>
      )}

      {isCustomBag && (
        <div style={{ padding: "12px 16px", background: "var(--cream)", borderRadius: 10, fontSize: ".88rem", color: "var(--ink-soft)", marginBottom: 14, lineHeight: 1.55 }}>
          Custom bag sizes require a <strong>100-piece minimum</strong>.
        </div>
      )}

      {isCustomBag && (
        <div className="field">
          <label>Describe the custom bag or size you need <span className="req">*</span></label>
          <textarea className="textarea" placeholder="e.g. Clear vinyl tote with a 5-inch gusset, approx. 14 wide x 16 tall, zipper close..." value={item.customDescription || ""}
            onChange={function(e) { onUpdate(idx, "customDescription", e.target.value); }} />
          {!item.customDescription && <div style={{ fontSize: ".8rem", color: "#C0392B", marginTop: 4 }}>Required — please describe your custom request.</div>}
        </div>
      )}

      {isCustomBag && (
        <div className="field-row">
          <div className="field">
            <label>Desired dimensions <span className="hint">(optional)</span></label>
            <input className="input" placeholder='e.g. 12" w x 14" h x 4" gusset' value={item.customDimensions || ""}
              onChange={function(e) { onUpdate(idx, "customDimensions", e.target.value); }} />
          </div>
          <div className="field">
            <label>Intended use <span className="hint">(optional)</span></label>
            <input className="input" placeholder="e.g. retail kit bag, event tote" value={item.customIntendedUse || ""}
              onChange={function(e) { onUpdate(idx, "customIntendedUse", e.target.value); }} />
          </div>
        </div>
      )}

      {isCustomBag && (
        <div className="field">
          <label>Special construction notes <span className="hint">(optional)</span></label>
          <input className="input" placeholder="e.g. reinforced binding, front pocket, snap close..." value={item.customConstructionNotes || ""}
            onChange={function(e) { onUpdate(idx, "customConstructionNotes", e.target.value); }} />
        </div>
      )}

      <div className="field-row">
        {!isCustomBag && (
          <div className="field">
            <label>Size</label>
            <select className="select" value={item.size}
              onChange={function(e) { onUpdate(idx, "size", e.target.value); }}>
              {sizeOptions.map(function(s) { return <option key={s}>{s}</option>; })}
              <option value="custom">Custom size (100-piece min.)</option>
            </select>
          </div>
        )}
        <div className="field">
          <label>Quantity {isCustomBag && <span className="hint">(100-piece minimum)</span>}</label>
          <input className="input" type="number" min={isCustomBag ? 100 : 1} value={item.qty}
            onChange={function(e) { onUpdate(idx, "qty", Math.max(isCustomBag ? 100 : 1, +e.target.value || (isCustomBag ? 100 : 1))); }} />
          {item.qty > VOL_THRESHOLD && !isCustomBag && (
            <div style={{ fontSize: ".8rem", color: "var(--forest)", marginTop: 4 }}>Above 200 — possible 10% volume discount. Confirmed on your quote.</div>
          )}
        </div>
      </div>

      <div className="field">
        <label>Ink colors (1 included)</label>
        <div style={{ display: "flex", gap: 8 }}>
          {[1, 2, 3, 4].map(function(c) {
            return (
              <button key={c} onClick={function() { onUpdate(idx, "colors", c); }}
                style={{ flex: 1, padding: "11px 0", borderRadius: 8, border: "1.5px solid " + (item.colors === c ? "var(--teal)" : "var(--line)"), background: item.colors === c ? "var(--teal-tint)" : "#fff", color: item.colors === c ? "var(--teal-600)" : "var(--ink)", fontWeight: 700, cursor: "pointer", fontSize: ".95rem", fontFamily: "var(--sans)" }}>
                {c}
              </button>
            );
          })}
        </div>
        <div className="hint" style={{ marginTop: 6 }}>{colorHint}</div>
      </div>

      <div className="field">
        <label>Pantone / hex ink color notes</label>
        <input className="input" placeholder="e.g. PMS 322 C, #0F766E" value={item.pantone}
          onChange={function(e) { onUpdate(idx, "pantone", e.target.value); }}
          style={pantoneInvalid ? { borderColor: "#C0392B" } : {}} />
        {pantoneInvalid ? (
          <div style={{ fontSize: ".8rem", color: "#C0392B", marginTop: 4, lineHeight: 1.4 }}>
            Use a Pantone/PMS number (e.g. PMS 322 C) or hex code (e.g. #0F766E). Plain color names are not accepted.
          </div>
        ) : (
          <div className="hint" style={{ marginTop: 5 }}>Custom ink colors may require a larger minimum — confirmed on your quote.</div>
        )}
      </div>

      <div className="field-row">
        <div className="field">
          <label>Zipper color</label>
          <select className="select" value={item.zipperColor}
            onChange={function(e) { onUpdate(idx, "zipperColor", e.target.value); }}>
            <option>Black</option>
            <option>White</option>
            <option>Navy</option>
            <option>Clear</option>
            <option>Match to brand</option>
          </select>
        </div>
        <div className="field">
          <label>Print placement</label>
          <select className="select" value={item.placement}
            onChange={function(e) { onUpdate(idx, "placement", e.target.value); }}>
            <option>Centered</option>
            <option>Top left</option>
            <option>Top right</option>
            <option>Bottom left</option>
            <option>Bottom right</option>
            <option value="mockup">See mockup</option>
          </select>
          {item.placement === "mockup" && (
            <button onClick={function() { ctx.navigate("#/design-lab"); }}
              style={{ marginTop: 6, fontSize: ".82rem", background: "var(--cream)", border: "1px solid var(--line)", borderRadius: 8, padding: "5px 11px", color: "var(--navy)", fontWeight: 600, fontFamily: "var(--sans)", cursor: "pointer", display: "flex", alignItems: "center", gap: 6 }}>
              <Icon name="image" size={14} /> Open Design Lab
            </button>
          )}
        </div>
      </div>

      <div className="field">
        <Toggle label="Match trim to zipper color (Default)"
          hint="Trim matches the webbing and tape — same finish as your selected zipper"
          on={item.trimMatchZipper}
          onChange={function(v) { onUpdate(idx, "trimMatchZipper", v); }} />
        {!item.trimMatchZipper && (
          <input className="input" style={{ marginTop: 8 }} placeholder="Trim / taping color notes (optional)"
            value={item.trimNotes} onChange={function(e) { onUpdate(idx, "trimNotes", e.target.value); }} />
        )}
      </div>

      <div className="field">
        <label>Special print area or placement notes</label>
        <input className="input" placeholder="e.g. front pocket only, 4-inch wide centered, wrap print..."
          value={item.printAreaNotes} onChange={function(e) { onUpdate(idx, "printAreaNotes", e.target.value); }} />
      </div>

      <div className="field" style={{ marginBottom: 0 }}>
        <Toggle label="Double-sided print"
          hint="Second screen setup + per-unit upcharge — confirmed on your quote"
          on={item.doubleSided}
          onChange={function(v) { onUpdate(idx, "doubleSided", v); }} />
      </div>

      {!isCustomBag && (
        <div style={{ marginTop: 14, paddingTop: 14, borderTop: "1px solid var(--line-soft)", display: "flex", justifyContent: "space-between", alignItems: "baseline" }}>
          <span style={{ fontSize: ".82rem", color: "var(--ink-soft)" }}>
            {uPrice !== null
              ? ("Est. " + item.qty + " x " + fmtUSD(uPrice))
              : "Price to be reviewed"}
          </span>
          {lTotal !== null && (
            <span style={{ fontWeight: 700, color: "var(--ink)" }}>{fmtUSD(lTotal)} est.</span>
          )}
        </div>
      )}
    </div>
  );
}

/* ── EstimatePanel ───────────────────────────────────────── */
function EstimatePanel({ items, spec, sample }) {
  if (sample) {
    return (
      <div className="card" style={{ padding: 24, position: "sticky", top: 96 }}>
        <h3 style={{ fontSize: "1.15rem", marginBottom: 8 }}>Sample request</h3>
        <p style={{ fontSize: ".9rem", color: "var(--ink-soft)", margin: 0 }}>No charge estimate for samples. Our team will confirm availability and any shipping cost.</p>
      </div>
    );
  }

  if (!items || items.length === 0) {
    return (
      <div className="card" style={{ padding: 24, position: "sticky", top: 96 }}>
        <h3 style={{ fontSize: "1.15rem", marginBottom: 8 }}>Estimate</h3>
        <p style={{ fontSize: ".9rem", color: "var(--ink-soft)" }}>Add products above to see estimated pricing.</p>
      </div>
    );
  }

  var totalQty    = items.reduce(function(s, i) { return s + i.qty; }, 0);
  var belowMin    = totalQty < MIN_TOTAL;
  var regularItems = items.filter(function(i) { return i.slug !== "custom-bag"; });
  var customItems  = items.filter(function(i) { return i.slug === "custom-bag"; });
  var artFileType  = fileExt(spec.file);
  var isRaster     = artFileType && RASTER_EXTS.includes(artFileType);

  var pricedLines   = regularItems.filter(function(i) { return lookupPrice(i.size) !== null; });
  var unpricedLines = regularItems.filter(function(i) { return lookupPrice(i.size) === null; });
  var estSubtotal   = pricedLines.reduce(function(s, i) { return s + lookupPrice(i.size) * i.qty; }, 0);
  var incomplete    = unpricedLines.length > 0;

  return (
    <div className="card" style={{ padding: 24, position: "sticky", top: 96 }}>
      <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 14 }}>
        <h3 style={{ fontSize: "1.15rem" }}>Estimate</h3>
        <span className="chip solid-teal" style={{ fontSize: ".72rem" }}>For review only</span>
      </div>

      {belowMin && (
        <div style={{ padding: "10px 14px", background: "#FFF3CD", borderRadius: 8, fontSize: ".84rem", color: "#856404", marginBottom: 14, display: "flex", gap: 8, alignItems: "flex-start" }}>
          <Icon name="spark" size={15} style={{ flexShrink: 0, marginTop: 1 }} />
          <span><strong>{totalQty} / 50</strong> piece minimum — add more to qualify.</span>
        </div>
      )}

      <div style={{ display: "flex", flexDirection: "column", gap: 12, marginBottom: 16 }}>
        {regularItems.map(function(item, i) {
          var uPrice = lookupPrice(item.size);
          var lTotal = uPrice !== null ? uPrice * item.qty : null;
          return (
            <div key={i} style={{ paddingBottom: 12, borderBottom: (i < regularItems.length - 1 || customItems.length > 0) ? "1px solid var(--line-soft)" : "none" }}>
              <div style={{ fontWeight: 700, fontSize: ".88rem", marginBottom: 4 }}>{item.name}</div>
              <div style={{ fontSize: ".82rem", color: "var(--ink-soft)", marginBottom: 4 }}>{item.size}</div>
              <div style={{ display: "flex", justifyContent: "space-between", fontSize: ".84rem" }}>
                <span style={{ color: "var(--ink-soft)" }}>
                  {uPrice !== null ? (item.qty + " x " + fmtUSD(uPrice)) : "Price to be reviewed"}
                </span>
                {lTotal !== null && (
                  <span style={{ fontWeight: 700, color: "var(--ink)" }}>{fmtUSD(lTotal)}</span>
                )}
              </div>
              {item.colors > 1 && (
                <div style={{ fontSize: ".78rem", color: "var(--ink-faint)", marginTop: 3 }}>+{item.colors - 1} color upcharge to be reviewed</div>
              )}
              {item.doubleSided && (
                <div style={{ fontSize: ".78rem", color: "var(--ink-faint)", marginTop: 2 }}>Double-sided upcharge to be reviewed</div>
              )}
              {item.qty > VOL_THRESHOLD && (
                <div style={{ fontSize: ".78rem", color: "var(--forest)", marginTop: 2 }}>200+ pcs — possible 10% discount</div>
              )}
            </div>
          );
        })}

        {customItems.map(function(item, i) {
          return (
            <div key={"c" + i} style={{ paddingBottom: 12, borderBottom: i < customItems.length - 1 ? "1px solid var(--line-soft)" : "none" }}>
              <div style={{ fontWeight: 700, fontSize: ".88rem", marginBottom: 2 }}>Custom Bag / Custom Size</div>
              <div style={{ fontSize: ".83rem", color: "var(--ink-soft)" }}>{item.qty} pieces</div>
              <div style={{ fontSize: ".79rem", color: "var(--teal-600)", marginTop: 3 }}>Pricing to be reviewed</div>
            </div>
          );
        })}
      </div>

      <div style={{ borderTop: "1px solid var(--line)", paddingTop: 14 }}>
        <div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline", marginBottom: 4 }}>
          <span style={{ fontSize: ".9rem", fontWeight: 600 }}>Est. subtotal</span>
          {incomplete ? (
            <span style={{ fontSize: ".82rem", color: "var(--ink-soft)", fontStyle: "italic" }}>Incomplete</span>
          ) : (
            <span style={{ fontWeight: 700, fontSize: "1.25rem", color: "var(--navy)" }}>{fmtUSD(estSubtotal)}</span>
          )}
        </div>
        {incomplete && (
          <div style={{ fontSize: ".78rem", color: "var(--ink-faint)", marginBottom: 8 }}>Some items need price review by Timeless Totes.</div>
        )}
        {spec.rush && (
          <div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline", marginTop: 6, paddingTop: 6, borderTop: "1px dashed var(--line)" }}>
            <span style={{ fontSize: ".84rem", color: "#856404", fontWeight: 600 }}>Rush handling fee (est.)</span>
            <span style={{ fontWeight: 700, color: "#856404" }}>+{fmtUSD(RUSH_FEE)}</span>
          </div>
        )}
        {spec.rush && !incomplete && (
          <div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline", marginTop: 6 }}>
            <span style={{ fontSize: ".84rem", fontWeight: 600 }}>Est. total with rush</span>
            <span style={{ fontWeight: 700, color: "var(--navy)" }}>{fmtUSD(estSubtotal + RUSH_FEE)}</span>
          </div>
        )}
        {isRaster && (
          <div style={{ fontSize: ".78rem", color: "#856404", marginTop: 6 }}>Artwork prep may apply: est. $25-$50</div>
        )}
      </div>

      <p style={{ fontSize: ".78rem", color: "var(--ink-soft)", margin: "14px 0 0", display: "flex", gap: 8, lineHeight: 1.5 }}>
        <Icon name="shield" size={16} style={{ color: "var(--teal)", flexShrink: 0 }} />
        Estimate only. Final quote confirmed after artwork and production review. No payment until you approve.
      </p>
    </div>
  );
}

/* ── Success screen ──────────────────────────────────────── */
function SuccessScreen({ ctx, sample }) {
  return (
    <section className="section">
      <div className="wrap-narrow" style={{ textAlign: "center" }}>
        <div style={{ width: 76, height: 76, borderRadius: "50%", background: "var(--forest-tint)", color: "var(--forest)", display: "flex", alignItems: "center", justifyContent: "center", margin: "0 auto 26px" }}>
          <Icon name="check" size={38} stroke={2} />
        </div>
        <h1 style={{ marginBottom: 16 }}>{sample ? "Sample request received" : "Quote request received"}</h1>
        <p className="lede" style={{ marginBottom: 36 }}>
          {sample
            ? "Your sample request has been sent to Timeless Totes. Our team will confirm sample availability and follow up directly."
            : "Your quote request has been sent to Timeless Totes. Our team will review the details and follow up after confirming your order."}
        </p>
        <div className="card" style={{ padding: 30, textAlign: "left", marginBottom: 32 }}>
          <h3 style={{ fontSize: "1.15rem", marginBottom: 20 }}>What happens next</h3>
          {[
            ["mail",    "We review your quote request",    "A specialist reviews your details and reaches out with any questions — usually within one business day."],
            ["palette", "Artwork review and proof",         "Our artwork partner reviews your files and prepares a digital proof for your approval."],
            ["check",   "Confirmed quote via QuickBooks",   "You receive a final quote. Timeless Totes invoices through QuickBooks after your approval — never before."],
            ["truck",   "Production begins",                "Once approved, your USA-made order goes into production. Standard lead time is 6-8 weeks from approval."],
          ].map(function(row, i) {
            return (
              <div key={row[1]} style={{ display: "flex", gap: 16, padding: "14px 0", borderBottom: i < 3 ? "1px solid var(--line-soft)" : "none" }}>
                <span style={{ width: 40, height: 40, borderRadius: 10, background: "var(--navy)", color: "#fff", display: "flex", alignItems: "center", justifyContent: "center", flexShrink: 0 }}><Icon name={row[0]} size={20} /></span>
                <div><strong>{row[1]}</strong><p style={{ margin: "3px 0 0", fontSize: ".9rem", color: "var(--ink-soft)" }}>{row[2]}</p></div>
              </div>
            );
          })}
        </div>
        <div style={{ display: "flex", gap: 12, justifyContent: "center", flexWrap: "wrap" }}>
          <button className="btn btn-primary" onClick={function() { ctx.navigate("#/"); }}>Back to home</button>
          <button className="btn btn-ghost" onClick={function() { ctx.navigate("#/products"); }}>Browse more products</button>
        </div>
      </div>
    </section>
  );
}

/* ── QuotePage ───────────────────────────────────────────── */
function QuotePage({ ctx, mode }) {
  var sample = mode === "sample";
  var [view, setView] = useState(sample ? "detailed" : (ctx.cart.length > 0 ? "detailed" : "choose"));
  var [step, setStep] = useState(0);

  var [items, setItems] = useState(function() {
    return ctx.cart.map(blankItem);
  });

  /* Initialize spec — pick up artwork from Design Lab if already uploaded */
  var [spec, setSpec] = useState(function() {
    var qa = ctx.quoteArtwork;
    return {
      file:    qa ? qa.fileName : "",
      fileObj: qa ? qa.file    : null,
      rush: false, date: "",
      shipStreet: "", shipCity: "", shipState: "", shipZip: "",
      globalNotes: "", deadlineNotes: "",
      name: "", business: "", email: "", confirmEmail: "", phone: "",
      billingSameAsShipping: true,
      billStreet: "", billCity: "", billState: "", billZip: "",
      additionalNotes: "",
    };
  });

  var [showArtworkConfirm,  setShowArtworkConfirm]  = useState(false);
  var [showShippingErrors,  setShowShippingErrors]   = useState(false);
  var [showDateError,       setShowDateError]        = useState(false);
  var [showContactErrors,   setShowContactErrors]    = useState(false);
  var [submitting,  setSubmitting]  = useState(false);
  var [submitError, setSubmitError] = useState(false);

  useEffect(function() { window.scrollTo(0, 0); }, [view, step]);

  if (view === "done") return <main><SuccessScreen ctx={ctx} sample={sample} /></main>;

  var setS = function(k, v) { setSpec(function(s) { var n = Object.assign({}, s); n[k] = v; return n; }); };

  /* Apply artwork to both local spec and shared ctx */
  var applyArtwork = function(name, fileObj) {
    var ext = fileExt(name);
    setSpec(function(s) { return Object.assign({}, s, { file: name, fileObj: fileObj }); });
    ctx.setQuoteArtwork({
      fileName: name,
      fileType: ext,
      fileSize: fileObj ? fileObj.size : null,
      file: fileObj,
      previewSrc: null,
      artworkPrepFlag: RASTER_EXTS.includes(ext),
    });
  };

  /* Remove artwork from local spec and shared ctx */
  var removeArtwork = function() {
    setSpec(function(s) { return Object.assign({}, s, { file: '', fileObj: null }); });
    ctx.clearQuoteArtwork();
    setShowArtworkConfirm(false);
  };

  var updateItem = function(idx, k, v) {
    setItems(function(arr) { return arr.map(function(item, i) { return i === idx ? Object.assign({}, item, { [k]: v }) : item; }); });
  };
  var removeItem = function(idx) {
    setItems(function(arr) { return arr.filter(function(_, i) { return i !== idx; }); });
    ctx.removeFromQuote(idx);
  };
  var addExtraProduct = function(product) {
    ctx.addToQuote(product);
    setItems(function(arr) { return arr.concat([blankItem(product)]); });
  };

  /* ---- Choose door ---- */
  if (view === "choose") {
    return (
      <main>
        <section className="section" style={{ paddingTop: "clamp(26px,4vw,40px)" }}>
          <div className="wrap" style={{ maxWidth: 980 }}>
            <nav style={{ display: "flex", alignItems: "center", gap: 8, fontSize: ".88rem", color: "var(--ink-faint)", marginBottom: 14 }}>
              <a onClick={function() { ctx.navigate("#/"); }} style={{ cursor: "pointer", color: "var(--ink-soft)" }}>Home</a>
              <span>/</span>
              <span style={{ color: "var(--ink)", fontWeight: 600 }}>Quote</span>
            </nav>
            <h1 style={{ fontSize: "clamp(1.9rem,3.2vw,2.5rem)", marginBottom: 10 }}>Start your quote</h1>
            <p style={{ fontSize: "1.05rem", color: "var(--ink-soft)", maxWidth: 600, margin: "0 0 30px", lineHeight: 1.55 }}>No payment on the website — we send a confirmed quote via QuickBooks after artwork and proof approval.</p>
            <div className="door-grid" style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 24 }}>
              <button className="card door-card" onClick={function() { setView("quick"); }}
                style={{ padding: 34, textAlign: "left", cursor: "pointer", display: "flex", flexDirection: "column", border: "1px solid var(--line)" }}>
                <span style={{ width: 52, height: 52, borderRadius: 13, background: "var(--teal-tint)", color: "var(--teal-600)", display: "flex", alignItems: "center", justifyContent: "center", marginBottom: 18 }}><Icon name="spark" size={25} /></span>
                <h3 style={{ fontSize: "1.5rem", marginBottom: 10 }}>Quick Quote</h3>
                <p style={{ color: "var(--ink-soft)", flex: 1 }}>A few fields and we follow up with a ballpark. Best for first-timers or early-stage inquiries.</p>
                <span style={{ display: "flex", flexDirection: "column", gap: 8, margin: "18px 0 22px" }}>
                  {["Under 2 minutes", "No artwork required", "Great for ballparks"].map(function(t) {
                    return <span key={t} style={{ display: "flex", gap: 9, fontSize: ".9rem", color: "var(--ink-soft)" }}><Icon name="check" size={16} style={{ color: "var(--forest)" }} /> {t}</span>;
                  })}
                </span>
                <span className="btn btn-ghost" style={{ alignSelf: "flex-start" }}>Start quick quote <Icon name="arrow" size={16} className="arr" /></span>
              </button>
              <button className="card door-card" onClick={function() { setView("detailed"); }}
                style={{ padding: 34, textAlign: "left", cursor: "pointer", display: "flex", flexDirection: "column", border: "1.5px solid var(--navy)", position: "relative" }}>
                <span className="chip solid-navy" style={{ position: "absolute", top: 20, right: 20 }}>Most accurate</span>
                <span style={{ width: 52, height: 52, borderRadius: 13, background: "var(--navy)", color: "#fff", display: "flex", alignItems: "center", justifyContent: "center", marginBottom: 18 }}><Icon name="layers" size={25} /></span>
                <h3 style={{ fontSize: "1.5rem", marginBottom: 10 }}>Full Quote Builder</h3>
                <p style={{ color: "var(--ink-soft)", flex: 1 }}>Add multiple products, configure per-item specs, upload artwork — with a live estimate as you go.</p>
                <span style={{ display: "flex", flexDirection: "column", gap: 8, margin: "18px 0 22px" }}>
                  {["Multi-product quote", "Live estimate", "Upload artwork"].map(function(t) {
                    return <span key={t} style={{ display: "flex", gap: 9, fontSize: ".9rem", color: "var(--ink-soft)" }}><Icon name="check" size={16} style={{ color: "var(--forest)" }} /> {t}</span>;
                  })}
                </span>
                <span className="btn btn-primary" style={{ alignSelf: "flex-start" }}>Build your quote <Icon name="arrow" size={16} className="arr" /></span>
              </button>
            </div>
            <p className="center" style={{ marginTop: 28, color: "var(--ink-soft)", fontSize: ".95rem" }}>
              Prefer to talk it through? <a className="link-arrow" style={{ display: "inline-flex" }} onClick={function() { ctx.navigate("#/contact"); }}>Call a specialist</a>
            </p>
          </div>
        </section>
      </main>
    );
  }

  /* ---- Quick quote ---- */
  if (view === "quick") {
    return (
      <main>
        <section className="section">
          <div className="wrap-narrow">
            <button className="link-arrow" onClick={function() { setView("choose"); }} style={{ fontSize: ".9rem", marginBottom: 20 }}>
              <Icon name="arrow" size={15} style={{ transform: "rotate(180deg)" }} /> Back
            </button>
            <h1 style={{ fontSize: "clamp(1.8rem,3vw,2.4rem)", marginBottom: 12 }}>A few quick details</h1>
            <p className="lede" style={{ marginBottom: 32 }}>Tell us the basics and we will reach out with a ballpark. No artwork needed yet — minimum 50 total pieces.</p>
            <form className="card" style={{ padding: "clamp(24px,3vw,36px)" }} onSubmit={function(e) { e.preventDefault(); setView("done"); }}>
              <div className="field-row">
                <div className="field"><label>Name <span className="req">*</span></label><input className="input" required placeholder="Your name" /></div>
                <div className="field"><label>Business name</label><input className="input" placeholder="Company / shop" /></div>
              </div>
              <div className="field-row">
                <div className="field"><label>Email <span className="req">*</span></label><input className="input" type="email" required placeholder="you@business.com" /></div>
                <div className="field"><label>Phone <span className="req">*</span></label><input className="input" type="tel" required placeholder="(000) 000-0000" /></div>
              </div>
              <div className="field-row">
                <div className="field">
                  <label>Product</label>
                  <select className="select" defaultValue={ctx.cart[0] ? ctx.cart[0].name : PRODUCTS[0].name}>
                    {PRODUCTS.map(function(p) { return <option key={p.slug}>{p.name}</option>; })}
                    <option>Not sure yet</option>
                    <option>Custom size (100-piece min.)</option>
                  </select>
                </div>
                <div className="field"><label>Estimated quantity</label><input className="input" type="number" placeholder="e.g. 100" /></div>
              </div>
              <div className="field"><label>Needed-by date <span className="hint">(optional)</span></label><input className="input" type="date" /></div>
              <div className="field"><label>Anything else?</label><textarea className="textarea" placeholder="Logo, colors, event, questions..." /></div>
              <p style={{ fontSize: ".84rem", color: "var(--ink-soft)", margin: "0 0 14px", padding: "10px 14px", background: "var(--cream)", borderRadius: 8 }}>
                No payment is collected on this site. After review, Timeless Totes will send a quote and invoice through QuickBooks.
              </p>
              <button type="submit" className="btn btn-primary btn-lg btn-block">Send quick quote <Icon name="arrow" size={17} className="arr" /></button>
            </form>
          </div>
        </section>
      </main>
    );
  }

  /* ---- Full quote builder wizard ---- */
  var last       = QUOTE_STEPS.length - 1;
  var totalQty   = items.reduce(function(s, i) { return s + i.qty; }, 0);
  var canContinue = step !== 0 || totalQty >= MIN_TOTAL;
  var isReviewStep = step === last;

  var stdStart = new Date(); stdStart.setDate(stdStart.getDate() + 42);
  var stdEnd   = new Date(); stdEnd.setDate(stdEnd.getDate() + 56);
  var fmtMD = function(d) { return d.toLocaleDateString('en-US', { month: 'long', day: 'numeric' }); };
  var isTightDeadline = spec.rush && spec.date && new Date(spec.date + 'T00:00:00') < stdStart;
  var artFileType = fileExt(spec.file);
  var isRasterArtwork = artFileType && RASTER_EXTS.includes(artFileType);
  var artworkFromDesignLab = spec.file && ctx.quoteArtwork && ctx.quoteArtwork.previewSrc;

  var next = function() {
    /* Step 0: pantone validation */
    if (step === 0) {
      var pantoneOk = items.every(function(i) { return isValidPantoneHex(i.pantone); });
      if (!pantoneOk) return;
    }
    /* Step 1: artwork confirm */
    if (step === 1 && !spec.file && !showArtworkConfirm) {
      setShowArtworkConfirm(true);
      return;
    }
    /* Step 2: shipping + date */
    if (step === 2) {
      var shipOk = spec.shipStreet.trim() && spec.shipCity.trim() && spec.shipState && isValidZip(spec.shipZip);
      if (!shipOk) { setShowShippingErrors(true); return; }
      if (spec.rush && spec.date && !isFutureDate(spec.date)) { setShowDateError(true); return; }
      setShowShippingErrors(false);
      setShowDateError(false);
    }
    /* Step 3: contact */
    if (step === 3) {
      var billingOk = spec.billingSameAsShipping || (
        spec.billStreet.trim() && spec.billCity.trim() && spec.billState && isValidZip(spec.billZip)
      );
      var contactOk = spec.name.trim() &&
        spec.business.trim() &&
        spec.email.trim() && isValidEmail(spec.email) &&
        spec.confirmEmail.trim() && spec.confirmEmail === spec.email &&
        spec.phone.trim() &&
        billingOk;
      if (!contactOk) {
        setShowContactErrors(true);
        return;
      }
    }
    setShowArtworkConfirm(false);
    setShowContactErrors(false);

    if (step < last) {
      setStep(step + 1);
      return;
    }

    /* Final submit — read file as base64 if present, then POST */
    setSubmitting(true);
    setSubmitError(false);

    function doPost(base64Data) {
      var qd = buildQuoteData(items, spec);
      if (base64Data) {
        qd.artworkAttachmentData = base64Data;
        qd.artworkAttached = true;
      }
      fetch('/api/quote', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(qd),
      }).then(function(res) {
        if (!res.ok) throw new Error('fail');
        ctx.clearCart();
        ctx.clearQuoteArtwork();
        setView('done');
      }).catch(function() {
        setSubmitError(true);
      }).finally(function() {
        setSubmitting(false);
      });
    }

    if (spec.fileObj) {
      var reader = new FileReader();
      reader.onload = function(e) {
        var b64 = e.target.result.split(',')[1];
        doPost(b64);
      };
      reader.onerror = function() {
        setSubmitError(true);
        setSubmitting(false);
      };
      reader.readAsDataURL(spec.fileObj);
    } else {
      doPost(null);
    }
  };

  var prev = function() {
    setShowArtworkConfirm(false);
    setShowShippingErrors(false);
    setShowDateError(false);
    setShowContactErrors(false);
    setSubmitError(false);
    if (step > 0) setStep(step - 1); else setView("choose");
  };

  /* ---- Shipping display helper ---- */
  var shipDisplay = [spec.shipStreet, spec.shipCity && spec.shipState ? (spec.shipCity + ", " + spec.shipState) : (spec.shipCity || spec.shipState), spec.shipZip].filter(Boolean).join(' ');

  return (
    <main>
      <section style={{ borderBottom: "1px solid var(--line)", padding: "clamp(24px,3.5vw,36px) 0 26px" }}>
        <div className="wrap">
          <nav style={{ display: "flex", alignItems: "center", gap: 8, fontSize: ".88rem", color: "var(--ink-faint)", marginBottom: 14 }}>
            <a onClick={function() { ctx.navigate("#/"); }} style={{ cursor: "pointer", color: "var(--ink-soft)" }}>Home</a>
            <span>/</span>
            <span style={{ color: "var(--ink)", fontWeight: 600 }}>{sample ? "Request a sample" : "Build your quote"}</span>
          </nav>
          <div style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-end", marginBottom: 20, flexWrap: "wrap", gap: 10 }}>
            <div>
              <h1 style={{ fontSize: "clamp(1.7rem,2.8vw,2.2rem)", marginBottom: 6 }}>{sample ? "Request a sample" : "Build your quote"}</h1>
              <p style={{ margin: 0, color: "var(--ink-soft)", fontSize: ".98rem" }}>50-piece total minimum. No payment collected — we invoice through QuickBooks after approval.</p>
            </div>
            {!sample && !isReviewStep && (
              <button className="link-arrow" style={{ fontSize: ".9rem", background: "none", border: "none", cursor: "pointer", fontFamily: "var(--sans)" }} onClick={function() { setView("quick"); }}>Switch to Quick Quote <Icon name="arrow" size={14} /></button>
            )}
          </div>
          <Stepper steps={QUOTE_STEPS} current={step} />
        </div>
      </section>

      <section className="section">
        <div className="wrap">
          <div className="quote-layout" style={{ display: "grid", gridTemplateColumns: isReviewStep ? "1fr" : "1.5fr .9fr", gap: 40, alignItems: "start" }}>
            <div>

              {/* Step 0: Products and Specs */}
              {step === 0 && (
                <div>
                  <StepHead t="Products and specifications"
                    d="Configure each product line. Minimum 50 pieces total across your entire order." />

                  {items.length === 0 && (
                    <div style={{ padding: "28px 24px", border: "2px dashed var(--line)", borderRadius: "var(--r-md)", textAlign: "center", background: "var(--cream)", marginBottom: 18 }}>
                      <div style={{ color: "var(--ink-faint)", marginBottom: 12 }}><Icon name="layers" size={32} stroke={1.3} /></div>
                      <p style={{ fontWeight: 600, margin: "0 0 8px" }}>No products added yet</p>
                      <p style={{ fontSize: ".9rem", color: "var(--ink-soft)", margin: 0 }}>Go to the Products page to add items, or select below.</p>
                    </div>
                  )}

                  {items.map(function(item, i) {
                    return <LineItemCard key={item.slug + "-" + i} item={item} idx={i} onUpdate={updateItem} onRemove={removeItem} ctx={ctx} />;
                  })}

                  <div style={{ marginTop: 12, marginBottom: 16 }}>
                    <label style={{ fontWeight: 600, fontSize: ".88rem", color: "var(--ink-soft)", display: "block", marginBottom: 8 }}>Add another product</label>
                    <div style={{ display: "flex", flexWrap: "wrap", gap: 8 }}>
                      {PRODUCTS.slice(0, 6).map(function(p) {
                        return (
                          <button key={p.slug} onClick={function() { addExtraProduct(p); }}
                            style={{ padding: "7px 13px", borderRadius: 9, border: "1.5px solid var(--line)", background: "var(--white)", color: "var(--ink-soft)", fontSize: ".84rem", fontWeight: 600, fontFamily: "var(--sans)", cursor: "pointer" }}>
                            + {p.name}
                          </button>
                        );
                      })}
                      <button onClick={function() { addExtraProduct({ slug: "custom-bag", name: "Custom Bag / Custom Size Request", accent: "navy", cardImg: null }); }}
                        style={{ padding: "7px 13px", borderRadius: 9, border: "1.5px solid var(--navy)", background: "var(--navy)", color: "#fff", fontSize: ".84rem", fontWeight: 600, fontFamily: "var(--sans)", cursor: "pointer", display: "flex", alignItems: "center", gap: 6 }}>
                        <Icon name="pencil" size={14} /> Custom bag / size
                      </button>
                    </div>
                  </div>

                  {totalQty > 0 && totalQty < MIN_TOTAL && (
                    <div style={{ padding: "12px 16px", background: "#FFF3CD", borderRadius: 8, fontSize: ".88rem", color: "#856404", display: "flex", gap: 8 }}>
                      <Icon name="spark" size={16} style={{ flexShrink: 0 }} />
                      <span>Total quantity: <strong>{totalQty}</strong>. Minimum is <strong>50 total pieces</strong> across all products.</span>
                    </div>
                  )}
                </div>
              )}

              {/* Step 1: Artwork */}
              {step === 1 && (
                <div>
                  <StepHead t="Your artwork"
                    d="One logo or artwork file for the full order. Your logo will be used across all products in this quote." />

                  {spec.file && (
                    <div style={{ marginBottom: 20, padding: "14px 16px", background: "var(--forest-tint)", border: "1.5px solid var(--forest)", borderRadius: 12, display: "flex", alignItems: "center", gap: 14 }}>
                      {artworkFromDesignLab ? (
                        <img src={ctx.quoteArtwork.previewSrc} alt=""
                          style={{ width: 44, height: 44, objectFit: "contain", borderRadius: 8, background: "#fff", border: "1px solid var(--line)", flexShrink: 0 }} />
                      ) : (
                        <span style={{ width: 44, height: 44, borderRadius: 8, background: "var(--forest)", color: "#fff", display: "flex", alignItems: "center", justifyContent: "center", flexShrink: 0 }}>
                          <Icon name="check" size={22} />
                        </span>
                      )}
                      <div style={{ flex: 1, minWidth: 0 }}>
                        <strong style={{ display: "block", fontSize: ".95rem", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{spec.file}</strong>
                        <span style={{ fontSize: ".81rem", color: "var(--ink-soft)" }}>
                          {artworkFromDesignLab ? "Uploaded in Design Lab — " : ""}Applies to all products in this order
                        </span>
                      </div>
                      <button onClick={removeArtwork}
                        style={{ background: "none", border: "1px solid var(--line)", borderRadius: 8, padding: "6px 12px", fontSize: ".82rem", fontWeight: 600, fontFamily: "var(--sans)", color: "var(--ink-soft)", cursor: "pointer", flexShrink: 0 }}>
                        Remove
                      </button>
                    </div>
                  )}

                  <UploadZone file={spec.file} onFile={applyArtwork} />

                  <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 14, marginTop: 20 }}>
                    {[
                      ["check",   "Vector preferred",              ".ai .eps .pdf .svg — scales perfectly to any size"],
                      ["check",   "PNG / JPG accepted with note",  "May require file cleanup ($25-$50) — our team will advise before finalizing your quote"],
                      ["palette", "We proof everything",           "Digital proof prepared before any printing begins"],
                      ["mail",    "No file yet?",                  "Submit now and email artwork to timelesstotes@yahoo.com"],
                    ].map(function(row) {
                      return (
                        <div key={row[1]} style={{ display: "flex", gap: 11, padding: 14, background: "var(--cream)", borderRadius: 10 }}>
                          <span style={{ color: "var(--teal)", flexShrink: 0 }}><Icon name={row[0]} size={19} /></span>
                          <div><strong style={{ fontSize: ".9rem" }}>{row[1]}</strong><div style={{ fontSize: ".82rem", color: "var(--ink-soft)" }}>{row[2]}</div></div>
                        </div>
                      );
                    })}
                  </div>
                  <div className="field" style={{ marginTop: 20, marginBottom: 0 }}>
                    <label>Artwork size and placement notes</label>
                    <input className="input" placeholder='5" wide, centered front' value={spec.globalNotes}
                      onChange={function(e) { setS("globalNotes", e.target.value); }} />
                  </div>
                  {showArtworkConfirm && (
                    <div style={{ marginTop: 18, padding: "14px 16px", background: "#FFF3CD", borderRadius: 10, border: "1px solid #FBBF24", fontSize: ".9rem", color: "#854d0e" }}>
                      <strong>No artwork uploaded.</strong> You can still submit your quote and email your logo separately to timelesstotes@yahoo.com. We will confirm the file before production begins.
                      <div style={{ display: "flex", gap: 10, marginTop: 12 }}>
                        <button className="btn btn-primary btn-sm" onClick={function() { setShowArtworkConfirm(false); setStep(step + 1); }}>Continue without artwork</button>
                        <button className="btn btn-ghost btn-sm" onClick={function() { setShowArtworkConfirm(false); }}>Go back and upload</button>
                      </div>
                    </div>
                  )}
                </div>
              )}

              {/* Step 2: Timing */}
              {step === 2 && (
                <div>
                  <StepHead t="Timing"
                    d="Most custom orders are completed in approximately 6-8 weeks after artwork approval, quote approval, and invoice/payment confirmation." />

                  <div className="card" style={{ padding: 18, background: "var(--cream)", marginBottom: 22, display: "flex", gap: 12 }}>
                    <Icon name="truck" size={20} style={{ color: "var(--teal)", flexShrink: 0, marginTop: 2 }} />
                    <div style={{ fontSize: ".9rem", color: "var(--ink-soft)" }}>
                      <strong style={{ color: "var(--ink)" }}>Estimated standard window: {fmtMD(stdStart)} - {fmtMD(stdEnd)}</strong>
                      <div style={{ marginTop: 4 }}>Standard lead time is <strong>6-8 weeks after artwork approval.</strong> This estimate is based on today's date and a standard production timeline.</div>
                    </div>
                  </div>

                  <div style={{ marginBottom: 18 }}>
                    <label style={{ fontWeight: 600, fontSize: ".93rem", display: "block", marginBottom: 10 }}>Shipping address <span className="req">*</span></label>
                    <div className="field" style={{ marginBottom: 10 }}>
                      <input className="input" placeholder="Street address" value={spec.shipStreet}
                        onChange={function(e) { setS("shipStreet", e.target.value); if (e.target.value.trim()) setShowShippingErrors(false); }}
                        style={showShippingErrors && !spec.shipStreet.trim() ? { borderColor: "#C0392B" } : {}} />
                      {showShippingErrors && !spec.shipStreet.trim() && (
                        <div style={{ fontSize: ".8rem", color: "#C0392B", marginTop: 4 }}>Street address is required.</div>
                      )}
                    </div>
                    <div className="field-row" style={{ marginBottom: 0 }}>
                      <div className="field" style={{ flex: 2, marginBottom: 0 }}>
                        <input className="input" placeholder="City" value={spec.shipCity}
                          onChange={function(e) { setS("shipCity", e.target.value); }}
                          style={showShippingErrors && !spec.shipCity.trim() ? { borderColor: "#C0392B" } : {}} />
                        {showShippingErrors && !spec.shipCity.trim() && (
                          <div style={{ fontSize: ".8rem", color: "#C0392B", marginTop: 4 }}>City is required.</div>
                        )}
                      </div>
                      <div className="field" style={{ flex: 1, marginBottom: 0 }}>
                        <select className="select" value={spec.shipState}
                          onChange={function(e) { setS("shipState", e.target.value); }}
                          style={showShippingErrors && !spec.shipState ? { borderColor: "#C0392B" } : {}}>
                          <option value="">State</option>
                          {US_STATES.map(function(s) { return <option key={s} value={s}>{s}</option>; })}
                        </select>
                        {showShippingErrors && !spec.shipState && (
                          <div style={{ fontSize: ".8rem", color: "#C0392B", marginTop: 4 }}>State is required.</div>
                        )}
                      </div>
                      <div className="field" style={{ flex: 1, marginBottom: 0 }}>
                        <input className="input" placeholder="ZIP" value={spec.shipZip}
                          onChange={function(e) { setS("shipZip", e.target.value); }}
                          style={showShippingErrors && !isValidZip(spec.shipZip) ? { borderColor: "#C0392B" } : {}} />
                        {showShippingErrors && !isValidZip(spec.shipZip) && (
                          <div style={{ fontSize: ".8rem", color: "#C0392B", marginTop: 4 }}>Valid ZIP required.</div>
                        )}
                      </div>
                    </div>
                  </div>

                  <div style={{ marginTop: 6 }}>
                    <Toggle label="I have a required deadline or event date"
                      hint="Only select this if your order needs to arrive by a specific date. Rush or priority scheduling may include an additional fee, confirmed in writing before invoicing."
                      on={spec.rush} onChange={function(v) { setS("rush", v); if (!v) setShowDateError(false); }} accent="red" />
                  </div>

                  {spec.rush && (
                    <div style={{ marginTop: 14, display: "flex", flexDirection: "column", gap: 14 }}>
                      <div className="field" style={{ marginBottom: 0 }}>
                        <label>Needed-by date</label>
                        <input className="input" type="date" value={spec.date}
                          onChange={function(e) { setS("date", e.target.value); setShowDateError(false); }}
                          style={showDateError ? { borderColor: "#C0392B" } : {}} />
                        {showDateError && (
                          <div style={{ fontSize: ".8rem", color: "#C0392B", marginTop: 4 }}>Needed-by date must be a future date.</div>
                        )}
                      </div>
                      <div className="field" style={{ marginBottom: 0 }}>
                        <label>Deadline details <span className="hint">(optional)</span></label>
                        <textarea className="textarea" placeholder="Tell us about the deadline, event, or timing need."
                          value={spec.deadlineNotes} onChange={function(e) { setS("deadlineNotes", e.target.value); }} />
                        <div className="hint" style={{ marginTop: 5 }}>If your deadline is sooner than our standard 6-8 week lead time, include the date and details here.</div>
                      </div>
                      {isTightDeadline && (
                        <div style={{ padding: "12px 16px", background: "#FFF3CD", borderRadius: 8, fontSize: ".88rem", color: "#856404", display: "flex", gap: 8, alignItems: "flex-start" }}>
                          <Icon name="spark" size={16} style={{ flexShrink: 0, marginTop: 1 }} />
                          <span>Tight timelines may require review and could include an additional rush fee (est. $200). We will confirm what is possible after reviewing your request.</span>
                        </div>
                      )}
                    </div>
                  )}
                </div>
              )}

              {/* Step 3: Contact */}
              {step === 3 && (
                <div>
                  <StepHead t="Where do we send your quote?"
                    d="A specialist will review your request and reach out — usually within one business day." />
                  <div className="field-row">
                    <div className="field">
                      <label>Name <span className="req">*</span></label>
                      <input className="input" required placeholder="Your name" value={spec.name}
                        onChange={function(e) { setS("name", e.target.value); }}
                        style={showContactErrors && !spec.name.trim() ? { borderColor: "#C0392B" } : {}} />
                      {showContactErrors && !spec.name.trim() && <div style={{ fontSize: ".8rem", color: "#C0392B", marginTop: 4 }}>Name is required.</div>}
                    </div>
                    <div className="field">
                      <label>Company / Store / Organization <span className="req">*</span></label>
                      <input className="input" placeholder="Business, brand, or org name" value={spec.business}
                        onChange={function(e) { setS("business", e.target.value); }}
                        style={showContactErrors && !spec.business.trim() ? { borderColor: "#C0392B" } : {}} />
                      {showContactErrors && !spec.business.trim()
                        ? <div style={{ fontSize: ".8rem", color: "#C0392B", marginTop: 4 }}>Company / store / organization name is required.</div>
                        : <div className="hint" style={{ marginTop: 4 }}>Helps us address your quote correctly.</div>
                      }
                    </div>
                  </div>
                  <div className="field">
                    <label>Email <span className="req">*</span></label>
                    <input className="input" type="email" required placeholder="you@business.com" value={spec.email}
                      onChange={function(e) { setS("email", e.target.value); }}
                      style={showContactErrors && (!spec.email.trim() || !isValidEmail(spec.email)) ? { borderColor: "#C0392B" } : {}} />
                    {showContactErrors && !spec.email.trim() && <div style={{ fontSize: ".8rem", color: "#C0392B", marginTop: 4 }}>Email is required.</div>}
                    {showContactErrors && spec.email.trim() && !isValidEmail(spec.email) && <div style={{ fontSize: ".8rem", color: "#C0392B", marginTop: 4 }}>Please enter a valid email address.</div>}
                  </div>
                  <div className="field">
                    <label>Confirm email <span className="req">*</span></label>
                    <input className="input" type="email" placeholder="Re-enter your email" value={spec.confirmEmail}
                      onChange={function(e) { setS("confirmEmail", e.target.value); }}
                      style={showContactErrors && (!spec.confirmEmail.trim() || spec.confirmEmail !== spec.email) ? { borderColor: "#C0392B" } : {}} />
                    {showContactErrors && !spec.confirmEmail.trim() && <div style={{ fontSize: ".8rem", color: "#C0392B", marginTop: 4 }}>Please confirm your email.</div>}
                    {showContactErrors && spec.confirmEmail.trim() && spec.confirmEmail !== spec.email && <div style={{ fontSize: ".8rem", color: "#C0392B", marginTop: 4 }}>Email addresses do not match.</div>}
                  </div>
                  <div className="field">
                    <label>Phone <span className="req">*</span></label>
                    <input className="input" type="tel" required placeholder="(000) 000-0000" value={spec.phone}
                      onChange={function(e) { setS("phone", e.target.value); }}
                      style={showContactErrors && !spec.phone.trim() ? { borderColor: "#C0392B" } : {}} />
                    {showContactErrors && !spec.phone.trim() && <div style={{ fontSize: ".8rem", color: "#C0392B", marginTop: 4 }}>Phone number is required.</div>}
                  </div>

                  <div style={{ marginTop: 6 }}>
                    <Toggle label="Billing address same as shipping"
                      hint="Uncheck to enter a separate billing address"
                      on={spec.billingSameAsShipping}
                      onChange={function(v) { setS("billingSameAsShipping", v); }} accent="teal" />
                  </div>
                  {!spec.billingSameAsShipping && (
                    <div style={{ marginTop: 12 }}>
                      <label style={{ fontWeight: 600, fontSize: ".93rem", display: "block", marginBottom: 10 }}>Billing address</label>
                      <div className="field" style={{ marginBottom: 10 }}>
                        <input className="input" placeholder="Street address" value={spec.billStreet}
                          onChange={function(e) { setS("billStreet", e.target.value); }}
                          style={showContactErrors && !spec.billStreet.trim() ? { borderColor: "#C0392B" } : {}} />
                        {showContactErrors && !spec.billStreet.trim() && <div style={{ fontSize: ".8rem", color: "#C0392B", marginTop: 4 }}>Billing street address is required.</div>}
                      </div>
                      <div className="field-row" style={{ marginBottom: 0 }}>
                        <div className="field" style={{ flex: 2, marginBottom: 0 }}>
                          <input className="input" placeholder="City" value={spec.billCity}
                            onChange={function(e) { setS("billCity", e.target.value); }}
                            style={showContactErrors && !spec.billCity.trim() ? { borderColor: "#C0392B" } : {}} />
                          {showContactErrors && !spec.billCity.trim() && <div style={{ fontSize: ".8rem", color: "#C0392B", marginTop: 4 }}>City is required.</div>}
                        </div>
                        <div className="field" style={{ flex: 1, marginBottom: 0 }}>
                          <select className="select" value={spec.billState}
                            onChange={function(e) { setS("billState", e.target.value); }}
                            style={showContactErrors && !spec.billState ? { borderColor: "#C0392B" } : {}}>
                            <option value="">State</option>
                            {US_STATES.map(function(s) { return <option key={s} value={s}>{s}</option>; })}
                          </select>
                          {showContactErrors && !spec.billState && <div style={{ fontSize: ".8rem", color: "#C0392B", marginTop: 4 }}>State is required.</div>}
                        </div>
                        <div className="field" style={{ flex: 1, marginBottom: 0 }}>
                          <input className="input" placeholder="ZIP" value={spec.billZip}
                            onChange={function(e) { setS("billZip", e.target.value); }}
                            style={showContactErrors && !isValidZip(spec.billZip) ? { borderColor: "#C0392B" } : {}} />
                          {showContactErrors && !isValidZip(spec.billZip) && <div style={{ fontSize: ".8rem", color: "#C0392B", marginTop: 4 }}>Valid ZIP required.</div>}
                        </div>
                      </div>
                    </div>
                  )}

                  <div className="field" style={{ marginTop: 14, marginBottom: 0 }}>
                    <label>Notes for our team <span className="hint">(optional)</span></label>
                    <textarea className="textarea" placeholder="Anything else about your project, brand, or timeline..."
                      value={spec.additionalNotes} onChange={function(e) { setS("additionalNotes", e.target.value); }} />
                  </div>

                  {spec.rush && (
                    <div style={{ padding: "12px 16px", background: "#FFF3CD", borderRadius: 8, fontSize: ".88rem", color: "#856404", marginTop: 16, display: "flex", gap: 8, alignItems: "flex-start" }}>
                      <Icon name="spark" size={16} style={{ flexShrink: 0, marginTop: 1 }} />
                      <span>Rush or front-of-line requests may include a handling fee (est. $200) — reviewed and confirmed by Timeless Totes before invoicing.</span>
                    </div>
                  )}
                  <p style={{ fontSize: ".84rem", color: "var(--ink-soft)", margin: "16px 0 0", padding: "12px 16px", background: "var(--cream)", borderRadius: 8, display: "flex", gap: 8 }}>
                    <Icon name="shield" size={16} style={{ color: "var(--teal)", flexShrink: 0, marginTop: 1 }} />
                    No payment is collected on this website. Timeless Totes will review your request and send a confirmed quote and invoice through QuickBooks after artwork approval.
                  </p>
                </div>
              )}

              {/* Step 4: Review */}
              {step === last && (
                <div>
                  <StepHead t="Review your quote"
                    d="Check everything below before submitting. Go back to make any changes." />

                  {items.map(function(item, i) {
                    var isCustom = item.slug === "custom-bag";
                    var uPrice = isCustom ? null : lookupPrice(item.size);
                    var lTotal = uPrice !== null ? uPrice * item.qty : null;
                    return (
                      <div key={i} className="card" style={{ padding: "16px 20px", marginBottom: 12 }}>
                        <div style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-start", gap: 12 }}>
                          <div>
                            <strong style={{ fontSize: ".98rem" }}>{isCustom ? "Custom Bag / Custom Size Request" : item.name}</strong>
                            {!isCustom && item.size && (
                              <div style={{ fontSize: ".84rem", color: "var(--ink-soft)", marginTop: 2 }}>{item.size}</div>
                            )}
                          </div>
                          {!isCustom && (
                            lTotal !== null ? (
                              <div style={{ textAlign: "right", flexShrink: 0 }}>
                                <div style={{ fontWeight: 700, color: "var(--navy)" }}>{fmtUSD(lTotal)}</div>
                                <div style={{ fontSize: ".76rem", color: "var(--ink-faint)" }}>{fmtUSD(uPrice)} x {item.qty}</div>
                              </div>
                            ) : (
                              <span style={{ fontSize: ".82rem", color: "var(--ink-soft)", fontStyle: "italic", flexShrink: 0 }}>Price to be reviewed</span>
                            )
                          )}
                          {isCustom && (
                            <span style={{ fontSize: ".82rem", color: "var(--ink-soft)", fontStyle: "italic", flexShrink: 0 }}>To be reviewed</span>
                          )}
                        </div>
                        <div style={{ display: "flex", flexWrap: "wrap", gap: "5px 16px", fontSize: ".83rem", color: "var(--ink-soft)", marginTop: 10 }}>
                          <span>Qty: <strong style={{ color: "var(--ink)" }}>{item.qty}</strong></span>
                          {!isCustom && <span>Colors: <strong style={{ color: "var(--ink)" }}>{item.colors}</strong>{item.colors > 1 && <span style={{ fontSize: ".76rem" }}> (upcharge to be reviewed)</span>}</span>}
                          {!isCustom && <span>Placement: <strong style={{ color: "var(--ink)" }}>{item.placement}</strong></span>}
                          {!isCustom && <span>Trim: <strong style={{ color: "var(--ink)" }}>{item.trimMatchZipper ? "Match zipper" : (item.trimNotes || "Match zipper")}</strong></span>}
                          {!isCustom && <span>Zipper: <strong style={{ color: "var(--ink)" }}>{item.zipperColor}</strong></span>}
                          {item.pantone && <span>Ink color: <strong style={{ color: "var(--ink)" }}>{item.pantone}</strong></span>}
                        </div>
                        {item.doubleSided && <div style={{ fontSize: ".8rem", color: "var(--ink-soft)", marginTop: 6 }}>Double-sided print (upcharge to be reviewed)</div>}
                        {isCustom && item.customDescription && <div style={{ fontSize: ".83rem", color: "var(--ink-soft)", marginTop: 8, fontStyle: "italic" }}>{item.customDescription}</div>}
                      </div>
                    );
                  })}

                  {(function() {
                    var reg = items.filter(function(i) { return i.slug !== "custom-bag"; });
                    var priced = reg.filter(function(i) { return lookupPrice(i.size) !== null; });
                    var anyUnpriced = reg.some(function(i) { return lookupPrice(i.size) === null; });
                    var hasCustom = items.some(function(i) { return i.slug === "custom-bag"; });
                    var sub = priced.reduce(function(s,i) { return s + lookupPrice(i.size) * i.qty; }, 0);
                    var incomplete = anyUnpriced || hasCustom;
                    var anyOver = items.some(function(i) { return i.qty > VOL_THRESHOLD; });
                    return (
                      <div className="card" style={{ padding: "16px 20px", marginBottom: 14 }}>
                        <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", paddingBottom: 10, marginBottom: 10, borderBottom: "1px solid var(--line-soft)" }}>
                          <span style={{ fontWeight: 600 }}>Total quantity</span>
                          <span style={{ fontWeight: 700 }}>{totalQty} pieces</span>
                        </div>
                        <div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline" }}>
                          <span style={{ fontWeight: 600 }}>Estimated subtotal</span>
                          {incomplete ? (
                            <span style={{ fontSize: ".88rem", color: "var(--ink-soft)", fontStyle: "italic" }}>Incomplete — items need review</span>
                          ) : (
                            <span style={{ fontWeight: 700, fontSize: "1.2rem", color: "var(--navy)" }}>{fmtUSD(sub)}</span>
                          )}
                        </div>
                        {spec.rush && (
                          <div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline", marginTop: 8, paddingTop: 8, borderTop: "1px dashed var(--line)" }}>
                            <span style={{ fontSize: ".9rem", color: "#856404", fontWeight: 600 }}>Rush handling fee (est.)</span>
                            <span style={{ fontWeight: 700, color: "#856404" }}>+{fmtUSD(RUSH_FEE)}</span>
                          </div>
                        )}
                        {spec.rush && !incomplete && (
                          <div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline", marginTop: 6 }}>
                            <span style={{ fontWeight: 600 }}>Est. total with rush</span>
                            <span style={{ fontWeight: 700, fontSize: "1.15rem", color: "var(--navy)" }}>{fmtUSD(sub + RUSH_FEE)}</span>
                          </div>
                        )}
                        {anyOver && (
                          <div style={{ marginTop: 8, fontSize: ".82rem", color: "var(--forest)" }}>
                            One or more items above 200 pieces — possible 10% volume discount, confirmed on your quote.
                          </div>
                        )}
                      </div>
                    );
                  })()}

                  <div className="card" style={{ padding: "14px 18px", marginBottom: 12, fontSize: ".88rem" }}>
                    <strong style={{ display: "block", marginBottom: 8 }}>Shipping and Timing</strong>
                    <div style={{ color: "var(--ink-soft)", display: "flex", flexDirection: "column", gap: 4 }}>
                      {spec.shipStreet && <span>{spec.shipStreet}</span>}
                      {(spec.shipCity || spec.shipState || spec.shipZip) && (
                        <span>
                          {[spec.shipCity, spec.shipState].filter(Boolean).join(", ")}{spec.shipZip ? " " + spec.shipZip : ""}
                        </span>
                      )}
                      <span>Standard lead time: <strong style={{ color: "var(--ink)" }}>6-8 weeks</strong></span>
                      {spec.rush && spec.date && (
                        <span style={{ color: "#C0392B" }}>Required by: <strong>{new Date(spec.date + 'T00:00:00').toLocaleDateString('en-US', { month: 'long', day: 'numeric', year: 'numeric' })}</strong></span>
                      )}
                      {spec.rush && <span style={{ color: "#856404" }}>Rush handling fee: <strong>est. {fmtUSD(RUSH_FEE)}</strong></span>}
                    </div>
                  </div>

                  <div className="card" style={{ padding: "14px 18px", marginBottom: 12, fontSize: ".88rem" }}>
                    <strong style={{ display: "block", marginBottom: 8 }}>Your information</strong>
                    <div style={{ color: "var(--ink-soft)", display: "flex", flexDirection: "column", gap: 3 }}>
                      <span><strong style={{ color: "var(--ink)" }}>{spec.name}</strong>{spec.business && (" / " + spec.business)}</span>
                      <span>{spec.email}</span>
                      <span>{spec.phone}</span>
                    </div>
                  </div>

                  {/* Artwork / Logo review card */}
                  <div className="card" style={{ padding: "14px 18px", marginBottom: 14, fontSize: ".88rem" }}>
                    <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 8, gap: 12 }}>
                      <strong>Artwork / Logo</strong>
                      <button onClick={function() { setStep(1); }}
                        style={{ fontSize: ".78rem", background: "none", border: "1px solid var(--line)", borderRadius: 7, padding: "4px 10px", color: "var(--ink-soft)", fontFamily: "var(--sans)", cursor: "pointer" }}>
                        Edit
                      </button>
                    </div>
                    {spec.file ? (
                      <div style={{ color: "var(--ink-soft)", display: "flex", flexDirection: "column", gap: 4 }}>
                        {artworkFromDesignLab && (
                          <div style={{ display: "flex", alignItems: "center", gap: 10, marginBottom: 6 }}>
                            <img src={ctx.quoteArtwork.previewSrc} alt=""
                              style={{ width: 36, height: 36, objectFit: "contain", borderRadius: 6, background: "#fff", border: "1px solid var(--line)", flexShrink: 0 }} />
                            <span style={{ fontSize: ".78rem", color: "var(--forest)", fontWeight: 600 }}>From Design Lab</span>
                          </div>
                        )}
                        <span>Artwork uploaded: <strong style={{ color: "var(--ink)" }}>Yes</strong></span>
                        <span>File: <strong style={{ color: "var(--ink)" }}>{spec.file}</strong></span>
                        {artFileType && <span>File type: <strong style={{ color: "var(--ink)" }}>{artFileType}</strong></span>}
                        <span>Attached to quote: <strong style={{ color: "var(--ink)" }}>{spec.fileObj ? "Yes" : "No"}</strong></span>
                        <span style={{ fontSize: ".8rem" }}>Applies to: <strong style={{ color: "var(--ink)" }}>All products in this order</strong></span>
                        {isRasterArtwork && (
                          <span style={{ color: "#856404", marginTop: 2 }}>Artwork prep may apply: estimated $25-$50 depending on complexity.</span>
                        )}
                      </div>
                    ) : (
                      <span style={{ color: "var(--ink-soft)" }}>No file uploaded — email your artwork to timelesstotes@yahoo.com after submitting.</span>
                    )}
                    {spec.globalNotes && <div style={{ marginTop: 6, color: "var(--ink-soft)" }}>Placement notes: {spec.globalNotes}</div>}
                  </div>

                  <div style={{ padding: "14px 18px", background: "var(--cream)", borderRadius: 10, border: "1px solid var(--line)", fontSize: ".88rem", color: "var(--ink-soft)", marginBottom: 16, lineHeight: 1.6, display: "flex", gap: 10 }}>
                    <Icon name="shield" size={16} style={{ color: "var(--teal)", flexShrink: 0, marginTop: 2 }} />
                    <span>This is an estimate for review. Final pricing and invoicing will be confirmed by Timeless Totes. No payment is collected on this website.</span>
                  </div>

                  {submitError && (
                    <div style={{ padding: "14px 18px", background: "#FEE2E2", borderRadius: 10, border: "1px solid #FCA5A5", fontSize: ".9rem", color: "#991B1B", marginBottom: 16 }}>
                      Something went wrong sending your quote request. Please try again, or email Timeless Totes directly at timelesstotes@yahoo.com.
                    </div>
                  )}
                </div>
              )}

              {/* Bottom nav */}
              <div style={{ display: "flex", justifyContent: "space-between", marginTop: 34, paddingTop: 24, borderTop: "1px solid var(--line)" }}>
                <button className="btn btn-ghost" onClick={prev}>{step === 0 ? "Cancel" : "Back"}</button>
                <button className="btn btn-primary" onClick={next}
                  disabled={isReviewStep ? submitting : !canContinue}
                  style={{ opacity: (isReviewStep ? submitting : !canContinue) ? .45 : 1 }}>
                  {isReviewStep
                    ? (submitting ? "Submitting..." : (sample ? "Submit sample request" : "Submit quote request"))
                    : "Continue"}
                  {!submitting && <Icon name="arrow" size={16} className="arr" />}
                </button>
              </div>
            </div>

            {!isReviewStep && <EstimatePanel items={items} spec={spec} sample={sample} />}
          </div>
        </div>
      </section>
    </main>
  );
}

Object.assign(window, { QuotePage });
