// Driver tools — HOS clock, Pay calculator, Detention timer.
// All client-side. Detention timer persists logs to localStorage so
// drivers can hand over a CSV trail when their dispatcher disputes it.
// Auth-gated at the router; tile only shows when signed in.

const { useState: useStateTl, useEffect: useEffectTl, useRef: useRefTl, useMemo: useMemoTl } = React;

// =============================================================
// HOURS-OF-SERVICE CLOCK
// Federal property-carrying rules (49 CFR 395):
//   • 11 hr max driving in a 14 hr on-duty window
//   • 30-min break required after 8 cumulative driving hours
//   • 10 consecutive hours off-duty before next shift
//   • 70 hrs / 8 days (or 60 / 7) for the rolling limit
// Driver inputs hours used today + rolling-week total; tool computes
// what's left. No backend, no GPS, no ELD pretensions.
// =============================================================
function HosClock() {
  const [drove, setDrove] = useStateTl("");
  const [onDuty, setOnDuty] = useStateTl("");
  const [weekly, setWeekly] = useStateTl("");
  const [rule, setRule] = useStateTl("70/8");

  function num(v) { const n = parseFloat(v); return isFinite(n) && n >= 0 ? n : 0; }
  const d = num(drove);
  const od = num(onDuty);
  const wk = num(weekly);

  const drvLeft = Math.max(0, 11 - d);
  const winLeft = Math.max(0, 14 - od);
  const breakIn = d < 8 ? Math.max(0, 8 - d) : null;
  const weeklyMax = rule === "70/8" ? 70 : 60;
  const wkLeft = Math.max(0, weeklyMax - wk);

  const drvOver = d > 11;
  const winOver = od > 14;
  const wkOver  = wk > weeklyMax;
  const needBreak = d >= 8;

  const tone = (over, warn) => over ? "crit" : warn ? "warn" : "ok";

  function fmt(h) {
    if (h === 0) return "0:00";
    const hours = Math.floor(h);
    const mins = Math.round((h - hours) * 60);
    return `${hours}:${String(mins).padStart(2, "0")}`;
  }

  return (
    <div className="tool-card">
      <div className="tool-h">
        <div className="tool-eyebrow">⏱ Tool 01</div>
        <h2 className="tool-title">Hours-of-service clock</h2>
        <p className="tool-sub">
          Federal property-carrying rules (49 CFR 395). You enter hours used
          today + this week. We tell you what's left.
        </p>
      </div>

      <div className="tool-form">
        <label className="tool-field">
          <span>Driving hours so far today</span>
          <input type="number" min="0" max="24" step="0.25"
            value={drove} onChange={e => setDrove(e.target.value)}
            placeholder="e.g. 6.5" />
        </label>
        <label className="tool-field">
          <span>On-duty hours so far today</span>
          <input type="number" min="0" max="24" step="0.25"
            value={onDuty} onChange={e => setOnDuty(e.target.value)}
            placeholder="e.g. 8.5" />
        </label>
        <label className="tool-field">
          <span>{rule === "70/8" ? "Hours rolling 8 days" : "Hours rolling 7 days"}</span>
          <input type="number" min="0" max="100" step="0.25"
            value={weekly} onChange={e => setWeekly(e.target.value)}
            placeholder="e.g. 42" />
        </label>
        <div className="tool-field tool-field-radio">
          <span>Weekly rule</span>
          <div className="tool-radio-row">
            <label><input type="radio" name="rule" checked={rule === "70/8"} onChange={() => setRule("70/8")} /> 70 hr / 8 days</label>
            <label><input type="radio" name="rule" checked={rule === "60/7"} onChange={() => setRule("60/7")} /> 60 hr / 7 days</label>
          </div>
        </div>
      </div>

      <div className="tool-out">
        <div className={`tool-out-tile tone-${tone(drvOver, drvLeft <= 1)}`}>
          <div className="tool-out-l">Drive time left</div>
          <div className="tool-out-n">{drvOver ? "OVER" : fmt(drvLeft)}</div>
          <div className="tool-out-s">{drvOver ? `Over by ${fmt(d - 11)}` : "of 11 hr"}</div>
        </div>
        <div className={`tool-out-tile tone-${tone(winOver, winLeft <= 1)}`}>
          <div className="tool-out-l">14-hr window left</div>
          <div className="tool-out-n">{winOver ? "OVER" : fmt(winLeft)}</div>
          <div className="tool-out-s">{winOver ? `Over by ${fmt(od - 14)}` : "of 14 hr"}</div>
        </div>
        <div className={`tool-out-tile tone-${needBreak ? "warn" : "ok"}`}>
          <div className="tool-out-l">30-min break</div>
          <div className="tool-out-n">{needBreak ? "DUE" : fmt(breakIn || 0)}</div>
          <div className="tool-out-s">{needBreak ? "Take it before driving more" : "until required"}</div>
        </div>
        <div className={`tool-out-tile tone-${tone(wkOver, wkLeft <= 5)}`}>
          <div className="tool-out-l">{rule} left</div>
          <div className="tool-out-n">{wkOver ? "OVER" : fmt(wkLeft)}</div>
          <div className="tool-out-s">{wkOver ? `Over by ${fmt(wk - weeklyMax)}` : `of ${weeklyMax} hr`}</div>
        </div>
      </div>

      <p className="tool-foot">
        Estimate only. Your ELD is the legal record. If your dispatcher tells you
        to keep driving past your 11 or 14, this calculator does not change the
        regulation — pull over and call DOT at 1-888-DOT-SAFT.
        {" "}
        <a href="#/hos" style={{ color: "var(--ink)", borderBottom: "1px solid var(--ink)", textDecoration: "none", paddingBottom: 1, fontStyle: "normal", fontWeight: 600 }}>
          Read the full FMCSA rules →
        </a>
      </p>
    </div>
  );
}

// =============================================================
// PAY CALCULATOR
// Owner-op + company driver use case: figure out what a load actually
// pays per hour (not per mile). Detention is included because it's
// half the difference between a profitable load and a losing one.
// =============================================================
function PayCalc() {
  const [cpm, setCpm] = useStateTl("0.65");
  const [loaded, setLoaded] = useStateTl("");
  const [dead, setDead] = useStateTl("");
  const [drvHrs, setDrvHrs] = useStateTl("");
  const [waitHrs, setWaitHrs] = useStateTl("");
  const [waitFreeHrs, setWaitFreeHrs] = useStateTl("2");
  const [detRate, setDetRate] = useStateTl("50");
  const [accessorials, setAccessorials] = useStateTl("");
  const [fuelGal, setFuelGal] = useStateTl("");
  const [fuelPpg, setFuelPpg] = useStateTl("3.95");

  function num(v) { const n = parseFloat(v); return isFinite(n) ? n : 0; }
  const cm = num(cpm);
  const lm = num(loaded), dm = num(dead);
  const dh = num(drvHrs), wh = num(waitHrs);
  const wf = num(waitFreeHrs);
  const dr = num(detRate);
  const ax = num(accessorials);
  const fg = num(fuelGal), fp = num(fuelPpg);

  const lineHaul = (lm + dm) * cm;
  const detention = Math.max(0, wh - wf) * dr;
  const fuelCost = fg * fp;
  const gross = lineHaul + detention + ax;
  const net = gross - fuelCost;
  const totalHrs = dh + wh;
  const perHour = totalHrs > 0 ? net / totalHrs : 0;
  const perDriveHr = dh > 0 ? net / dh : 0;
  const ratePerMile = (lm + dm) > 0 ? gross / (lm + dm) : 0;

  const fmt$ = (n) => `$${n.toFixed(2)}`;
  const fmtCPM = (n) => `$${n.toFixed(3)}/mi`;

  return (
    <div className="tool-card">
      <div className="tool-h">
        <div className="tool-eyebrow">💵 Tool 02</div>
        <h2 className="tool-title">Load pay calculator</h2>
        <p className="tool-sub">
          What did this load actually pay you per hour — once you account for
          detention, deadhead, fuel, and the time the dock made you sit?
        </p>
      </div>

      <div className="tool-form tool-form-pay">
        <label className="tool-field">
          <span>Rate per mile (CPM, $)</span>
          <input type="number" step="0.01" min="0" value={cpm}
            onChange={e => setCpm(e.target.value)} />
        </label>
        <label className="tool-field">
          <span>Loaded miles</span>
          <input type="number" min="0" value={loaded}
            onChange={e => setLoaded(e.target.value)} placeholder="0" />
        </label>
        <label className="tool-field">
          <span>Deadhead miles</span>
          <input type="number" min="0" value={dead}
            onChange={e => setDead(e.target.value)} placeholder="0" />
        </label>
        <label className="tool-field">
          <span>Driving hours</span>
          <input type="number" min="0" step="0.25" value={drvHrs}
            onChange={e => setDrvHrs(e.target.value)} placeholder="0" />
        </label>
        <label className="tool-field">
          <span>Wait / dock hours</span>
          <input type="number" min="0" step="0.25" value={waitHrs}
            onChange={e => setWaitHrs(e.target.value)} placeholder="0" />
        </label>
        <label className="tool-field">
          <span>Free wait (hrs before detention)</span>
          <input type="number" min="0" step="0.5" value={waitFreeHrs}
            onChange={e => setWaitFreeHrs(e.target.value)} />
        </label>
        <label className="tool-field">
          <span>Detention $/hr</span>
          <input type="number" min="0" step="5" value={detRate}
            onChange={e => setDetRate(e.target.value)} />
        </label>
        <label className="tool-field">
          <span>Other accessorials ($)</span>
          <input type="number" min="0" step="10" value={accessorials}
            onChange={e => setAccessorials(e.target.value)} placeholder="0" />
        </label>
        <label className="tool-field">
          <span>Fuel burned (gal)</span>
          <input type="number" min="0" step="1" value={fuelGal}
            onChange={e => setFuelGal(e.target.value)} placeholder="0" />
        </label>
        <label className="tool-field">
          <span>Fuel $/gal</span>
          <input type="number" min="0" step="0.01" value={fuelPpg}
            onChange={e => setFuelPpg(e.target.value)} />
        </label>
      </div>

      <div className="tool-out">
        <div className="tool-out-tile">
          <div className="tool-out-l">Linehaul</div>
          <div className="tool-out-n">{fmt$(lineHaul)}</div>
          <div className="tool-out-s">{(lm + dm).toLocaleString()} mi @ {fmt$(cm)}</div>
        </div>
        <div className="tool-out-tile">
          <div className="tool-out-l">Detention</div>
          <div className="tool-out-n">{fmt$(detention)}</div>
          <div className="tool-out-s">{Math.max(0, wh - wf).toFixed(1)} hr × {fmt$(dr)}</div>
        </div>
        <div className="tool-out-tile">
          <div className="tool-out-l">Gross</div>
          <div className="tool-out-n">{fmt$(gross)}</div>
          <div className="tool-out-s">all-in for the load</div>
        </div>
        <div className="tool-out-tile">
          <div className="tool-out-l">Net of fuel</div>
          <div className="tool-out-n">{fmt$(net)}</div>
          <div className="tool-out-s">fuel cost {fmt$(fuelCost)}</div>
        </div>
        <div className={`tool-out-tile tone-${perHour < 25 && totalHrs > 0 ? "warn" : "ok"}`}>
          <div className="tool-out-l">Net per hour total</div>
          <div className="tool-out-n">{fmt$(perHour)}</div>
          <div className="tool-out-s">{totalHrs.toFixed(1)} hr (drive + wait)</div>
        </div>
        <div className="tool-out-tile">
          <div className="tool-out-l">Net per drive hour</div>
          <div className="tool-out-n">{fmt$(perDriveHr)}</div>
          <div className="tool-out-s">{dh.toFixed(1)} hr behind the wheel</div>
        </div>
        <div className="tool-out-tile">
          <div className="tool-out-l">Effective rate</div>
          <div className="tool-out-n">{fmtCPM(ratePerMile)}</div>
          <div className="tool-out-s">gross ÷ all miles</div>
        </div>
      </div>

      <p className="tool-foot">
        If "net per hour total" comes in under your local minimum wage, the dock
        sat you for free and the broker booked the load against you. Save the
        number. Quote it next time someone tells you a $0.65/mi run is "good pay."
      </p>
    </div>
  );
}

