// ============================================================
// Farm Fresh — shared UI components
// ============================================================
const { useState, useRef, useEffect } = React;

// ---- component styles (injected once) ----
const FF_CSS = `
/* ---------- produce grid ---------- */
.grid-wrap{ flex:1; min-height:0; padding:14px 14px 22px; }
.produce-grid{
  display:grid;
  grid-template-columns:repeat(3, 1fr);
  gap:11px;
  padding-bottom:2px;
}
.tile{
  position:relative;
  background:var(--surface);
  border:1.5px solid var(--line);
  border-radius:var(--r-md);
  padding:13px 8px 11px;
  display:flex; flex-direction:column; align-items:center;
  gap:3px;
  box-shadow:var(--shadow-card);
  transition:transform .08s ease, border-color .12s ease;
  min-height:108px;
  justify-content:center;
}
.tile:active{ transform:scale(.95); }
.tile .emoji{ font-size:38px; line-height:1; filter:drop-shadow(0 1px 1px oklch(0 0 0 /.12)); }
.tile .nm{ font-weight:700; font-size:13.5px; text-align:center; line-height:1.05; color:var(--ink); }
.tile .pr{ font-size:12px; color:var(--ink-soft); font-weight:400; }
.tile .pr b{ font-weight:700; color:var(--green-ink); }
.tile .unit-tag{
  position:absolute; top:7px; right:7px;
  font-size:9.5px; font-weight:700; letter-spacing:.04em;
  padding:2px 6px; border-radius:999px; text-transform:uppercase;
}
.unit-tag.lb{ background:var(--terra-bg); color:var(--terra-ink); }
.unit-tag.each{ background:var(--green-bg); color:var(--green-ink); }
.tile .inbag{
  position:absolute; top:6px; left:6px;
  min-width:21px; height:21px; padding:0 5px;
  border-radius:999px; background:var(--green); color:#fff;
  font-size:12px; font-weight:800;
  display:flex; align-items:center; justify-content:center;
  box-shadow:0 2px 5px oklch(0.5 0.1 145 /.4);
}

/* ---------- keypad ---------- */
.kp{ display:grid; grid-template-columns:repeat(3,1fr); gap:10px; }
.kp button{
  background:var(--bg-2); border:1.5px solid var(--line);
  border-radius:var(--r-sm); font-size:26px; font-weight:600;
  padding:16px 0; color:var(--ink); font-family:var(--mono);
  transition:transform .06s, background .1s;
}
.kp button:active{ transform:scale(.94); background:var(--line-soft); }
.kp button.act{ color:var(--terra-ink); }

/* ---------- buttons ---------- */
.btn{
  border-radius:var(--r-md); font-weight:700; font-size:17px;
  padding:16px; display:flex; align-items:center; justify-content:center; gap:9px;
  transition:transform .07s, filter .12s;
}
.btn:active{ transform:scale(.97); }
.btn-green{ background:var(--green); color:#fff; box-shadow:0 5px 16px oklch(0.55 0.13 145 /.32); }
.btn-terra{ background:var(--terra); color:#fff; box-shadow:0 5px 16px oklch(0.62 0.16 42 /.32); }
.btn-ghost{ background:var(--bg-2); color:var(--ink); border:1.5px solid var(--line); }
.btn-soft{ background:var(--surface); color:var(--ink); border:1.5px solid var(--line); box-shadow:var(--shadow-card); }
.btn[disabled]{ opacity:.4; pointer-events:none; }

/* ---------- sheet ---------- */
.sheet{
  background:var(--bg); border-radius:26px 26px 0 0;
  width:100%; max-width:480px; margin:0 auto;
  box-shadow:var(--shadow-pop); animation:ff-up .26s cubic-bezier(.2,.8,.25,1);
  display:flex; flex-direction:column; max-height:92%;
  overflow:hidden;
}
.sheet .grab{ width:42px; height:5px; border-radius:999px; background:var(--line); margin:10px auto 4px; flex:none; }
.sheet-head{ padding:6px 20px 12px; display:flex; align-items:center; justify-content:space-between; flex:none; }
.sheet-head h2{ margin:0; font-size:21px; font-weight:800; letter-spacing:-.01em; }
.modal-card{
  background:var(--bg); border-radius:24px; width:100%; max-width:380px;
  box-shadow:var(--shadow-pop); animation:ff-pop .2s ease; overflow:hidden;
}
.x-btn{ width:38px; height:38px; border-radius:50%; background:var(--bg-2); border:1.5px solid var(--line);
  display:flex; align-items:center; justify-content:center; font-size:20px; color:var(--ink-soft); flex:none; }
@keyframes ff-shake{ 0%,100%{transform:translateX(0)} 20%{transform:translateX(-9px)} 40%{transform:translateX(8px)} 60%{transform:translateX(-6px)} 80%{transform:translateX(4px)} }

/* ---------- admin ---------- */
.adm-field{ display:flex; flex-direction:column; gap:5px; }
.adm-field label{ font-size:11px; font-weight:700; color:var(--ink-faint); text-transform:uppercase; letter-spacing:.05em; }
.adm-input{ background:var(--surface); border:1.5px solid var(--line); border-radius:11px; padding:11px 13px;
  font-size:16px; font-weight:600; color:var(--ink); width:100%; }
.adm-input:focus{ outline:none; border-color:var(--green); }
.seg{ display:flex; background:var(--bg-2); border:1.5px solid var(--line); border-radius:11px; padding:3px; gap:3px; }
.seg button{ flex:1; padding:9px 0; border-radius:8px; font-weight:700; font-size:14px; color:var(--ink-soft); }
.seg button.on{ background:var(--surface); color:var(--ink); box-shadow:var(--shadow-card); }

/* ---------- category tabs ---------- */
.tabbar{ display:flex; gap:8px; padding:11px 14px 9px; overflow-x:auto; flex:none;
  background:var(--bg); border-bottom:1.5px solid var(--line-soft); }
.tabbar::-webkit-scrollbar{ height:0; }
.tab{ flex:none; padding:9px 16px; border-radius:999px; font-weight:700; font-size:14.5px;
  background:var(--surface); border:1.5px solid var(--line); color:var(--ink-soft);
  display:flex; align-items:center; gap:6px; transition:all .12s; white-space:nowrap; }
.tab .cnt{ font-size:11.5px; font-weight:700; opacity:.6; }
.tab.on{ background:var(--green); border-color:var(--green); color:#fff; box-shadow:0 3px 10px oklch(0.55 0.13 145 /.3); }
.tab.on .cnt{ opacity:.8; }

/* category section header inside the grid */
.cat-head{ display:flex; align-items:center; gap:9px; padding:4px 2px 9px; }
.cat-head .lbl{ font-size:13px; font-weight:800; text-transform:uppercase; letter-spacing:.06em; color:var(--ink-soft); }
.cat-head .rule{ flex:1; height:1.5px; background:var(--line); border-radius:2px; }
.cat-head .n{ font-size:11.5px; font-weight:700; color:var(--ink-faint); }
.cat-block + .cat-block{ margin-top:18px; }
`;

(function injectFFCSS() {
  if (document.getElementById("ff-comp-css")) return;
  const s = document.createElement("style");
  s.id = "ff-comp-css";
  s.textContent = FF_CSS;
  document.head.appendChild(s);
})();

// ---------- Produce tile ----------
function Tile({ item, inBag, onTap }) {
  const ref = useRef(null);
  const tap = () => {
    if (ref.current) {
      ref.current.classList.remove("tile-pulse");
      void ref.current.offsetWidth;
      ref.current.classList.add("tile-pulse");
    }
    onTap(item);
  };
  return (
    <button className="tile" ref={ref} onClick={tap}>
      {inBag > 0 && <span className="inbag tnum">{inBag}</span>}
      <span className={"unit-tag " + item.unit}>{item.unit === "lb" ? "/ lb" : "each"}</span>
      <span className="emoji">{item.emoji}</span>
      <span className="nm">{item.name}</span>
      <span className="pr mono"><b>{FF.money(item.price)}</b></span>
    </button>
  );
}

// ---------- Number keypad (emits keystrokes via onKey; parent accumulates) ----------
function Keypad({ onKey, allowDecimal = true }) {
  const keys = ["1","2","3","4","5","6","7","8","9", allowDecimal ? "." : "", "0", "del"];
  return (
    <div className="kp">
      {keys.map((k, i) =>
        k === "" ? <span key={i} /> :
        <button key={i} className={k === "." ? "act" : ""} onClick={() => onKey(k)}>
          {k === "del" ? "⌫" : k}
        </button>
      )}
    </div>
  );
}