// =============================================================
// DETENTION TIMER
// Tap "Start waiting" when the gate guard takes your number, "Rolling"
// when the wheels move. Logs to localStorage so the trail survives
// reload + a CSV export feeds your dispatcher's dispute. No DB on the
// server — your phone, your record. (We could ship a synced version
// on the paid driver tier later; this stays free forever.)
// =============================================================
const DET_KEY = "sc.detentionLogs.v1";
const DET_ACTIVE_KEY = "sc.detentionActive.v1";

function DetentionTimer() {
  const [active, setActive] = useStateTl(() => {
    try { return JSON.parse(localStorage.getItem(DET_ACTIVE_KEY) || "null"); }
    catch { return null; }
  });
  const [logs, setLogs] = useStateTl(() => {
    try { return JSON.parse(localStorage.getItem(DET_KEY) || "[]"); }
    catch { return []; }
  });
  const [now, setNow] = useStateTl(Date.now());
  const [where, setWhere] = useStateTl("");
  const [dock, setDock] = useStateTl("");
  // Dispute-letter modal state. Picks the saved session, opens a small
  // form for broker name + contract terms, then renders a ready-to-send
  // letter with all the timestamps + dollar claim worked out.
  const [disputeFor, setDisputeFor] = useStateTl(null);
  const [dispBroker, setDispBroker] = useStateTl("");
  const [dispEmail, setDispEmail] = useStateTl("");
  const [dispLoad, setDispLoad] = useStateTl("");
  const [dispFreeHrs, setDispFreeHrs] = useStateTl("2");
  const [dispRate, setDispRate] = useStateTl("50");
  const [dispDriver, setDispDriver] = useStateTl("");

  // Live tick while a session is active.
  useEffectTl(() => {
    if (!active) return;
    const t = setInterval(() => setNow(Date.now()), 1000);
    return () => clearInterval(t);
  }, [!!active]);

  function persistActive(v) {
    try { localStorage.setItem(DET_ACTIVE_KEY, JSON.stringify(v)); } catch {}
    setActive(v);
  }
  function persistLogs(v) {
    try { localStorage.setItem(DET_KEY, JSON.stringify(v)); } catch {}
    setLogs(v);
  }

  function start() {
    const session = {
      startedAt: Date.now(),
      where: where.trim(),
      dock: dock.trim(),
    };
    persistActive(session);
  }
  function stop() {
    if (!active) return;
    const ended = {
      ...active,
      endedAt: Date.now(),
      durationMs: Date.now() - active.startedAt,
    };
    const next = [ended, ...logs].slice(0, 200);
    persistLogs(next);
    persistActive(null);
    setWhere(""); setDock("");
  }
  function delLog(i) {
    const next = logs.slice(); next.splice(i, 1);
    persistLogs(next);
  }
  function clearAll() {
    if (!window.confirm("Clear every saved detention session? This cannot be undone.")) return;
    persistLogs([]);
  }
  function exportCsv() {
    if (logs.length === 0) return;
    const rows = [
      ["started_iso", "ended_iso", "duration_min", "where", "dock"],
      ...logs.map(l => [
        new Date(l.startedAt).toISOString(),
        new Date(l.endedAt).toISOString(),
        Math.round(l.durationMs / 60000),
        (l.where || "").replace(/"/g, '""'),
        (l.dock || "").replace(/"/g, '""'),
      ]),
    ];
    const csv = rows.map(r => r.map(c => /[",\n]/.test(String(c)) ? `"${c}"` : c).join(",")).join("\n");
    const blob = new Blob([csv], { type: "text/csv" });
    const url = URL.createObjectURL(blob);
    const a = document.createElement("a");
    a.href = url; a.download = `detention-log-${new Date().toISOString().slice(0,10)}.csv`;
    a.click();
    URL.revokeObjectURL(url);
  }

  function fmtElapsed(ms) {
    const s = Math.max(0, Math.floor(ms / 1000));
    const h = Math.floor(s / 3600);
    const m = Math.floor((s % 3600) / 60);
    const ss = s % 60;
    return `${String(h).padStart(2,"0")}:${String(m).padStart(2,"0")}:${String(ss).padStart(2,"0")}`;
  }
  function fmtDur(ms) {
    const m = Math.round(ms / 60000);
    const h = Math.floor(m / 60), mm = m % 60;
    if (h === 0) return `${mm} min`;
    return `${h} hr ${String(mm).padStart(2,"0")} min`;
  }
  function fmtTime(ts) {
    return new Date(ts).toLocaleString(undefined, {
      month: "short", day: "numeric", hour: "numeric", minute: "2-digit",
    });
  }

  // Dispute letter builder. Pure-string template; no branding, no logo —
  // drivers paste this into Gmail / their broker portal and send. Shows
  // the contract math: hours over free time × rate = claim.
  function buildDisputeText(log) {
    const free = parseFloat(dispFreeHrs) || 0;
    const rate = parseFloat(dispRate) || 0;
    const totalHrs = log.durationMs / 3600000;
    const billable = Math.max(0, totalHrs - free);
    const claim = billable * rate;
    const startStr = new Date(log.startedAt).toLocaleString();
    const endStr = new Date(log.endedAt).toLocaleString();
    const facility = [log.where, log.dock].filter(Boolean).join(" · ") || "Receiver";
    const broker = (dispBroker || "[Broker]").trim();
    const driverLine = dispDriver.trim() || "[Driver name]";
    const loadLine = dispLoad.trim() ? `Load / Pro #: ${dispLoad.trim()}\n` : "";
    return (
`Subject: Detention claim — ${facility} — ${new Date(log.startedAt).toLocaleDateString()}

To: ${dispEmail || "[Broker email]"}

${broker} team,

Per the rate confirmation on the load below, I'm submitting the following detention claim. All times verified by my on-device session log.

${loadLine}Facility: ${facility}
Arrived (gate / check-in): ${startStr}
Departed (wheels rolling): ${endStr}
Total time on facility: ${totalHrs.toFixed(2)} hours
Free time per contract: ${free.toFixed(2)} hours
Billable detention: ${billable.toFixed(2)} hours
Contract rate: $${rate.toFixed(2)}/hour
———
Claim total: $${claim.toFixed(2)}

Please confirm receipt and process for the next settlement cycle. Happy to provide additional documentation if needed.

Thanks,
${driverLine}
`
    );
  }
  function copyDispute() {
    if (!disputeFor) return;
    const text = buildDisputeText(disputeFor);
    if (navigator.clipboard && navigator.clipboard.writeText) {
      navigator.clipboard.writeText(text).then(() => {
        // Brief inline confirm — re-using the dispBroker as a flash field is messy;
        // simplest: alert. Drivers expect tactile feedback here.
        alert("Letter copied to clipboard.");
      }).catch(() => {});
    }
  }
  function mailDispute() {
    if (!disputeFor) return;
    const text = buildDisputeText(disputeFor);
    // Pull subject line out for mailto
    const m = text.match(/^Subject:\s*(.+?)\n/);
    const subj = m ? m[1] : "Detention claim";
    const body = text.replace(/^Subject:\s*.+?\n+/, "");
    const to = (dispEmail || "").trim();
    const href = `mailto:${encodeURIComponent(to)}?subject=${encodeURIComponent(subj)}&body=${encodeURIComponent(body)}`;
    window.location.href = href;
  }
  function downloadDispute() {
    if (!disputeFor) return;
    const text = buildDisputeText(disputeFor);
    const blob = new Blob([text], { type: "text/plain" });
    const url = URL.createObjectURL(blob);
    const a = document.createElement("a");
    a.href = url;
    a.download = `detention-claim-${new Date(disputeFor.startedAt).toISOString().slice(0,10)}.txt`;
    a.click();
    URL.revokeObjectURL(url);
  }

  const elapsedMs = active ? now - active.startedAt : 0;

  return (
    <div className="tool-card tool-detention">
      <div className="tool-h">
        <div className="tool-eyebrow">⏰ Tool 03</div>
        <h2 className="tool-title">Detention timer + dispute generator</h2>
        <p className="tool-sub">
          Tap when you arrive. Tap again when wheels roll. Hit "Dispute" on any
          saved session to generate a ready-to-send claim letter — broker name,
          contract terms, dollar amount worked out, copy or email in one tap.
        </p>
      </div>

      {active ? (
        <div className="dt-running">
          <div className="dt-elapsed">{fmtElapsed(elapsedMs)}</div>
          <div className="dt-where">
            {active.where || active.dock
              ? `${active.where || ""}${active.where && active.dock ? " · " : ""}${active.dock || ""}`
              : "Session in progress"}
          </div>
          <div className="dt-since">Started {fmtTime(active.startedAt)}</div>
          <button className="dt-btn dt-btn-stop" onClick={stop}>Wheels rolling — stop timer</button>
        </div>
      ) : (
        <div className="dt-idle">
          <div className="tool-form tool-form-pay">
            <label className="tool-field">
              <span>Where (optional)</span>
              <input type="text" placeholder="Walmart DC #6021, Sacramento"
                value={where} onChange={e => setWhere(e.target.value)} />
            </label>
            <label className="tool-field">
              <span>Dock / door (optional)</span>
              <input type="text" placeholder="Door 47"
                value={dock} onChange={e => setDock(e.target.value)} />
            </label>
          </div>
          <button className="dt-btn dt-btn-start" onClick={start}>I'm waiting — start timer</button>
        </div>
      )}

      {logs.length > 0 && (
        <div className="dt-logs">
          <div className="dt-logs-h">
            <span>Saved sessions · {logs.length}</span>
            <span className="dt-logs-tools">
              <button className="dt-link" onClick={exportCsv}>Export CSV</button>
              <span className="dt-link-sep">·</span>
              <button className="dt-link dt-link-danger" onClick={clearAll}>Clear all</button>
            </span>
          </div>
          <ul className="dt-list">
            {logs.map((l, i) => (
              <li key={l.startedAt + ":" + l.endedAt} className="dt-li">
                <div className="dt-li-dur">{fmtDur(l.durationMs)}</div>
                <div className="dt-li-body">
                  <div className="dt-li-when">
                    {fmtTime(l.startedAt)} — {fmtTime(l.endedAt)}
                  </div>
                  {(l.where || l.dock) && (
                    <div className="dt-li-where">
                      {l.where}{l.where && l.dock ? " · " : ""}{l.dock}
                    </div>
                  )}
                </div>
                <div style={{ display: "flex", gap: 12, alignItems: "center" }}>
                  <button className="dt-link" onClick={() => setDisputeFor(l)}>Dispute</button>
                  <span className="dt-link-sep">·</span>
                  <button className="dt-link dt-link-danger" onClick={() => delLog(i)}>Delete</button>
                </div>
              </li>
            ))}
          </ul>
        </div>
      )}

      {disputeFor && (
        <div style={{
          position: "fixed", inset: 0, background: "rgba(20, 18, 14, 0.55)",
          zIndex: 100, display: "flex", alignItems: "center", justifyContent: "center",
          padding: 24,
        }} onClick={(e) => { if (e.target === e.currentTarget) setDisputeFor(null); }}>
          <div style={{
            background: "#fff", borderRadius: 10, maxWidth: 720, width: "100%",
            maxHeight: "90vh", overflow: "auto", padding: 28, position: "relative",
          }}>
            <button onClick={() => setDisputeFor(null)} style={{
              position: "absolute", top: 14, right: 14, background: "transparent",
              border: 0, cursor: "pointer", fontSize: 22, color: "var(--ink-soft)",
              lineHeight: 1,
            }}>×</button>
            <div style={{
              fontFamily: "var(--font-mono)", fontSize: 11, letterSpacing: "0.18em",
              textTransform: "uppercase", color: "var(--ink-soft)", marginBottom: 8,
            }}>Generate dispute letter</div>
            <h3 style={{
              fontFamily: "var(--font-serif)", fontSize: 26, letterSpacing: "-0.02em",
              margin: "0 0 6px",
            }}>
              {fmtDur(disputeFor.durationMs)} at {disputeFor.where || disputeFor.dock || "the facility"}
            </h3>
            <p style={{ color: "var(--ink-soft)", fontSize: 13, margin: "0 0 22px" }}>
              {fmtTime(disputeFor.startedAt)} — {fmtTime(disputeFor.endedAt)}
            </p>

            <div className="tool-form" style={{ marginBottom: 20 }}>
              <label className="tool-field">
                <span>Broker name</span>
                <input type="text" placeholder="Acme Logistics" value={dispBroker} onChange={e => setDispBroker(e.target.value)} />
              </label>
              <label className="tool-field">
                <span>Broker email (optional)</span>
                <input type="email" placeholder="ops@brokerage.com" value={dispEmail} onChange={e => setDispEmail(e.target.value)} />
              </label>
              <label className="tool-field">
                <span>Load / Pro # (optional)</span>
                <input type="text" placeholder="L-12345" value={dispLoad} onChange={e => setDispLoad(e.target.value)} />
              </label>
              <label className="tool-field">
                <span>Your name</span>
                <input type="text" placeholder="J. Driver" value={dispDriver} onChange={e => setDispDriver(e.target.value)} />
              </label>
              <label className="tool-field">
                <span>Free hrs (per contract)</span>
                <input type="number" min="0" step="0.25" value={dispFreeHrs} onChange={e => setDispFreeHrs(e.target.value)} />
              </label>
              <label className="tool-field">
                <span>Detention $/hr</span>
                <input type="number" min="0" step="5" value={dispRate} onChange={e => setDispRate(e.target.value)} />
              </label>
            </div>

            <div style={{ marginBottom: 16 }}>
              <div style={{
                fontFamily: "var(--font-mono)", fontSize: 10, letterSpacing: "0.14em",
                textTransform: "uppercase", color: "var(--ink-soft)", marginBottom: 8,
              }}>Letter preview</div>
              <pre style={{
                background: "var(--paper-2)", border: "1px solid var(--rule)",
                borderRadius: 6, padding: 16, fontFamily: "ui-monospace, Menlo, monospace",
                fontSize: 12, lineHeight: 1.55, whiteSpace: "pre-wrap",
                wordBreak: "break-word", margin: 0, maxHeight: 280, overflowY: "auto",
              }}>{buildDisputeText(disputeFor)}</pre>
            </div>

            <div style={{ display: "flex", gap: 8, flexWrap: "wrap" }}>
              <button className="dt-btn" onClick={mailDispute} style={{ background: "var(--ink)" }}>Open in email →</button>
              <button className="dt-btn" onClick={copyDispute} style={{ background: "#fff", color: "var(--ink)" }}>Copy text</button>
              <button className="dt-btn" onClick={downloadDispute} style={{ background: "#fff", color: "var(--ink)" }}>Download .txt</button>
            </div>
          </div>
        </div>
      )}

      <p className="tool-foot">
        Records live on this device. Clear browser data and they're gone — so
        export your CSV before swapping phones. We'll add a synced paid-driver
        tier later; this one stays free, period.
      </p>
    </div>
  );
}

// =============================================================
// FUEL SURCHARGE CALCULATOR
// Industry standard formula for fuel surcharge in trucking:
//   FSC ($/mi) = max(0, (current_diesel - base_price) / mpg)
// Base price is whatever the broker contract pegs (commonly $1.20/gal
// historical floor); MPG is the truck's measured average. The result is
// what the driver should be billing on top of linehaul. Most drivers
// don't bill it because they don't know how to compute it.
// =============================================================
function FuelSurcharge() {
  const [retail, setRetail] = useStateTl("3.95");
  const [base, setBase] = useStateTl("1.20");
  const [mpg, setMpg] = useStateTl("6.5");
  const [miles, setMiles] = useStateTl("");

  function num(v) { const n = parseFloat(v); return isFinite(n) && n > 0 ? n : 0; }
  const r = num(retail);
  const b = num(base);
  const m = num(mpg);
  const mi = num(miles);

  const fscPerMile = m > 0 ? Math.max(0, (r - b) / m) : 0;
  const fscTotal = fscPerMile * mi;
  // Industry tiered table — common in carrier-broker contracts. Rate
  // recomputes per $0.05 step; breaks help drivers eyeball whether the
  // broker's posted FSC is in line.
  const tiers = [];
  for (let p = Math.max(2.0, Math.floor(b * 20) / 20); p <= 6.5; p += 0.10) {
    tiers.push({
      diesel: p,
      fsc: m > 0 ? Math.max(0, (p - b) / m) : 0,
    });
  }

  const fmt$ = (n, d=2) => `$${n.toFixed(d)}`;

  return (
    <div className="tool-card">
      <div className="tool-h">
        <div className="tool-eyebrow">⛽ Tool 04</div>
        <h2 className="tool-title">Fuel surcharge calculator</h2>
        <p className="tool-sub">
          Standard formula: <code style={{ background: "var(--paper-2)", padding: "2px 6px", borderRadius: 3, fontSize: 13 }}>(diesel − base) ÷ MPG</code>.
          Most drivers leave money on the table because they don't compute it.
          Run your own number, compare it to whatever the broker posts.
        </p>
      </div>

      <div className="tool-form">
        <label className="tool-field">
          <span>Current diesel ($/gal)</span>
          <input type="number" min="0" step="0.01" value={retail}
            onChange={e => setRetail(e.target.value)} />
        </label>
        <label className="tool-field">
          <span>Contract base ($/gal)</span>
          <input type="number" min="0" step="0.01" value={base}
            onChange={e => setBase(e.target.value)} />
        </label>
        <label className="tool-field">
          <span>Your truck's MPG</span>
          <input type="number" min="0" step="0.1" value={mpg}
            onChange={e => setMpg(e.target.value)} />
        </label>
        <label className="tool-field">
          <span>Loaded miles (optional)</span>
          <input type="number" min="0" value={miles}
            onChange={e => setMiles(e.target.value)} placeholder="0" />
        </label>
      </div>

      <div className="tool-out">
        <div className="tool-out-tile tone-ok">
          <div className="tool-out-l">FSC per mile</div>
          <div className="tool-out-n">{fmt$(fscPerMile, 4)}</div>
          <div className="tool-out-s">on top of your linehaul</div>
        </div>
        <div className="tool-out-tile">
          <div className="tool-out-l">Spread vs base</div>
          <div className="tool-out-n">{fmt$(Math.max(0, r - b))}</div>
          <div className="tool-out-s">per gallon over contract</div>
        </div>
        {mi > 0 && (
          <div className="tool-out-tile tone-ok">
            <div className="tool-out-l">FSC for this load</div>
            <div className="tool-out-n">{fmt$(fscTotal)}</div>
            <div className="tool-out-s">{mi.toLocaleString()} miles × {fmt$(fscPerMile, 4)}</div>
          </div>
        )}
        {mi > 0 && (
          <div className="tool-out-tile">
            <div className="tool-out-l">Per gal over base</div>
            <div className="tool-out-n">{(mi / m).toFixed(1)}</div>
            <div className="tool-out-s">gal you'll burn</div>
          </div>
        )}
      </div>

      <details style={{ marginTop: 18 }}>
        <summary style={{ cursor: "pointer", fontFamily: "var(--font-mono)", fontSize: 11, letterSpacing: "0.14em", textTransform: "uppercase", color: "var(--ink-soft)" }}>
          Show full FSC tier table
        </summary>
        <table style={{ marginTop: 14, borderCollapse: "collapse", width: "100%", fontSize: 13 }}>
          <thead>
            <tr style={{ borderBottom: "1px solid var(--rule)" }}>
              <th style={{ textAlign: "left", padding: "8px 12px", fontFamily: "var(--font-mono)", fontSize: 10, letterSpacing: "0.14em", textTransform: "uppercase", color: "var(--ink-soft)" }}>Diesel</th>
              <th style={{ textAlign: "right", padding: "8px 12px", fontFamily: "var(--font-mono)", fontSize: 10, letterSpacing: "0.14em", textTransform: "uppercase", color: "var(--ink-soft)" }}>FSC ($/mi)</th>
              <th style={{ textAlign: "right", padding: "8px 12px", fontFamily: "var(--font-mono)", fontSize: 10, letterSpacing: "0.14em", textTransform: "uppercase", color: "var(--ink-soft)" }}>$/100 mi</th>
            </tr>
          </thead>
          <tbody>
            {tiers.map(t => (
              <tr key={t.diesel} style={{
                borderBottom: "1px solid var(--rule)",
                background: Math.abs(t.diesel - r) < 0.05 ? "var(--paper-2)" : "transparent",
              }}>
                <td style={{ padding: "6px 12px" }}>{fmt$(t.diesel)}</td>
                <td style={{ padding: "6px 12px", textAlign: "right", fontFamily: "var(--font-mono)" }}>{fmt$(t.fsc, 4)}</td>
                <td style={{ padding: "6px 12px", textAlign: "right", fontFamily: "var(--font-mono)" }}>{fmt$(t.fsc * 100)}</td>
              </tr>
            ))}
          </tbody>
        </table>
      </details>

      <p className="tool-foot">
        If the broker posts an FSC that's a nickel below your computed number,
        every load with them is a half-cent miss. Carriers running 100K+ miles
        a year are leaving four-figure money on the table here annually.
      </p>
    </div>
  );
}

// =============================================================
// CDL / MEDICAL / HAZMAT / TWIC / PASSPORT REMINDERS
// localStorage-backed (no DB write yet — that requires a cron-email
// pipeline). Drivers enter expiration dates; the page surfaces big
// status alerts (60/30/7 day countdowns) every time they return.
// When the cron-email layer ships, this tool will offer to migrate
// the local entries to a synced reminder list.
// =============================================================
const REM_KEY = "sc.driverReminders.v1";

const REMINDER_FIELDS = [
  { key: "cdl_expires", label: "CDL expires", help: "Your license. Lapsing = pulled off the road, period." },
  { key: "medical_expires", label: "Medical card expires", help: "DOT physical. 24 mo standard; insulin / sleep apnea may shorten." },
  { key: "hazmat_expires", label: "Hazmat endorsement expires", help: "Renewable every 5 yrs; fingerprints + TSA background re-run." },
  { key: "twic_expires", label: "TWIC expires", help: "Port/secure-area access. 5-yr renewal." },
  { key: "passport_expires", label: "Passport expires", help: "Cross-border (CA/MX) and FAST card prereq." },
];

function Reminders() {
  const [data, setData] = useStateTl(() => {
    try { return JSON.parse(localStorage.getItem(REM_KEY) || "{}"); }
    catch { return {}; }
  });

  function save(next) {
    try { localStorage.setItem(REM_KEY, JSON.stringify(next)); } catch {}
    setData(next);
  }
  function setField(key, val) {
    save({ ...data, [key]: val });
  }
  function clearAll() {
    if (!window.confirm("Clear every saved reminder date? This cannot be undone.")) return;
    save({});
  }

  const today = new Date(); today.setHours(0,0,0,0);
  function daysUntil(dateStr) {
    if (!dateStr) return null;
    const d = new Date(dateStr); d.setHours(0,0,0,0);
    if (isNaN(d)) return null;
    return Math.round((d - today) / 86400000);
  }
  function tone(days) {
    if (days == null) return "";
    if (days < 0) return "crit";   // expired
    if (days <= 30) return "crit"; // <= 30 days
    if (days <= 90) return "warn"; // 31-90
    return "ok";
  }
  function statusLabel(days) {
    if (days == null) return "—";
    if (days < 0) return `Expired ${Math.abs(days)}d ago`;
    if (days === 0) return "Expires today";
    if (days === 1) return "Expires tomorrow";
    if (days <= 30) return `${days}d left`;
    if (days <= 90) return `${days}d left`;
    if (days <= 365) return `${days}d left`;
    const yrs = (days / 365).toFixed(1);
    return `${yrs} yrs left`;
  }

  const upcoming = REMINDER_FIELDS
    .map(f => ({ ...f, days: daysUntil(data[f.key]), date: data[f.key] }))
    .filter(f => f.days != null)
    .sort((a, b) => a.days - b.days);

  const hasAny = upcoming.length > 0;
  const critCount = upcoming.filter(f => f.days != null && f.days <= 30).length;

  return (
    <div className="tool-card">
      <div className="tool-h">
        <div className="tool-eyebrow">📅 Tool 05</div>
        <h2 className="tool-title">Renewal reminders</h2>
        <p className="tool-sub">
          Every credential that can put you on the bench. Enter the dates,
          come back any day, and the alerts are right here. Saves on this
          device only — synced email reminders are next.
        </p>
      </div>

      {hasAny && (
        <div style={{
          marginBottom: 24, padding: 18, borderRadius: 8,
          background: critCount > 0 ? "oklch(0.96 0.05 25)" : "var(--paper-2)",
          border: `1px solid ${critCount > 0 ? "oklch(0.80 0.12 25)" : "var(--rule)"}`,
        }}>
          <div style={{
            fontFamily: "var(--font-mono)", fontSize: 11, letterSpacing: "0.14em",
            textTransform: "uppercase", color: critCount > 0 ? "oklch(0.40 0.18 25)" : "var(--ink-soft)",
            marginBottom: 12, fontWeight: 700,
          }}>
            {critCount > 0 ? `⚠ ${critCount} renewal${critCount === 1 ? "" : "s"} due in 30 days or less` : "Upcoming renewals"}
          </div>
          <div style={{ display: "grid", gap: 8 }}>
            {upcoming.slice(0, 5).map(f => (
              <div key={f.key} style={{
                display: "grid", gridTemplateColumns: "1fr auto auto", gap: 12,
                alignItems: "center", padding: "10px 14px", background: "#fff",
                border: "1px solid var(--rule)", borderRadius: 6,
                borderLeft: f.days != null && f.days <= 30 ? "4px solid oklch(0.55 0.20 25)"
                          : f.days != null && f.days <= 90 ? "4px solid oklch(0.60 0.16 75)"
                          : "4px solid oklch(0.55 0.14 145)",
              }}>
                <div>
                  <div style={{ fontWeight: 600, fontSize: 14 }}>{f.label.replace(" expires", "")}</div>
                  <div style={{ fontFamily: "var(--font-mono)", fontSize: 11, color: "var(--ink-soft)", letterSpacing: "0.04em" }}>
                    {f.date}
                  </div>
                </div>
                <div style={{ fontFamily: "var(--font-serif)", fontSize: 17, fontWeight: 600,
                              color: f.days != null && f.days < 0 ? "oklch(0.40 0.20 25)"
                                   : f.days != null && f.days <= 30 ? "oklch(0.40 0.20 25)"
                                   : f.days != null && f.days <= 90 ? "oklch(0.45 0.15 75)"
                                   : "var(--ink)" }}>
                  {statusLabel(f.days)}
                </div>
              </div>
            ))}
          </div>
        </div>
      )}

      <div className="tool-form">
        {REMINDER_FIELDS.map(f => (
          <label key={f.key} className="tool-field">
            <span>{f.label}</span>
            <input type="date"
              value={data[f.key] || ""}
              onChange={e => setField(f.key, e.target.value)} />
            <span style={{ fontFamily: "var(--font-sans)", textTransform: "none",
                            letterSpacing: 0, fontSize: 11, color: "var(--ink-soft)",
                            marginTop: 2, fontStyle: "italic" }}>
              {f.help}
            </span>
          </label>
        ))}
      </div>

      {hasAny && (
        <div style={{ marginTop: 18, textAlign: "right" }}>
          <button onClick={clearAll} className="dt-link dt-link-danger" style={{ fontSize: 11 }}>
            Clear all dates
          </button>
        </div>
      )}

      <p className="tool-foot">
        Saved on this device only. Clear browser data and they're gone — write
        the dates down somewhere too. Synced email reminders (60 / 30 / 7 day
        warnings) ship with the next driver-tier release.
      </p>
    </div>
  );
}

// =============================================================
// OWNER-OPERATOR COST-PER-MILE CALCULATOR
// The number every OO needs but most don't actually compute. Fixed
// costs (truck note, insurance, plates, permits, ELD subscription)
// stay constant whether the truck rolls or sits — they hit each mile
// only by getting amortized over the year's miles. Variable costs
// (fuel, maintenance, tolls) scale with miles. Driver pay is in there
// because a single-truck OO is paying themselves; multi-truck removes
// it. This is the OG "should I take this load" math.
// =============================================================
function CpmCalc() {
  // Defaults pre-filled to roughly representative midwest single-truck
  // OO running ~120K miles/year. Driver tunes from there.
  const [annualMiles, setAnnualMiles] = useStateTl("120000");
  // FIXED — annual
  const [truckPayment, setTruckPayment] = useStateTl("18000");
  const [trailerPayment, setTrailerPayment] = useStateTl("4800");
  const [insurance, setInsurance] = useStateTl("14000");
  const [platesPermits, setPlatesPermits] = useStateTl("3500");
  const [eldOffice, setEldOffice] = useStateTl("1800");
  const [accountingFactoring, setAccountingFactoring] = useStateTl("3000");
  const [otherFixed, setOtherFixed] = useStateTl("0");
  // VARIABLE — per mile or per gallon
  const [mpg, setMpg] = useStateTl("6.5");
  const [diesel, setDiesel] = useStateTl("3.95");
  const [maintCpm, setMaintCpm] = useStateTl("0.15");
  const [tiresCpm, setTiresCpm] = useStateTl("0.04");
  const [tollsAnnual, setTollsAnnual] = useStateTl("3000");
  // DRIVER PAY — for single-truck OO this is what they take home
  const [driverPay, setDriverPay] = useStateTl("75000");
  // EVALUATING THIS LOAD
  const [thisRate, setThisRate] = useStateTl("");

  function n(v) { const x = parseFloat(v); return isFinite(x) ? x : 0; }
  const am = Math.max(1, n(annualMiles));

  const fixedAnnual = n(truckPayment) + n(trailerPayment) + n(insurance)
    + n(platesPermits) + n(eldOffice) + n(accountingFactoring) + n(otherFixed);
  const fixedCpm = fixedAnnual / am;

  const fuelCpm = n(mpg) > 0 ? n(diesel) / n(mpg) : 0;
  const variableCpm = fuelCpm + n(maintCpm) + n(tiresCpm) + (n(tollsAnnual) / am);
  const driverCpm = n(driverPay) / am;
  const breakeven = fixedCpm + variableCpm;
  const profitableMin = breakeven + driverCpm;

  const thisRateN = n(thisRate);
  const margin = thisRateN > 0 ? thisRateN - profitableMin : null;
  const marginPct = thisRateN > 0 ? ((thisRateN - profitableMin) / thisRateN) * 100 : null;

  const fmt$ = (v, d=3) => `$${v.toFixed(d)}`;
  const fmtPct = (v) => `${v >= 0 ? "+" : ""}${v.toFixed(1)}%`;

  return (
    <div className="tool-card">
      <div className="tool-h">
        <div className="tool-eyebrow">🧾 Tool 06</div>
        <h2 className="tool-title">Owner-operator CPM</h2>
        <p className="tool-sub">
          Your real cost per mile. Fixed costs amortized over the year's miles,
          variable costs that move with the wheels, and your own pay on top.
          Run this once — paste the breakeven into your phone — and never take
          a losing load again.
        </p>
      </div>

      <details open style={{ marginBottom: 24 }}>
        <summary style={{ cursor: "pointer", fontFamily: "var(--font-mono)", fontSize: 11, letterSpacing: "0.18em", textTransform: "uppercase", color: "var(--ink-soft)", padding: "8px 0" }}>
          Fixed costs · annual
        </summary>
        <div className="tool-form tool-form-pay" style={{ marginTop: 14 }}>
          <label className="tool-field">
            <span>Annual miles</span>
            <input type="number" min="1000" step="1000" value={annualMiles}
              onChange={e => setAnnualMiles(e.target.value)} />
          </label>
          <label className="tool-field">
            <span>Truck note ($/yr)</span>
            <input type="number" min="0" step="100" value={truckPayment}
              onChange={e => setTruckPayment(e.target.value)} />
          </label>
          <label className="tool-field">
            <span>Trailer note ($/yr)</span>
            <input type="number" min="0" step="100" value={trailerPayment}
              onChange={e => setTrailerPayment(e.target.value)} />
          </label>
          <label className="tool-field">
            <span>Insurance ($/yr)</span>
            <input type="number" min="0" step="100" value={insurance}
              onChange={e => setInsurance(e.target.value)} />
          </label>
          <label className="tool-field">
            <span>Plates · permits · IFTA ($/yr)</span>
            <input type="number" min="0" step="100" value={platesPermits}
              onChange={e => setPlatesPermits(e.target.value)} />
          </label>
          <label className="tool-field">
            <span>ELD · office · phone ($/yr)</span>
            <input type="number" min="0" step="100" value={eldOffice}
              onChange={e => setEldOffice(e.target.value)} />
          </label>
          <label className="tool-field">
            <span>Accounting · factoring ($/yr)</span>
            <input type="number" min="0" step="100" value={accountingFactoring}
              onChange={e => setAccountingFactoring(e.target.value)} />
          </label>
          <label className="tool-field">
            <span>Other fixed ($/yr)</span>
            <input type="number" min="0" step="100" value={otherFixed}
              onChange={e => setOtherFixed(e.target.value)} />
          </label>
        </div>
      </details>

      <details open style={{ marginBottom: 24 }}>
        <summary style={{ cursor: "pointer", fontFamily: "var(--font-mono)", fontSize: 11, letterSpacing: "0.18em", textTransform: "uppercase", color: "var(--ink-soft)", padding: "8px 0" }}>
          Variable costs · per mile
        </summary>
        <div className="tool-form tool-form-pay" style={{ marginTop: 14 }}>
          <label className="tool-field">
            <span>MPG</span>
            <input type="number" min="0" step="0.1" value={mpg}
              onChange={e => setMpg(e.target.value)} />
          </label>
          <label className="tool-field">
            <span>Diesel ($/gal)</span>
            <input type="number" min="0" step="0.01" value={diesel}
              onChange={e => setDiesel(e.target.value)} />
          </label>
          <label className="tool-field">
            <span>Maintenance ($/mi)</span>
            <input type="number" min="0" step="0.01" value={maintCpm}
              onChange={e => setMaintCpm(e.target.value)} />
          </label>
          <label className="tool-field">
            <span>Tires ($/mi)</span>
            <input type="number" min="0" step="0.01" value={tiresCpm}
              onChange={e => setTiresCpm(e.target.value)} />
          </label>
          <label className="tool-field">
            <span>Tolls ($/yr)</span>
            <input type="number" min="0" step="100" value={tollsAnnual}
              onChange={e => setTollsAnnual(e.target.value)} />
          </label>
        </div>
      </details>

      <details style={{ marginBottom: 24 }}>
        <summary style={{ cursor: "pointer", fontFamily: "var(--font-mono)", fontSize: 11, letterSpacing: "0.18em", textTransform: "uppercase", color: "var(--ink-soft)", padding: "8px 0" }}>
          Driver pay (yourself)
        </summary>
        <div className="tool-form" style={{ marginTop: 14 }}>
          <label className="tool-field">
            <span>What you want to pay yourself ($/yr)</span>
            <input type="number" min="0" step="1000" value={driverPay}
              onChange={e => setDriverPay(e.target.value)} />
            <span style={{ fontFamily: "var(--font-sans)", textTransform: "none",
                            letterSpacing: 0, fontSize: 11, color: "var(--ink-soft)",
                            marginTop: 4, fontStyle: "italic" }}>
              For a single-truck OO. Set to 0 if you're already counting driver pay
              as a separate variable cost.
            </span>
          </label>
        </div>
      </details>

      <div className="tool-out">
        <div className="tool-out-tile">
          <div className="tool-out-l">Fixed CPM</div>
          <div className="tool-out-n">{fmt$(fixedCpm)}</div>
          <div className="tool-out-s">{fmt$(fixedAnnual, 0).replace("$", "$")} / {am.toLocaleString()} mi</div>
        </div>
        <div className="tool-out-tile">
          <div className="tool-out-l">Fuel CPM</div>
          <div className="tool-out-n">{fmt$(fuelCpm)}</div>
          <div className="tool-out-s">{fmt$(n(diesel), 2)}/gal ÷ {n(mpg).toFixed(1)} mpg</div>
        </div>
        <div className="tool-out-tile">
          <div className="tool-out-l">Variable CPM</div>
          <div className="tool-out-n">{fmt$(variableCpm)}</div>
          <div className="tool-out-s">fuel + maint + tires + tolls</div>
        </div>
        <div className="tool-out-tile tone-warn">
          <div className="tool-out-l">Breakeven CPM</div>
          <div className="tool-out-n">{fmt$(breakeven)}</div>
          <div className="tool-out-s">no profit, no driver pay</div>
        </div>
        <div className="tool-out-tile tone-ok">
          <div className="tool-out-l">Profitable rate</div>
          <div className="tool-out-n">{fmt$(profitableMin)}</div>
          <div className="tool-out-s">breakeven + driver pay</div>
        </div>
        <div className="tool-out-tile">
          <div className="tool-out-l">Driver CPM</div>
          <div className="tool-out-n">{fmt$(driverCpm)}</div>
          <div className="tool-out-s">{fmt$(n(driverPay), 0).replace("$", "$")} / yr</div>
        </div>
      </div>

      <div style={{
        marginTop: 28, padding: 22, background: "var(--paper-2)",
        border: "1px solid var(--rule)", borderRadius: 8,
      }}>
        <div style={{
          fontFamily: "var(--font-mono)", fontSize: 11, letterSpacing: "0.18em",
          textTransform: "uppercase", color: "var(--ink-soft)", marginBottom: 14,
        }}>
          Evaluate this load
        </div>
        <div className="tool-form" style={{ marginBottom: 16 }}>
          <label className="tool-field">
            <span>Offered rate ($/mi)</span>
            <input type="number" min="0" step="0.01" value={thisRate}
              onChange={e => setThisRate(e.target.value)} placeholder="e.g. 2.45" />
          </label>
        </div>
        {thisRateN > 0 && (
          <div className="tool-out" style={{ marginBottom: 0 }}>
            <div className={`tool-out-tile tone-${margin >= 0.20 ? "ok" : margin >= 0 ? "warn" : "crit"}`}>
              <div className="tool-out-l">Margin per mile</div>
              <div className="tool-out-n">{margin >= 0 ? "+" : ""}{fmt$(margin, 3)}</div>
              <div className="tool-out-s">over your profitable rate</div>
            </div>
            <div className={`tool-out-tile tone-${marginPct >= 10 ? "ok" : marginPct >= 0 ? "warn" : "crit"}`}>
              <div className="tool-out-l">Margin %</div>
              <div className="tool-out-n">{fmtPct(marginPct)}</div>
              <div className="tool-out-s">on the offered rate</div>
            </div>
            <div className="tool-out-tile">
              <div className="tool-out-l">Verdict</div>
              <div className="tool-out-n" style={{ fontSize: 16, lineHeight: 1.2 }}>
                {margin < 0 ? "Loses money"
                  : margin < 0.10 ? "Razor thin"
                  : margin < 0.30 ? "OK"
                  : "Take it"}
              </div>
              <div className="tool-out-s">vs profitable rate</div>
            </div>
          </div>
        )}
      </div>

      <p className="tool-foot">
        Real-world CPM is more brutal than most OOs admit until they sit down
        and run it. If your breakeven shocks you, that's the point — you're
        running a business now, and the loads have to clear that line.
      </p>
    </div>
  );
}

// =============================================================
// PARKING — TPIMS real-time stall counts at MAASTO rest areas.
// Asks for browser geolocation; falls back to state filter.
// Pulls truck_parking_now (latest obs per site joined to dimension).
// =============================================================
function Parking() {
  const [sites, setSites]       = useStateTl([]);
  const [loading, setLoading]   = useStateTl(true);
  const [userLoc, setUserLoc]   = useStateTl(null);
  const [locStatus, setLocStat] = useStateTl("idle"); // idle|loading|denied|ok|unsupported
  const [stateFilter, setStateF] = useStateTl("all");

  useEffectTl(() => {
    let alive = true;
    if (!window.SI_DB || !window.SI_DB.raw) return;
    (async () => {
      try {
        const rows = await window.SI_DB.raw.select(
          "truck_parking_now",
          "select=site_id,site_name,state,highway,direction,amenity_type,capacity,lat,lng,available,available_pct,status,observed_at&limit=2000"
        );
        if (!alive) return;
        setSites(Array.isArray(rows) ? rows : []);
      } catch {}
      finally { if (alive) setLoading(false); }
    })();
    return () => { alive = false; };
  }, []);

  const requestLocation = () => {
    if (!navigator.geolocation) { setLocStat("unsupported"); return; }
    setLocStat("loading");
    navigator.geolocation.getCurrentPosition(
      pos => { setUserLoc({ lat: pos.coords.latitude, lng: pos.coords.longitude }); setLocStat("ok"); },
      ()  => { setLocStat("denied"); },
      { timeout: 10000, maximumAge: 5 * 60 * 1000 }
    );
  };

  const haversine = (a, b) => {
    if (!a || !b || a.lat == null || b.lat == null) return null;
    const R = 3959; // miles
    const toRad = d => d * Math.PI / 180;
    const dLat = toRad(b.lat - a.lat), dLng = toRad(b.lng - a.lng);
    const A = Math.sin(dLat/2)**2 +
              Math.cos(toRad(a.lat)) * Math.cos(toRad(b.lat)) *
              Math.sin(dLng/2)**2;
    return 2 * R * Math.asin(Math.sqrt(A));
  };

  const states = ["all", ...Array.from(new Set(sites.map(s => s.state).filter(Boolean))).sort()];

  const enriched = sites.map(s => ({
    ...s,
    _distance: userLoc && s.lat != null ? haversine(userLoc, s) : null,
  }));

  const filtered = enriched
    .filter(s => stateFilter === "all" || s.state === stateFilter)
    .sort((a, b) => {
      if (a._distance != null && b._distance != null) return a._distance - b._distance;
      if (a._distance != null) return -1;
      if (b._distance != null) return 1;
      return (a.state || "").localeCompare(b.state || "") || (a.site_name || "").localeCompare(b.site_name || "");
    });

  const visible = filtered.slice(0, 60);

  const statusOf = (s) => {
    if (s.status === "closed") return { label: "CLOSED", bg: "oklch(0.42 0.05 25)", fg: "#fff" };
    if (s.available == null)   return { label: "UNKNOWN", bg: "oklch(0.92 0.01 240)", fg: "var(--ink-soft)" };
    if (s.available === 0)     return { label: "FULL", bg: "oklch(0.50 0.22 25)", fg: "#fff" };
    if (s.available_pct != null && s.available_pct < 15) return { label: "ALMOST FULL", bg: "oklch(0.65 0.18 60)", fg: "#fff" };
    if (s.available_pct != null && s.available_pct < 35) return { label: "FILLING", bg: "oklch(0.78 0.14 90)", fg: "var(--ink)" };
    return { label: "OPEN", bg: "oklch(0.55 0.18 145)", fg: "#fff" };
  };

  return (
    <div className="tool-card">
      <div className="tool-h">
        <h2 className="tool-title">Parking near me</h2>
        <p className="tool-sub">
          Real-time available stalls at public rest areas in 8 MAASTO states
          (Iowa, Indiana, Kansas, Kentucky, Michigan, Minnesota, Ohio,
          Wisconsin) via the federal TPIMS feed. Free. No account.
        </p>
      </div>

      <div style={{ display: "flex", flexWrap: "wrap", gap: 12, alignItems: "center", padding: "16px 0" }}>
        {locStatus !== "ok" && (
          <button className="tool-btn-primary" onClick={requestLocation}
                  disabled={locStatus === "loading"}>
            {locStatus === "loading" ? "Requesting…" : "📍 Use my location"}
          </button>
        )}
        {locStatus === "ok" && (
          <span style={{ fontSize: 13, color: "var(--ink-soft)" }}>
            📍 Sorted by distance from your location
          </span>
        )}
        {locStatus === "denied" && (
          <span style={{ fontSize: 12, color: "oklch(0.55 0.16 25)" }}>
            Location denied — pick a state instead
          </span>
        )}
        {locStatus === "unsupported" && (
          <span style={{ fontSize: 12, color: "var(--ink-soft)" }}>
            Browser doesn't support geolocation
          </span>
        )}
        <select className="tool-select" value={stateFilter}
                onChange={e => setStateF(e.target.value)}
                style={{ marginLeft: "auto" }}>
          {states.map(s => <option key={s} value={s}>{s === "all" ? "All states" : s}</option>)}
        </select>
      </div>

      {loading ? (
        <div style={{ padding: 24, textAlign: "center", color: "var(--ink-soft)" }}>Loading rest areas…</div>
      ) : sites.length === 0 ? (
        <div style={{ padding: 24, textAlign: "center", color: "var(--ink-soft)", fontSize: 13 }}>
          No TPIMS data yet — daily ingest hasn't populated the table. Check back tomorrow.
        </div>
      ) : visible.length === 0 ? (
        <div style={{ padding: 24, textAlign: "center", color: "var(--ink-soft)" }}>
          No rest areas match this filter.
        </div>
      ) : (
        <div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
          {visible.map(s => {
            const st = statusOf(s);
            const updatedAgo = s.observed_at ? (() => {
              const t = new Date(s.observed_at).getTime();
              const min = Math.round((Date.now() - t) / 60000);
              if (min < 60) return `${min}m ago`;
              const hr = Math.round(min / 60);
              if (hr < 24) return `${hr}h ago`;
              return `${Math.round(hr / 24)}d ago`;
            })() : "";
            return (
              <div key={s.site_id}
                   style={{ display: "grid", gridTemplateColumns: "1fr 110px 90px", gap: 12,
                            alignItems: "center", padding: "10px 12px", border: "1px solid var(--rule)",
                            borderRadius: 6, background: "#fff" }}>
                <div>
                  <div style={{ fontFamily: "var(--font-serif)", fontSize: 16, color: "var(--ink)" }}>
                    {s.site_name}
                  </div>
                  <div style={{ fontFamily: "var(--font-mono)", fontSize: 11, color: "var(--ink-soft)" }}>
                    {[s.highway, s.direction, s.state].filter(Boolean).join(" · ")}
                    {s._distance != null && ` · ${s._distance.toFixed(1)} mi`}
                    {updatedAgo && ` · updated ${updatedAgo}`}
                  </div>
                </div>
                <div style={{ textAlign: "right", fontFamily: "var(--font-mono)", fontSize: 13 }}>
                  {s.available != null ? (
                    <>
                      <strong style={{ fontSize: 18 }}>{s.available}</strong>
                      {s.capacity ? <span style={{ color: "var(--ink-soft)" }}> / {s.capacity}</span> : null}
                      <div style={{ fontSize: 10, color: "var(--ink-soft)" }}>open stalls</div>
                    </>
                  ) : <span style={{ color: "var(--ink-soft)" }}>—</span>}
                </div>
                <div style={{ textAlign: "center" }}>
                  <span style={{ background: st.bg, color: st.fg, fontFamily: "var(--font-mono)",
                                 fontSize: 10, letterSpacing: "0.1em", padding: "4px 8px",
                                 borderRadius: 4, fontWeight: 700 }}>
                    {st.label}
                  </span>
                </div>
              </div>
            );
          })}
          {filtered.length > visible.length && (
            <div style={{ textAlign: "center", padding: 12, fontSize: 12, color: "var(--ink-soft)" }}>
              Showing nearest {visible.length} of {filtered.length} rest areas in this filter.
            </div>
          )}
        </div>
      )}
    </div>
  );
}

// =============================================================
// TOOLS PAGE — seven sections, sticky tab nav, auth-gated.
// =============================================================
function ToolsPage({ onNav }) {
  const [authedUser, setAuthedUser] = useStateTl(null);
  const [tab, setTab] = useStateTl("detention");
  useEffectTl(() => {
    let alive = true;
    if (window.SI_DB && window.SI_DB.auth && window.SI_DB.auth.getCurrentUser) {
      window.SI_DB.auth.getCurrentUser().then(u => { if (alive) setAuthedUser(u); }).catch(() => {});
    }
    return () => { alive = false; };
  }, []);
  const isAuthed = !!(authedUser && authedUser.email);

  return (
    <div className="tools-page">
      <style>{`
        .tools-page { background: var(--paper); padding-bottom: 96px; }
        .tools-hero {
          max-width: 1100px; margin: 0 auto; padding: 56px 24px 24px;
          border-bottom: 1px solid var(--rule);
        }
        .tools-back {
          display: inline-flex; align-items: center; gap: 6px;
          font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.16em;
          text-transform: uppercase; color: var(--ink-soft);
          background: transparent; border: 0; cursor: pointer;
          padding: 0 0 16px;
        }
        .tools-back:hover { color: var(--ink); }
        .tools-mark {
          font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.32em;
          text-transform: uppercase; color: var(--ink-soft); margin-bottom: 14px;
          display: inline-flex; align-items: center; gap: 10px;
        }
        .tools-mark .dot { display: inline-block; width: 8px; height: 8px;
          border-radius: 50%; background: oklch(0.55 0.18 145); }
        .tools-title {
          font-family: var(--font-serif); font-size: 48px; line-height: 1.05;
          letter-spacing: -0.025em; margin: 0 0 12px;
        }
        .tools-title em { font-style: italic; color: var(--red, oklch(0.50 0.16 250)); }
        .tools-sub {
          color: var(--ink-soft); font-size: 16px; line-height: 1.55; margin: 0;
          max-width: 720px;
        }
        @media (max-width: 700px) { .tools-title { font-size: 36px; } }

        .tools-icon-grid {
          max-width: 1100px; margin: 0 auto; padding: 32px 24px 8px;
          display: grid;
          grid-template-columns: repeat(4, 1fr);
          gap: 14px;
        }
        @media (max-width: 900px) { .tools-icon-grid { grid-template-columns: repeat(2, 1fr); } }
        @media (max-width: 520px) { .tools-icon-grid { grid-template-columns: 1fr 1fr; gap: 10px; } }
        .tig-card {
          background: #fff; border: 2px solid var(--rule); border-radius: 12px;
          padding: 22px 18px 18px; cursor: pointer;
          transition: border-color 0.13s, transform 0.13s, box-shadow 0.13s;
          display: flex; flex-direction: column; align-items: flex-start;
          text-align: left; font-family: inherit; color: inherit;
          position: relative; overflow: hidden;
        }
        .tig-card:hover { border-color: var(--ink); transform: translateY(-2px); box-shadow: 0 4px 16px rgba(0,0,0,0.08); }
        .tig-card.is-active { border-color: var(--ink); background: var(--paper); }
        .tig-card.is-active::after {
          content: ""; position: absolute; bottom: 0; left: 0; right: 0; height: 3px;
          background: var(--ink);
        }
        .tig-emoji { font-size: 36px; line-height: 1; margin-bottom: 12px; }
        .tig-name {
          font-family: var(--font-serif); font-size: 16px; font-weight: 700;
          letter-spacing: -0.01em; line-height: 1.2; margin: 0 0 6px;
        }
        .tig-desc {
          font-size: 12px; color: var(--ink-soft); line-height: 1.45; margin: 0;
        }

        .tools-body { max-width: 1100px; margin: 0 auto; padding: 0 24px; }

        .tool-card {
          background: #fff; border: 1px solid var(--rule); border-radius: 8px;
          padding: 32px; margin-bottom: 32px; position: relative; overflow: hidden;
        }
        .tool-card::before {
          content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 4px;
          background: var(--ink);
        }
        .tool-h { margin-bottom: 24px; padding-bottom: 20px; border-bottom: 1px solid var(--rule); }
        .tool-eyebrow {
          font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.18em;
          text-transform: uppercase; color: var(--ink-soft); margin-bottom: 8px;
        }
        .tool-title {
          font-family: var(--font-serif); font-size: 28px; letter-spacing: -0.02em;
          line-height: 1.15; margin: 0 0 8px;
        }
        .tool-sub { color: var(--ink-soft); font-size: 14px; line-height: 1.55; margin: 0; max-width: 720px; }

        .tool-form {
          display: grid; grid-template-columns: repeat(2, 1fr); gap: 14px 18px;
          margin-bottom: 24px;
        }
        .tool-form-pay { grid-template-columns: repeat(3, 1fr); }
        @media (max-width: 760px) { .tool-form, .tool-form-pay { grid-template-columns: 1fr; } }
        .tool-field { display: flex; flex-direction: column; gap: 6px; }
        .tool-field > span {
          font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.14em;
          text-transform: uppercase; color: var(--ink-soft);
        }
        .tool-field input[type=number],
        .tool-field input[type=text] {
          font-family: var(--font-sans); font-size: 16px;
          padding: 10px 12px; border: 1px solid var(--rule); border-radius: 6px;
          background: var(--paper); color: var(--ink); outline: none;
        }
        .tool-field input:focus { border-color: var(--ink); }
        .tool-field-radio span { margin-bottom: 4px; }
        .tool-radio-row {
          display: flex; gap: 12px; padding: 8px 0;
          font-size: 14px; color: var(--ink);
        }
        .tool-radio-row label { display: flex; align-items: center; gap: 6px; cursor: pointer; }

        .tool-out {
          display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px;
          margin-bottom: 16px;
        }
        @media (max-width: 880px) { .tool-out { grid-template-columns: repeat(2, 1fr); } }
        @media (max-width: 480px) { .tool-out { grid-template-columns: 1fr; } }
        .tool-out-tile {
          background: var(--paper-2); border: 1px solid var(--rule);
          border-radius: 6px; padding: 14px 16px;
        }
        .tool-out-tile.tone-warn {
          background: oklch(0.96 0.05 50); border-color: oklch(0.85 0.10 50);
        }
        .tool-out-tile.tone-crit {
          background: oklch(0.95 0.05 25); border-color: oklch(0.80 0.12 25);
        }
        .tool-out-tile.tone-ok {
          background: oklch(0.96 0.04 145); border-color: oklch(0.85 0.08 145);
        }
        .tool-out-l {
          font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.14em;
          text-transform: uppercase; color: var(--ink-soft);
        }
        .tool-out-n {
          font-family: var(--font-serif); font-size: 26px; letter-spacing: -0.02em;
          margin: 4px 0; line-height: 1.1; font-weight: 600;
        }
        .tool-out-s {
          font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.04em;
          color: var(--ink-soft);
        }
        .tool-foot {
          font-size: 12px; color: var(--ink-soft); line-height: 1.55;
          margin: 16px 0 0; font-style: italic;
        }

        .tool-detention .dt-running, .tool-detention .dt-idle { padding: 24px 0; text-align: center; }
        .dt-elapsed {
          font-family: var(--font-mono); font-size: 64px; letter-spacing: -0.02em;
          color: var(--red, oklch(0.50 0.16 250)); font-weight: 700;
          margin-bottom: 8px;
        }
        .dt-where {
          font-family: var(--font-serif); font-size: 18px;
          letter-spacing: -0.005em; color: var(--ink); margin-bottom: 4px;
        }
        .dt-since {
          font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.14em;
          text-transform: uppercase; color: var(--ink-soft); margin-bottom: 24px;
        }
        .dt-btn {
          font-family: inherit; font-size: 16px; padding: 16px 32px;
          border-radius: 8px; cursor: pointer; border: 1px solid var(--ink);
          background: var(--ink); color: #fff; font-weight: 600;
        }
        .dt-btn-stop {
          background: oklch(0.55 0.20 25); border-color: oklch(0.55 0.20 25);
        }
        .dt-btn:hover { opacity: 0.9; }
        .dt-logs {
          margin-top: 28px; padding-top: 24px; border-top: 1px solid var(--rule);
        }
        .dt-logs-h {
          font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.16em;
          text-transform: uppercase; color: var(--ink-soft);
          display: flex; justify-content: space-between; margin-bottom: 14px;
        }
        .dt-link {
          background: transparent; border: 0; cursor: pointer;
          font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.16em;
          text-transform: uppercase; color: var(--ink-soft); padding: 0;
          border-bottom: 1px dotted var(--ink-soft);
        }
        .dt-link:hover { color: var(--ink); }
        .dt-link-danger:hover { color: oklch(0.50 0.20 25); }
        .dt-link-sep { margin: 0 8px; opacity: 0.5; }
        .dt-list { list-style: none; padding: 0; margin: 0; }
        .dt-li {
          display: grid; grid-template-columns: 120px 1fr auto; gap: 16px;
          padding: 12px 0; border-top: 1px solid var(--rule); align-items: center;
        }
        .dt-li-dur {
          font-family: var(--font-serif); font-size: 18px;
          letter-spacing: -0.01em; font-weight: 600;
        }
        .dt-li-when {
          font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.04em;
          color: var(--ink-soft);
        }
        .dt-li-where {
          font-size: 13px; color: var(--ink); margin-top: 2px;
        }

        .tools-locked {
          max-width: 800px; margin: 64px auto; padding: 48px 24px; text-align: center;
        }
      `}</style>

      <section className="tools-hero">
        <button className="tools-back" onClick={() => onNav("drivers")}>← Back to The Yard</button>
        <div className="tools-mark"><span className="dot" /> Tools</div>
        <h1 className="tools-title">Every tool a driver <em>actually</em> needs.</h1>
        <p className="tools-sub">
          Free, client-side, no GPS pretensions. Pick a tool below and start.
        </p>
      </section>

      {!isAuthed ? (
        <div className="tools-locked">
          <h2 style={{ fontFamily: "var(--font-serif)", fontSize: 28, letterSpacing: "-0.02em", margin: "0 0 12px" }}>
            Sign in to The Yard first.
          </h2>
          <p style={{ color: "var(--ink-soft)", marginBottom: 20 }}>
            These tools live behind The Yard. One email, one click, you're in.
          </p>
          <button className="dt-btn" onClick={() => onNav("drivers")}>
            Go to The Yard →
          </button>
        </div>
      ) : (
        <>
          <div className="tools-icon-grid">
            {[
              { id: "detention", emoji: "⏰", name: "Detention Timer", desc: "Tap in, tap out. Auto-generates a dispute letter for your dispatcher." },
              { id: "hos",       emoji: "⏱", name: "HOS Clock",        desc: "Enter hours used. See drive time, 14-hr window, and break left." },
              { id: "pay",       emoji: "💵", name: "Pay Calculator",   desc: "What did the load actually pay per mile after fuel and fees?" },
              { id: "fsc",       emoji: "⛽", name: "Fuel Surcharge",   desc: "Calculate the exact fuel surcharge owed on any lane, any rate table." },
              { id: "cpm",       emoji: "🧾", name: "OO Breakeven",     desc: "Owner-op? Find the cost-per-mile floor before you say yes to a load." },
              { id: "reminders", emoji: "📅", name: "Renewals",         desc: "DOT medical card, CDL, insurance — never let a date sneak up on you." },
              { id: "parking",   emoji: "🅿️", name: "Parking Near Me", desc: "Truck stops and rest areas on your current route, mapped live." },
            ].map(t => (
              <button key={t.id} className={`tig-card${tab === t.id ? " is-active" : ""}`}
                      onClick={() => { setTab(t.id); document.querySelector(".tools-body")?.scrollIntoView({ behavior: "smooth", block: "start" }); }}>
                <div className="tig-emoji">{t.emoji}</div>
                <div className="tig-name">{t.name}</div>
                <p className="tig-desc">{t.desc}</p>
              </button>
            ))}
          </div>

          <div className="tools-body" style={{ marginTop: 32 }}>
            {tab === "detention" && <DetentionTimer />}
            {tab === "hos" && <HosClock />}
            {tab === "pay" && <PayCalc />}
            {tab === "fsc" && <FuelSurcharge />}
            {tab === "cpm" && <CpmCalc />}
            {tab === "reminders" && <Reminders />}
            {tab === "parking" && <Parking />}
          </div>
        </>
      )}
    </div>
  );
}

window.ToolsPage = ToolsPage;