// ---------- +/- stepper ----------
function Stepper({ value, onChange, min = 0 }) {
  return (
    <div style={{ display:"flex", alignItems:"center", gap:0, border:"1.5px solid var(--line)",
      borderRadius:12, overflow:"hidden", background:"var(--surface)" }}>
      <button onClick={() => onChange(Math.max(min, value - 1))}
        style={{ width:40, height:40, fontSize:22, fontWeight:700, color:"var(--ink-soft)" }}>−</button>
      <span className="mono" style={{ minWidth:30, textAlign:"center", fontSize:16, fontWeight:700 }}>{value}</span>
      <button onClick={() => onChange(value + 1)}
        style={{ width:40, height:40, fontSize:22, fontWeight:700, color:"var(--green-ink)" }}>+</button>
    </div>
  );
}

// ---------- themed confirm dialog (replaces the browser's native confirm) ----------
function ConfirmModal({ title, message, confirmLabel = "OK", cancelLabel = "Cancel", tone = "terra", onConfirm, onCancel }) {
  return (
    <div className="scrim center" onClick={onCancel} style={{ zIndex:90 }}>
      <div className="modal-card" onClick={(e) => e.stopPropagation()} style={{ padding:"22px 20px 18px", maxWidth:340 }}>
        <div style={{ fontWeight:800, fontSize:19, letterSpacing:"-.01em", marginBottom:6 }}>{title}</div>
        {message && (
          <div style={{ fontSize:14.5, color:"var(--ink-soft)", fontWeight:600, lineHeight:1.45, marginBottom:18 }}>{message}</div>
        )}
        <div style={{ display:"grid", gridTemplateColumns:"1fr 1fr", gap:10 }}>
          <button className="btn btn-ghost" onClick={onCancel}>{cancelLabel}</button>
          <button className={"btn " + (tone === "green" ? "btn-green" : "btn-terra")} onClick={onConfirm}>{confirmLabel}</button>
        </div>
      </div>
    </div>
  );
}

// ---------- void-a-sale dialog (asks for a reason, kept as a record) ----------
function VoidModal({ number, total, onVoid, onCancel }) {
  const [reason, setReason] = useState("");
  const picks = ["Wrong items", "Customer changed mind", "Rang up twice", "Refund"];
  return (
    <div className="scrim center" onClick={onCancel} style={{ zIndex:90 }}>
      <div className="modal-card" onClick={(e) => e.stopPropagation()} style={{ padding:"22px 20px 18px", maxWidth:360 }}>
        <div style={{ fontWeight:800, fontSize:19, letterSpacing:"-.01em", marginBottom:4 }}>Void Sale {number}?</div>
        <div style={{ fontSize:14, color:"var(--ink-soft)", fontWeight:600, lineHeight:1.45, marginBottom:14 }}>
          It stays on record as <b>voided</b> (never deleted) and won't count in the day's total. Why are you voiding it?
        </div>
        <div style={{ display:"flex", flexWrap:"wrap", gap:7, marginBottom:11 }}>
          {picks.map(p => (
            <button key={p} onClick={() => setReason(p)}
              style={{ fontSize:12.5, fontWeight:700, padding:"7px 11px", borderRadius:999,
                background: reason === p ? "var(--terra-bg)" : "var(--bg-2)",
                border:"1.5px solid " + (reason === p ? "var(--terra)" : "var(--line)"),
                color: reason === p ? "var(--terra-ink)" : "var(--ink-soft)" }}>{p}</button>
          ))}
        </div>
        <input className="adm-input" value={reason} onChange={(e) => setReason(e.target.value)}
          placeholder="Reason…" style={{ marginBottom:16 }} />
        <div style={{ display:"grid", gridTemplateColumns:"1fr 1fr", gap:10 }}>
          <button className="btn btn-ghost" onClick={onCancel}>Cancel</button>
          <button className="btn btn-terra" disabled={!reason.trim()} onClick={() => onVoid(reason.trim())}>Void sale</button>
        </div>
      </div>
    </div>
  );
}

Object.assign(window, { Tile, Keypad, Stepper, ConfirmModal, VoidModal });
