/* global React, ReactDOM, Icon, Button, Chip, ScreenHeader, Panel, SectionLabel, AgentNote, DocToolbar, Segmented, FitBadge, Provenance, TONES, CANDIDATE, SAVED_RESUMES, GENERATED_RESUMES, RESUME_STATUS, RESUME_DIFF */
const { useState: useRes } = React;

const TEMPLATES = [
  { key: "classic", name: "Classic", sub: "Serif headings, single column", accent: "#1F1B16", font: "var(--font-display)", cols: 1 },
  { key: "modern", name: "Modern", sub: "Sans, two-column sidebar", accent: "#4A5868", font: "var(--font-sans)", cols: 2 },
  { key: "technical", name: "Technical", sub: "Mono accents, dense", accent: "#5A7150", font: "var(--font-sans)", cols: 1 },
  { key: "executive", name: "Executive", sub: "Cardinal rule, roomy", accent: "#8C1515", font: "var(--font-display)", cols: 1 },
];

const RESUME = {
  summary: "Senior product manager with six years in payments and growth. I move one number at a time and ship the experiment that proves it.",
  experience: [
    { role: "Senior Product Manager, Growth", co: "Plaid", dates: "2021 — Present", bullets: [
      "Owned merchant checkout experimentation, shipping 40+ A/B tests that lifted conversion 18% across 2M monthly sessions.",
      "Built the experimentation platform adopted by 9 product teams.",
      "Partnered with 12 engineers to launch a redesigned card-entry flow, cutting drop-off 23% in one quarter.",
    ]},
    { role: "Product Manager", co: "Affirm", dates: "2018 — 2021", bullets: [
      "Launched split-pay checkout for 3 enterprise merchants, $40M GMV in year one.",
      "Ran the pricing experiment program; standardized how the team called a result.",
    ]},
  ],
  education: { school: "Carnegie Mellon University", degree: "M.S. Information Systems", year: "2020" },
  skills: ["Experimentation", "Payments", "PLG", "SQL", "Roadmapping", "A/B testing"],
};

// US-standard page presets. ratio = physical height / width.
const PAGE = {
  letter: { label: "Letter", ratio: 11 / 8.5, note: "8.5 \u00d7 11 in \u00b7 US standard" },
  a4:     { label: "A4",     ratio: 297 / 210, note: "210 \u00d7 297 mm \u00b7 international" },
};
// Spacing presets scale the document's vertical rhythm. The fit gauge measures the
// real rendered height, so spacing now visibly fills (or overflows) the fixed page.
const DENS = {
  compact:  { gap: 6,  lh: 1.3,  label: "Compact" },
  balanced: { gap: 13, lh: 1.5,  label: "Balanced" },
  roomy:    { gap: 26, lh: 1.9,  label: "Roomy" },
};
const DENS_ORDER = ["roomy", "balanced", "compact"];          // loosest -> tightest
const FILL_FACTOR = { compact: 0.82, balanced: 1, roomy: 1.28 };  // relative content height
const PAGE_W = 540, VPAD = 38, HPAD = 40;                     // page render width + margins (px)
const UPLOAD_FMT = {
  pdf:  { label: "PDF",  tone: "cardinal" },
  docx: { label: "DOCX", tone: "slate" },
  doc:  { label: "DOC",  tone: "slate" },
  tex:  { label: "TEX",  tone: "sage" },
};
// Fonts offered in the editor (saved with the template). System families + web-safe classics.
const DOC_FONTS = [
  { value: "default", label: "Template default" },
  { value: "var(--font-sans)", label: "Inter · sans" },
  { value: "var(--font-display)", label: "Fraunces · serif" },
  { value: "'Georgia', serif", label: "Georgia · serif" },
  { value: "'Times New Roman', Times, serif", label: "Times · serif" },
  { value: "Arial, Helvetica, sans-serif", label: "Arial · sans" },
  { value: "var(--font-mono)", label: "JetBrains · mono" },
];
const isSerifFont = (f) => /serif|display|fraunces|georgia|times/i.test(f || "");

// ---- Template customization (every option maps 1:1 to the LaTeX backend) ----
const DEFAULT_SECTIONS = [
  { key: "summary",    label: "Summary",    side: "main", on: true },
  { key: "experience", label: "Experience", side: "main", on: true },
  { key: "education",  label: "Education",  side: "side", on: true },
  { key: "skills",     label: "Skills",     side: "side", on: true },
];
const ACCENT_SWATCHES = [
  { value: null,      label: "Template" },
  { value: "#8C1515", label: "Cardinal" },
  { value: "#4A5868", label: "Slate" },
  { value: "#5A7150", label: "Sage" },
  { value: "#1F1B16", label: "Ink" },
];
const HEAD_STYLES = [
  { value: "rule",     label: "Underline", tex: "\\titlerule" },
  { value: "sideline", label: "Sideline",  tex: "\\rule[bar]" },
  { value: "plain",    label: "Plain",     tex: "\\textsc" },
];
const SKILL_STYLES = [
  { value: "tags",   label: "Tags" },
  { value: "inline", label: "Inline" },
  { value: "list",   label: "List" },
];
const MARGINS = {
  narrow: { label: "Narrow", h: 28, v: 28, tex: "0.5in" },
  normal: { label: "Normal", h: 40, v: 38, tex: "0.75in" },
  wide:   { label: "Wide",   h: 56, v: 50, tex: "1in" },
};
// Advanced (power-user) controls. Each maps to a LaTeX primitive.
const BULLETS = [
  { value: "disc",  label: "\u2022", tex: "\\textbullet" },
  { value: "dash",  label: "\u2013", tex: "--" },
  { value: "arrow", label: "\u25B8", tex: "$\\triangleright$" },
];
const DEFAULT_ADV = {
  lh: null,          // null = follow the Spacing preset; number = \linespread override
  bullet: "disc",    // \labelitemi
  nameSize: 25,      // pt, header name
  contact: "inline", // inline row vs stacked lines
  pageNums: false,   // \pagestyle{plain}
};

// Editable text lives in a model of HTML strings, so typed edits AND inline formatting
// (bold/italic/underline) survive re-renders and persist into the saved template.
function buildModel() {
  const m = {
    name: CANDIDATE.fullName,
    summary: RESUME.summary,
    eduDegree: RESUME.education.degree,
    eduSchool: `${RESUME.education.school} · ${RESUME.education.year}`,
  };
  RESUME.experience.forEach((e, i) => {
    m[`role_${i}`] = e.role;
    e.bullets.forEach((b, j) => { m[`bullet_${i}_${j}`] = b; });
  });
  RESUME.skills.forEach((s, i) => { m[`skill_${i}`] = s; });
  return m;
}
const DEFAULT_MODEL = buildModel();

function ScrResume() {
  const [tpl, setTpl] = useRes("executive");
  const [density, setDensity] = useRes("balanced");
  const [applied, setApplied] = useRes("balanced");   // effective spacing (auto-fit may tighten it)
  const [accentOn, setAccentOn] = useRes(true);
  const [pageSize, setPageSize] = useRes("letter");
  const [pageCount, setPageCount] = useRes(1);
  const [autoFit, setAutoFit] = useRes(false);
  const [custom, setCustom] = useRes(null);           // { name, format } uploaded template
  const [useCustom, setUseCustom] = useRes(false);    // is the uploaded template the active one
  const [fit, setFit] = useRes(null);                 // { contentH, innerH } measured from the doc
  const [tab, setTab] = useRes("editor");
  const [saved, setSaved] = useRes(false);
  const [editing, setEditing] = useRes(false);
  const [docFont, setDocFont] = useRes("default");   // font family override (saved in template)
  const [fontPt, setFontPt] = useRes(11);            // base type size in pt (saved in template)
  const [model, setModel] = useRes(buildModel);      // editable text + inline formatting (saved)
  const onEditField = (key, html) => setModel(prev => (prev[key] === html ? prev : { ...prev, [key]: html }));

  // Template customization (each option compiles to the .tex source)
  const [sections, setSections] = useRes(DEFAULT_SECTIONS);
  const [accentColor, setAccentColor] = useRes(null);      // null = template default
  const [headStyle, setHeadStyle] = useRes("rule");
  const [skillStyle, setSkillStyle] = useRes("tags");
  const [margin, setMargin] = useRes("normal");
  const [custOpen, setCustOpen] = useRes(false);      // customize overlay over the preview
  const [hoverSec, setHoverSec] = useRes(null);       // section row hovered → highlighted in the doc
  const [adv, setAdv] = useRes(DEFAULT_ADV);          // advanced (power-user) options
  const [showTex, setShowTex] = useRes(false);        // generated .tex source viewer
  const setAdvKey = (k, v) => setAdv(p => ({ ...p, [k]: v }));
  const toggleSection = (key) => setSections(prev => prev.map(s => s.key === key ? { ...s, on: !s.on } : s));
  const moveSection = (key, dir) => setSections(prev => {
    const i = prev.findIndex(s => s.key === key);
    const j = i + dir;
    if (j < 0 || j >= prev.length) return prev;
    const next = [...prev];
    [next[i], next[j]] = [next[j], next[i]];
    return next;
  });
  const design = { sections, accentColor, headStyle, skillStyle, margin, hoverSec, adv };

  const builtin = TEMPLATES.find(x => x.key === tpl);
  const isCustom = !!(custom && useCustom);
  const t = isCustom
    ? { key: "custom", name: custom.name, sub: "Your uploaded layout", accent: "#4A5868", font: "var(--font-sans)", cols: 1, custom: true, format: custom.format }
    : builtin;

  // The document reports its real measured height here (de-duped to avoid render loops).
  const handleFit = (contentH, innerH) => {
    setFit(prev => (prev && prev.contentH === contentH && prev.innerH === innerH) ? prev : { contentH, innerH });
  };

  // Resolve effective spacing. Manual = the chosen value; auto-fit picks the loosest
  // preset (never looser than the manual pick) that still fits the target page count.
  React.useEffect(() => {
    if (!autoFit) { setApplied(density); return; }
    if (!fit) return;
    const base = fit.contentH / FILL_FACTOR[applied];
    const target = fit.innerH * pageCount;
    const start = DENS_ORDER.indexOf(density);
    let app = "compact";
    for (let k = start; k < DENS_ORDER.length; k++) {
      if (base * FILL_FACTOR[DENS_ORDER[k]] <= target) { app = DENS_ORDER[k]; break; }
    }
    setApplied(app);
  }, [autoFit, density, pageCount, fit, applied]);

  return (
    <div style={{ maxWidth: 1140, margin: "0 auto", padding: "8px 0 40px" }}>
      <ScreenHeader
        eyebrow="Step 3 · Base résumé"
        title="Your base résumé, written by Offerroom"
        lede="Drawn from everything in your memory and grounded in résumé research. This is the master, every tailored version starts here."
        actions={<>
          <Button variant="secondary" size="sm" icon="download">Export PDF</Button>
          <Button variant="primary" size="sm" icon={saved ? "check" : "check"} onClick={() => setSaved(true)}>{saved ? "Base saved" : "Save base & template"}</Button>
        </>}
      />

      <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", gap: 12, marginBottom: 16 }}>
        <Segmented value={tab} onChange={setTab} options={[
          { value: "editor", label: "Base résumé" },
          { value: "library", label: `Saved & generated · ${GENERATED_RESUMES.length}` },
        ]}/>
        {tab === "library" && <Button variant="secondary" size="sm" icon="sparkles">Generate for a new job</Button>}
      </div>

      {tab === "library" ? <ResumeLibrary/> : (
      <>
      {saved && (
        <div className="cad-fade" style={{ marginBottom: 16 }}>
          <Panel pad={0} style={{ borderColor: "var(--sage-line)", background: "var(--sage-tint)" }}>
            <div style={{ display: "flex", alignItems: "center", gap: 12, padding: "12px 16px" }}>
              <span style={{ width: 30, height: 30, borderRadius: 999, background: "#5A7150", color: "#fff", display: "grid", placeItems: "center", flexShrink: 0 }}><Icon name="check" size={16}/></span>
              <div style={{ flex: 1, minWidth: 0 }}>
                <div style={{ fontSize: 13.5, fontWeight: 600, color: "var(--sage-text)" }}>Base résumé saved · {t.name} template</div>
                <div style={{ fontSize: 12, color: "var(--sage-text)", opacity: 0.85 }}>Template, fonts, type size and your edits are locked into the master. Every tailored version starts here.</div>
              </div>
              <Button variant="secondary" size="sm" icon="layers" onClick={() => setTab("library")}>View saved</Button>
            </div>
          </Panel>
        </div>
      )}

      <AgentNote time="just now" actions={<><Button variant={editing ? "primary" : "secondary"} size="sm" icon="edit" onClick={() => setEditing(e => !e)}>{editing ? "Done editing" : "Edit content"}</Button><Button variant="ghost" size="sm" icon="refresh">Regenerate a section</Button></>}>
        This is written from your work history and tuned against what hiring teams in payments actually read for. Pick a template and adjust the format until it feels like yours; your content stays intact.
      </AgentNote>

      <div style={{ display: "grid", gridTemplateColumns: "300px 1fr", gap: 16, marginTop: 16, alignItems: "start" }}>
        {/* Controls */}
        <div style={{ display: "flex", flexDirection: "column", gap: 16, position: "sticky", top: 0 }}>
          {/* 1 · Template */}
          <Panel pad={16}>
            <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 12 }}>
              <SectionLabel>Template</SectionLabel>
              <span style={{ fontSize: 10, letterSpacing: "0.06em", color: "var(--fg-3)", fontFamily: "var(--font-mono)" }}>{isCustom ? "CUSTOM" : "4 BUILT-IN"}</span>
            </div>
            <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 10 }}>
              {TEMPLATES.map(x => {
                const on = !isCustom && tpl === x.key;
                return (
                  <button key={x.key} onClick={() => { setTpl(x.key); setUseCustom(false); }} style={{
                    textAlign: "left", padding: 0, cursor: "pointer", borderRadius: 8, overflow: "hidden",
                    background: "#fff", fontFamily: "var(--font-sans)",
                    border: on ? "2px solid #8C1515" : "1px solid var(--ink-100)",
                    boxShadow: on ? "0 4px 12px rgba(140,21,21,0.10)" : "none", transition: "all 120ms",
                  }}>
                    <TemplateThumb t={x}/>
                    <div style={{ padding: "7px 9px 9px" }}>
                      <div style={{ fontSize: 12.5, fontWeight: 600 }}>{x.name}</div>
                      <div style={{ fontSize: 10.5, color: "var(--fg-2)", lineHeight: 1.3, marginTop: 1 }}>{x.sub}</div>
                    </div>
                  </button>
                );
              })}
            </div>

            {custom && (
              <div onClick={() => setUseCustom(true)} style={{ marginTop: 10, display: "flex", alignItems: "center", gap: 10, padding: "10px 11px", borderRadius: 8, cursor: "pointer",
                background: isCustom ? "rgba(140,21,21,0.05)" : "#fff",
                border: isCustom ? "2px solid #8C1515" : "1px solid var(--ink-100)" }}>
                <span style={{ width: 30, height: 38, borderRadius: 5, background: "#fff", border: "1px solid var(--ink-100)", display: "grid", placeItems: "center", color: "var(--fg-2)", flexShrink: 0 }}><Icon name="fileText" size={15}/></span>
                <div style={{ flex: 1, minWidth: 0 }}>
                  <div style={{ fontSize: 12.5, fontWeight: 600, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{custom.name}</div>
                  <div style={{ fontSize: 10.5, color: "var(--fg-2)", marginTop: 3, display: "inline-flex", alignItems: "center", gap: 6 }}>
                    <Chip tone={(UPLOAD_FMT[custom.format] || UPLOAD_FMT.pdf).tone} dot={false}>{(UPLOAD_FMT[custom.format] || UPLOAD_FMT.pdf).label}</Chip>
                    {isCustom ? "Active" : "Tap to use"}
                  </div>
                </div>
                <button onClick={(e) => { e.stopPropagation(); setCustom(null); setUseCustom(false); }} title="Remove"
                  style={{ width: 26, height: 26, borderRadius: 6, border: "1px solid var(--ink-100)", background: "#fff", cursor: "pointer", display: "grid", placeItems: "center", color: "var(--fg-2)", flexShrink: 0 }}><Icon name="trash" size={13}/></button>
              </div>
            )}

            <TemplateUpload onUpload={(name, format) => { setCustom({ name, format }); setUseCustom(true); }}/>
          </Panel>

          {/* 2 · Page */}
          <Panel pad={16}>
            <SectionLabel style={{ marginBottom: 12 }}>Page</SectionLabel>
            <div style={{ display: "flex", flexDirection: "column", gap: 12 }}>
              <CtrlRow label="Size">
                <Segmented value={pageSize} onChange={setPageSize} options={[{ value: "letter", label: "Letter" }, { value: "a4", label: "A4" }]}/>
              </CtrlRow>
              <CtrlRow label="Length">
                <Segmented value={pageCount} onChange={setPageCount} options={[{ value: 1, label: "1 page" }, { value: 2, label: "2 pages" }]}/>
              </CtrlRow>
              <div style={{ fontSize: 11.5, color: "var(--fg-2)", lineHeight: 1.5, paddingTop: 4, borderTop: "1px solid var(--ink-50)" }}>
                <Icon name="check" size={12} style={{ color: "#5A7150", verticalAlign: "-2px" }}/> {PAGE[pageSize].note}
              </div>
            </div>
          </Panel>

          {/* 3 · Fit & spacing */}
          <Panel pad={16}>
            <SectionLabel style={{ marginBottom: 12 }}>Fit &amp; spacing</SectionLabel>
            <PageFitGauge fit={fit} pageCount={pageCount} autoFit={autoFit}/>
            <div style={{ display: "flex", flexDirection: "column", gap: 14, marginTop: 14 }}>
              <div style={{ opacity: autoFit ? 0.5 : 1, pointerEvents: autoFit ? "none" : "auto" }}>
                <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 7 }}>
                  <span style={{ fontSize: 12, color: "var(--fg-2)" }}>Spacing</span>
                  {autoFit && <span style={{ fontSize: 10, fontFamily: "var(--font-mono)", letterSpacing: "0.04em", color: "var(--cardinal)" }}>AUTO · {DENS[applied].label.toUpperCase()}</span>}
                </div>
                <Segmented value={density} onChange={setDensity} options={[{ value: "compact", label: "Compact" }, { value: "balanced", label: "Balanced" }, { value: "roomy", label: "Roomy" }]}/>
              </div>
              <ToggleRow
                label={`Auto-fit to ${pageCount} page${pageCount > 1 ? "s" : ""}`}
                sub="Offerroom tightens spacing so it never spills."
                on={autoFit} onClick={() => setAutoFit(v => !v)}/>
              <ToggleRow label="Colored accent rule" on={accentOn} onClick={() => setAccentOn(v => !v)}/>
            </div>
          </Panel>

        </div>

        {/* Preview */}
        <Panel pad={0}>
          <DocToolbar
            left={<><Icon name="fileText" size={15} style={{ color: "var(--fg-2)" }}/><span style={{ fontSize: 13, fontWeight: 500 }}>{CANDIDATE.fullName} — base résumé</span><Chip tone="info" dot={false}>{isCustom ? custom.name : `${t.name}.tex`}</Chip>{editing && <span style={{ fontSize: 11.5, color: "var(--cardinal)", display: "inline-flex", alignItems: "center", gap: 5 }}><Icon name="edit" size={11}/>Editing · click any text</span>}</>}
            right={<><span style={{ fontSize: 11, color: "var(--fg-2)", fontFamily: "var(--font-mono)", letterSpacing: "0.02em" }}>{PAGE[pageSize].label} · {pageCount}p</span><Button variant={custOpen ? "primary" : "secondary"} size="sm" icon="layers" onClick={() => setCustOpen(v => !v)}>{custOpen ? "Done" : "Customize"}</Button><Button variant={editing ? "primary" : "ghost"} size="sm" icon="edit" onClick={() => setEditing(e => !e)}>{editing ? "Done" : "Edit"}</Button><Button variant="ghost" size="sm" icon="download">PDF</Button></>}/>
          {isCustom && (
            <div style={{ display: "flex", alignItems: "center", gap: 9, padding: "9px 16px", background: "var(--slate-tint)", borderBottom: "1px solid var(--ink-50)" }}>
              <Icon name="upload" size={14} style={{ color: "var(--slate-text)", flexShrink: 0 }}/>
              <span style={{ fontSize: 12, color: "var(--slate-text)" }}>Your content, flowed into <b style={{ fontWeight: 600 }}>{custom.name}</b>. Offerroom maps each section into your layout.</span>
            </div>
          )}
          {editing && <FormatBar docFont={docFont} setDocFont={setDocFont} fontPt={fontPt} setFontPt={setFontPt}/>}
          <div style={{ position: "relative", background: "var(--paper-sunken)", padding: 24, paddingRight: custOpen ? 336 : 24, display: "grid", placeItems: "start center", transition: "padding 240ms cubic-bezier(0.2,0.7,0.1,1)" }}>
            {/* The doc zooms out while customizing so both stay fully visible */}
            <div style={{ zoom: custOpen ? 0.78 : 1, transition: "zoom 240ms" }}>
              <ResumeDoc t={t} density={applied} accentOn={accentOn} editing={editing} pageSize={pageSize} pageCount={pageCount} onFit={handleFit} docFont={docFont} fontPt={fontPt} model={model} onEdit={onEditField} design={design}/>
            </div>
            {custOpen && (
              <CustomizePanel
                sections={sections} moveSection={moveSection} toggleSection={toggleSection}
                accentColor={accentColor} setAccentColor={setAccentColor} builtin={builtin}
                headStyle={headStyle} setHeadStyle={setHeadStyle}
                skillStyle={skillStyle} setSkillStyle={setSkillStyle}
                margin={margin} setMargin={setMargin}
                onHoverSec={setHoverSec} onClose={() => { setCustOpen(false); setHoverSec(null); }}
                adv={adv} setAdvKey={setAdvKey} onViewTex={() => setShowTex(true)}/>
            )}
          </div>
          {showTex && <TexSourceModal design={design} t={t} pageSize={pageSize} fontPt={fontPt} density={applied} onClose={() => setShowTex(false)}/>}
        </Panel>
      </div>
      </>
      )}
    </div>
  );
}

// ============================================================
// Customize overlay — floats over the preview; every control maps
// to the LaTeX backend. Hovering a section row highlights it in the doc.
// ============================================================
function CustomizePanel({ sections, moveSection, toggleSection, accentColor, setAccentColor, builtin, headStyle, setHeadStyle, skillStyle, setSkillStyle, margin, setMargin, onHoverSec, onClose, adv, setAdvKey, onViewTex }) {
  const [advOpen, setAdvOpen] = React.useState(false);
  const ArrowBtn = ({ dir, disabled, onClick }) => (
    <button onClick={onClick} disabled={disabled} title={dir < 0 ? "Move up" : "Move down"}
      style={{ width: 22, height: 22, borderRadius: 5, border: "1px solid var(--ink-100)", background: "#fff", cursor: disabled ? "default" : "pointer", color: disabled ? "var(--ink-100)" : "var(--fg-2)", fontSize: 11, lineHeight: 1, display: "grid", placeItems: "center", padding: 0, flexShrink: 0 }}>{dir < 0 ? "\u2191" : "\u2193"}</button>
  );
  return (
    <div className="cad-slide-in" style={{ position: "absolute", top: 16, right: 16, bottom: 16, width: 296, display: "flex", flexDirection: "column", background: "#fff", border: "1px solid var(--ink-100)", borderRadius: 12, boxShadow: "0 20px 48px rgba(31,27,22,0.18)", overflow: "hidden", zIndex: 5 }}>
      <div style={{ display: "flex", alignItems: "center", gap: 10, padding: "13px 16px", borderBottom: "1px solid var(--ink-50)", flexShrink: 0 }}>
        <SectionLabel>Customize template</SectionLabel>
        <span style={{ fontSize: 10, letterSpacing: "0.06em", color: "var(--fg-3)", fontFamily: "var(--font-mono)", flex: 1 }}>.TEX</span>
        <button onClick={onClose} title="Close" style={{ width: 26, height: 26, borderRadius: 6, border: "1px solid var(--ink-100)", background: "#fff", cursor: "pointer", display: "grid", placeItems: "center", color: "var(--fg-2)", padding: 0 }}><Icon name="close" size={13}/></button>
      </div>

      <div style={{ flex: 1, overflow: "auto", padding: 16, display: "flex", flexDirection: "column", gap: 14 }}>
        <div>
          <div style={{ fontSize: 12, color: "var(--fg-2)", marginBottom: 7 }}>Sections · hover to preview, drag order with arrows</div>
          <div style={{ border: "1px solid var(--ink-100)", borderRadius: 8, overflow: "hidden" }} onMouseLeave={() => onHoverSec(null)}>
            {sections.map((s, i) => (
              <div key={s.key} onMouseEnter={() => onHoverSec(s.on ? s.key : null)}
                style={{ display: "flex", alignItems: "center", gap: 7, padding: "7px 10px", background: s.on ? "#fff" : "var(--paper-sunken)", borderBottom: i < sections.length - 1 ? "1px solid var(--ink-50)" : "none", cursor: "default" }}>
                <span style={{ fontSize: 12.5, fontWeight: 500, flex: 1, color: s.on ? "var(--fg-1)" : "var(--fg-3)", textDecoration: s.on ? "none" : "line-through" }}>{s.label}</span>
                {s.side === "side" && <span title="Renders in the sidebar on two-column templates" style={{ fontSize: 9, fontFamily: "var(--font-mono)", letterSpacing: "0.05em", color: "var(--fg-3)" }}>SIDE</span>}
                <ArrowBtn dir={-1} disabled={i === 0} onClick={() => moveSection(s.key, -1)}/>
                <ArrowBtn dir={1} disabled={i === sections.length - 1} onClick={() => moveSection(s.key, 1)}/>
                <button onClick={() => toggleSection(s.key)} title={s.on ? "Hide section" : "Show section"} style={{ width: 22, height: 22, borderRadius: 5, border: "1px solid var(--ink-100)", background: s.on ? "var(--cardinal-50)" : "#fff", color: s.on ? "var(--cardinal)" : "var(--fg-3)", cursor: "pointer", display: "grid", placeItems: "center", padding: 0, flexShrink: 0 }}><Icon name="eye" size={12}/></button>
              </div>
            ))}
          </div>
        </div>

        <div>
          <div style={{ fontSize: 12, color: "var(--fg-2)", marginBottom: 7 }}>Accent color</div>
          <div style={{ display: "flex", gap: 7 }}>
            {ACCENT_SWATCHES.map(a => {
              const on = accentColor === a.value;
              const chip = a.value || builtin.accent;
              return (
                <button key={a.label} onClick={() => setAccentColor(a.value)} title={a.label}
                  style={{ width: 26, height: 26, borderRadius: 999, cursor: "pointer", padding: 0, position: "relative",
                    background: a.value ? chip : "#fff",
                    border: on ? "2px solid var(--cardinal)" : "1px solid var(--ink-100)",
                    boxShadow: on ? "0 0 0 2px #fff inset" : "none" }}>
                  {!a.value && <span style={{ position: "absolute", inset: 5, borderRadius: 999, background: `conic-gradient(${chip} 0 50%, var(--ink-100) 50% 100%)` }}/>}
                </button>
              );
            })}
          </div>
        </div>

        <div>
          <div style={{ fontSize: 12, color: "var(--fg-2)", marginBottom: 7 }}>Headings</div>
          <Segmented value={headStyle} onChange={setHeadStyle} options={HEAD_STYLES.map(h => ({ value: h.value, label: h.label }))}/>
        </div>
        <div>
          <div style={{ fontSize: 12, color: "var(--fg-2)", marginBottom: 7 }}>Skills as</div>
          <Segmented value={skillStyle} onChange={setSkillStyle} options={SKILL_STYLES}/>
        </div>
        <div>
          <div style={{ fontSize: 12, color: "var(--fg-2)", marginBottom: 7 }}>Margins</div>
          <Segmented value={margin} onChange={setMargin} options={Object.keys(MARGINS).map(k => ({ value: k, label: MARGINS[k].label }))}/>
        </div>

        {/* Advanced — collapsed by default; every control is a LaTeX primitive */}
        <div style={{ border: "1px solid var(--ink-100)", borderRadius: 8, overflow: "hidden" }}>
          <button onClick={() => setAdvOpen(v => !v)} style={{ width: "100%", display: "flex", alignItems: "center", gap: 8, padding: "10px 12px", border: "none", background: advOpen ? "var(--paper)" : "#fff", cursor: "pointer", fontFamily: "var(--font-sans)", textAlign: "left" }}>
            <span style={{ fontSize: 12.5, fontWeight: 600, color: "var(--fg-1)", flex: 1 }}>Advanced</span>
            <span style={{ fontSize: 9.5, fontFamily: "var(--font-mono)", letterSpacing: "0.05em", color: "var(--fg-3)" }}>POWER USER</span>
            <span style={{ fontSize: 11, color: "var(--fg-2)", transform: advOpen ? "rotate(180deg)" : "none", transition: "transform 160ms", display: "inline-block" }}>{"\u25BE"}</span>
          </button>
          {advOpen && (
            <div className="cad-fade" style={{ padding: 12, borderTop: "1px solid var(--ink-50)", display: "flex", flexDirection: "column", gap: 13 }}>
              {/* Line height override */}
              <div>
                <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 6 }}>
                  <span style={{ fontSize: 12, color: "var(--fg-2)" }}>Line height</span>
                  <span style={{ fontSize: 10.5, fontFamily: "var(--font-mono)", color: adv.lh ? "var(--cardinal)" : "var(--fg-3)" }}>{adv.lh ? adv.lh.toFixed(2) : "FROM SPACING"}</span>
                </div>
                <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
                  <input type="range" min="1.15" max="1.9" step="0.05" value={adv.lh || 1.5} onChange={e => setAdvKey("lh", parseFloat(e.target.value))} style={{ flex: 1, accentColor: "#8C1515" }}/>
                  {adv.lh && <button onClick={() => setAdvKey("lh", null)} title="Reset to spacing preset" style={{ height: 22, padding: "0 8px", borderRadius: 5, border: "1px solid var(--ink-100)", background: "#fff", cursor: "pointer", fontSize: 10.5, color: "var(--fg-2)", fontFamily: "var(--font-sans)" }}>Reset</button>}
                </div>
              </div>
              {/* Bullet marker */}
              <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", gap: 10 }}>
                <span style={{ fontSize: 12, color: "var(--fg-2)" }}>Bullet marker</span>
                <div style={{ display: "flex", gap: 5 }}>
                  {BULLETS.map(b => {
                    const on = adv.bullet === b.value;
                    return <button key={b.value} onClick={() => setAdvKey("bullet", b.value)} title={b.tex}
                      style={{ width: 28, height: 26, borderRadius: 6, cursor: "pointer", fontSize: 13, lineHeight: 1, display: "grid", placeItems: "center", padding: 0,
                        border: on ? "1px solid rgba(140,21,21,0.3)" : "1px solid var(--ink-100)",
                        background: on ? "var(--cardinal-50)" : "#fff", color: on ? "var(--cardinal)" : "var(--fg-1)" }}>{b.label}</button>;
                  })}
                </div>
              </div>
              {/* Name size */}
              <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", gap: 10 }}>
                <span style={{ fontSize: 12, color: "var(--fg-2)" }}>Name size</span>
                <div style={{ display: "flex", alignItems: "center", border: "1px solid var(--ink-100)", borderRadius: 6, overflow: "hidden", height: 26 }}>
                  <button onClick={() => setAdvKey("nameSize", Math.max(20, adv.nameSize - 1))} style={{ width: 24, height: 24, border: "none", background: "transparent", cursor: "pointer", color: "var(--fg-1)", fontSize: 14, lineHeight: 1, padding: 0 }}>{"\u2212"}</button>
                  <span style={{ minWidth: 42, textAlign: "center", fontSize: 11.5, fontVariantNumeric: "tabular-nums" }}>{adv.nameSize} pt</span>
                  <button onClick={() => setAdvKey("nameSize", Math.min(32, adv.nameSize + 1))} style={{ width: 24, height: 24, border: "none", background: "transparent", cursor: "pointer", color: "var(--fg-1)", fontSize: 14, lineHeight: 1, padding: 0 }}>+</button>
                </div>
              </div>
              {/* Contact layout */}
              <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", gap: 10 }}>
                <span style={{ fontSize: 12, color: "var(--fg-2)" }}>Contact</span>
                <Segmented value={adv.contact} onChange={v => setAdvKey("contact", v)} options={[{ value: "inline", label: "Inline" }, { value: "stacked", label: "Stacked" }]}/>
              </div>
              {/* Page numbers */}
              <ToggleRow label="Page numbers" on={adv.pageNums} onClick={() => setAdvKey("pageNums", !adv.pageNums)}/>
            </div>
          )}
        </div>
      </div>

      <div style={{ padding: "11px 16px", borderTop: "1px solid var(--ink-50)", background: "var(--paper)", flexShrink: 0 }}>
        <div style={{ fontSize: 10.5, color: "var(--fg-2)", lineHeight: 1.5, fontFamily: "var(--font-mono)", letterSpacing: "0.01em" }}>
          sections {"\u2192"} \section {"\u00b7"} margins {"\u2192"} geometry {MARGINS[margin].tex} {"\u00b7"} headings {"\u2192"} {HEAD_STYLES.find(h => h.value === headStyle).tex}
        </div>
        <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", gap: 8, marginTop: 8 }}>
          <span style={{ fontSize: 11, color: "var(--fg-2)" }}>
            <Icon name="check" size={12} style={{ color: "#5A7150", verticalAlign: "-2px" }}/> Applied live · ATS-safe
          </span>
          <Button variant="secondary" size="sm" icon="fileText" onClick={onViewTex}>View .tex</Button>
        </div>
      </div>
    </div>
  );
}

const TemplateThumb = ({ t }) => (
  <div style={{ height: 76, background: "#fff", borderBottom: "1px solid var(--ink-50)", padding: 9, display: "flex", flexDirection: "column", gap: 4 }}>
    {t.accent !== "#1F1B16" && <span style={{ height: 3, width: "40%", background: t.accent, borderRadius: 2 }}/>}
    <span style={{ height: 5, width: "55%", background: "var(--ink-300)", borderRadius: 2 }}/>
    {t.cols === 2 ? (
      <div style={{ display: "flex", gap: 6, flex: 1, marginTop: 2 }}>
        <div style={{ width: "32%", background: t.accent + "22", borderRadius: 2 }}/>
        <div style={{ flex: 1, display: "flex", flexDirection: "column", gap: 3 }}>
          {[1,1,1].map((_,i)=><span key={i} style={{ height: 2.5, background: "var(--ink-100)", borderRadius: 2 }}/>)}
        </div>
      </div>
    ) : (
      <div style={{ display: "flex", flexDirection: "column", gap: 3, marginTop: 2 }}>
        {[1,1,1,1].map((_,i)=><span key={i} style={{ height: 2.5, width: (90 - i*8) + "%", background: "var(--ink-100)", borderRadius: 2 }}/>)}
      </div>
    )}
  </div>
);

const Toggle = ({ on, onClick }) => (
  <button onClick={onClick} style={{ width: 38, height: 22, borderRadius: 999, border: "none", cursor: "pointer", padding: 2,
    background: on ? "#8C1515" : "var(--ink-100)", transition: "background 160ms", display: "flex", justifyContent: on ? "flex-end" : "flex-start" }}>
    <span style={{ width: 18, height: 18, borderRadius: 999, background: "#fff", boxShadow: "0 1px 2px rgba(0,0,0,0.2)", transition: "all 160ms" }}/>
  </button>
);

function ResumeDoc({ t, density, accentOn, tailored, editing, pageSize = "letter", pageCount = 1, onFit, docFont = "default", fontPt = 11, model, onEdit, design }) {
  const d = DENS[density] || DENS.balanced;
  const dz = design || {};
  const adv = dz.adv || DEFAULT_ADV;
  const gap = d.gap, lh = adv.lh || d.lh;
  const secList = dz.sections || DEFAULT_SECTIONS;
  const headStyle = dz.headStyle || "rule";
  const skillStyle = dz.skillStyle || "tags";
  const mg = MARGINS[dz.margin] || MARGINS.normal;
  const vpad = mg.v, hpad = mg.h;
  const accent = accentOn ? (dz.accentColor || t.accent) : "#1F1B16";
  const bulletCss = { disc: "disc", dash: '"\u2013\u2002"', arrow: '"\u25B8\u2002"' }[adv.bullet] || "disc";
  const ratio = (PAGE[pageSize] || PAGE.letter).ratio;
  const onePageH = Math.round(PAGE_W * ratio);
  const innerH = onePageH - 2 * vpad;
  const m = model || DEFAULT_MODEL;

  // Typography saved in the template: font family override + base size scale.
  const useFont = docFont && docFont !== "default";
  const headFont = useFont ? docFont : t.font;
  const bodyFont = useFont ? docFont : "var(--font-sans)";
  const sans = !isSerifFont(headFont);
  const scale = fontPt / 11;
  const z = (n) => Math.round(n * scale * 10) / 10;

  // Measure the real rendered content height so the page-fit gauge tells the truth.
  const contentRef = React.useRef(null);
  const reported = React.useRef("");
  const [contentH, setContentH] = React.useState(0);
  React.useLayoutEffect(() => {
    const el = contentRef.current;
    if (!el) return;
    const h = el.scrollHeight;
    const key = h + "@" + innerH;
    if (key !== reported.current) {
      reported.current = key;
      setContentH(h);
      onFit && onFit(h, innerH);
    }
  });
  const used = contentH ? Math.max(1, Math.ceil(contentH / innerH)) : 1;
  const sheets = Math.max(pageCount, used);
  const sheetH = sheets * onePageH;

  // Bullets Offerroom rewrote for the target role (mirrors RESUME_DIFF: Plaid bullets 0 & 2).
  const isTailoredBullet = (i, j) => tailored && i === 0 && (j === 0 || j === 2);
  // Editable text lives in the model (HTML), so edits + inline formatting persist.
  const edStyle = editing ? { outline: "1px dashed rgba(140,21,21,0.35)", outlineOffset: 2, borderRadius: 2, cursor: "text" } : null;
  const F = (key, tag, baseStyle, extra) => React.createElement(tag, {
    ...(editing ? { contentEditable: true, suppressContentEditableWarning: true, onBlur: (e) => onEdit && onEdit(key, e.currentTarget.innerHTML) } : {}),
    style: { ...baseStyle, ...(editing ? edStyle : null) },
    dangerouslySetInnerHTML: { __html: m[key] != null ? m[key] : "" },
    ...(extra || {}),
  });
  return (
    <div style={{ position: "relative", width: PAGE_W, minHeight: sheetH, background: "#fff", boxShadow: "0 8px 24px rgba(31,27,22,0.10)", boxSizing: "border-box", padding: `${vpad}px ${hpad}px`, fontFamily: bodyFont }}>
        {/* region beyond the target page count, flagged in the gauge's ochre */}
        {used > pageCount && (
          <div style={{ position: "absolute", left: 0, right: 0, top: pageCount * onePageH, bottom: 0, background: "rgba(176,138,62,0.07)", pointerEvents: "none" }}/>
        )}
        {/* page-break guides */}
        {Array.from({ length: sheets - 1 }).map((_, i) => {
          const beyond = (i + 1) >= pageCount;
          return (
            <div key={i} style={{ position: "absolute", left: 0, right: 0, top: (i + 1) * onePageH, pointerEvents: "none" }}>
              <div style={{ borderTop: `1px dashed ${beyond ? "rgba(176,138,62,0.6)" : "rgba(31,27,22,0.16)"}` }}/>
              <span style={{ position: "absolute", right: 10, top: 3, fontSize: 8.5, fontFamily: "var(--font-mono)", letterSpacing: "0.06em", color: beyond ? "#6E5419" : "var(--fg-3)", background: "#fff", padding: "0 5px" }}>PAGE {i + 2}</span>
            </div>
          );
        })}
        <span style={{ position: "absolute", right: 10, top: 9, fontSize: 8.5, fontFamily: "var(--font-mono)", letterSpacing: "0.06em", color: "var(--fg-3)" }}>PAGE 1</span>
        {/* \pagestyle{plain}: folio centered at each page foot */}
        {adv.pageNums && Array.from({ length: sheets }).map((_, i) => (
          <span key={i} style={{ position: "absolute", left: 0, right: 0, top: (i + 1) * onePageH - 22, textAlign: "center", fontSize: z(9.5), color: "var(--fg-2)", fontVariantNumeric: "tabular-nums", pointerEvents: "none" }}>{i + 1}</span>
        ))}

        <div ref={contentRef}>
          <div style={{ borderBottom: accentOn ? `2px solid ${accent}` : "1px solid var(--ink-100)", paddingBottom: 12 }}>
            {F("name", "div", { fontFamily: headFont, fontSize: z(adv.nameSize), fontWeight: sans ? 700 : 500, letterSpacing: "-0.01em", color: "#1F1B16" })}
            {adv.contact === "stacked" ? (
              <div style={{ fontSize: z(11.5), color: "var(--fg-2)", marginTop: 4, display: "flex", flexDirection: "column", gap: 2 }}>
                <span>{CANDIDATE.email}</span><span>{CANDIDATE.location}</span><span>{CANDIDATE.linkedin}</span>
              </div>
            ) : (
              <div style={{ fontSize: z(11.5), color: "var(--fg-2)", marginTop: 4, display: "flex", gap: 12, flexWrap: "wrap" }}>
                <span>{CANDIDATE.email}</span><span>·</span><span>{CANDIDATE.location}</span><span>·</span><span>{CANDIDATE.linkedin}</span>
              </div>
            )}
          </div>

          {(() => {
            const sp = (key) => ({ accent, font: headFont, sans, scale, headStyle, hl: dz.hoverSec === key });
            const bodies = {
              summary: (
                <DocSection key="summary" title="Summary" {...sp("summary")}>
                  {F("summary", "p", { margin: 0, fontSize: z(11.5), lineHeight: lh, color: "var(--ink-700)" })}
                </DocSection>
              ),
              experience: (
                <DocSection key="experience" title="Experience" {...sp("experience")}>
                  {RESUME.experience.map((e, i) => (
                    <div key={i} style={{ marginBottom: i < RESUME.experience.length - 1 ? gap : 0 }}>
                      <div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline" }}>
                        {F(`role_${i}`, "span", { fontSize: z(12), fontWeight: 600, color: "#1F1B16" })}
                        <span style={{ fontSize: z(10.5), color: "var(--fg-2)", fontFamily: "var(--font-mono)" }}>{e.dates}</span>
                      </div>
                      <div style={{ fontSize: z(11), color: accent, fontWeight: 500, marginBottom: 4 }}>{e.co}</div>
                      <ul style={{ margin: 0, paddingLeft: 15, fontSize: z(11), lineHeight: lh, color: "var(--ink-700)", listStyleType: bulletCss }}>
                        {e.bullets.map((b, j) => {
                          const tw = isTailoredBullet(i, j);
                          return F(`bullet_${i}_${j}`, "li", { marginBottom: 2, background: tw ? "rgba(74,88,104,0.10)" : "transparent", borderRadius: tw ? 3 : 0, boxDecorationBreak: "clone", WebkitBoxDecorationBreak: "clone", padding: tw ? "0 3px" : 0 }, { key: j });
                        })}
                      </ul>
                    </div>
                  ))}
                </DocSection>
              ),
              education: (
                <DocSection key="education" title="Education" {...sp("education")}>
                  {F("eduDegree", "div", { fontSize: z(11.5), fontWeight: 600 })}
                  {F("eduSchool", "div", { fontSize: z(11), color: "var(--fg-2)" })}
                </DocSection>
              ),
              skills: (
                <DocSection key="skills" title="Skills" {...sp("skills")}>
                  {skillStyle === "tags" && (
                    <div style={{ display: "flex", flexWrap: "wrap", gap: 5 }}>
                      {RESUME.skills.map((s, i) => (
                        F(`skill_${i}`, "span", { fontSize: z(10), padding: "2px 7px", borderRadius: 4, background: t.cols === 2 ? "transparent" : "var(--paper-sunken)",
                          border: t.cols === 2 ? `1px solid ${accent}40` : "none", color: "var(--ink-700)", fontFamily: "var(--font-mono)" }, { key: i })
                      ))}
                    </div>
                  )}
                  {skillStyle === "inline" && (
                    <p style={{ margin: 0, fontSize: z(11), lineHeight: lh, color: "var(--ink-700)" }}>
                      {RESUME.skills.map((s, i) => (
                        <React.Fragment key={i}>
                          {F(`skill_${i}`, "span", {})}
                          {i < RESUME.skills.length - 1 && <span style={{ color: "var(--fg-3)" }}> · </span>}
                        </React.Fragment>
                      ))}
                    </p>
                  )}
                  {skillStyle === "list" && (
                    <ul style={{ margin: 0, paddingLeft: 15, fontSize: z(11), lineHeight: lh, color: "var(--ink-700)", columns: t.cols === 2 ? 1 : 2 }}>
                      {RESUME.skills.map((s, i) => F(`skill_${i}`, "li", { marginBottom: 2, breakInside: "avoid" }, { key: i }))}
                    </ul>
                  )}
                </DocSection>
              ),
            };
            const active = secList.filter(s => s.on);
            if (t.cols !== 2) {
              return <div style={{ marginTop: gap + 2 }}>{active.map(s => bodies[s.key])}</div>;
            }
            const main = active.filter(s => s.side !== "side").map(s => bodies[s.key]);
            const side = active.filter(s => s.side === "side").map(s => bodies[s.key]);
            return (
              <div style={{ display: "grid", gridTemplateColumns: "1.6fr 1fr", gap: 22, marginTop: gap + 2 }}>
                <div>{main}</div>
                <div><div style={{ height: gap }}/>{side}</div>
              </div>
            );
          })()}
        </div>
    </div>
  );
}

const DocSection = ({ title, accent, font, sans = true, scale = 1, headStyle = "rule", hl = false, children }) => (
  <section style={{ marginBottom: 16, borderRadius: 4, boxShadow: hl ? "0 0 0 3px rgba(140,21,21,0.28)" : "none", background: hl ? "rgba(140,21,21,0.03)" : "transparent", transition: "box-shadow 160ms, background 160ms" }}>
    <div style={{ fontFamily: font, fontSize: Math.round(11 * scale * 10) / 10, fontWeight: 600, letterSpacing: sans ? "0.08em" : "0", textTransform: sans ? "uppercase" : "none", color: accent, marginBottom: 7,
      borderBottom: headStyle === "rule" ? "1px solid var(--ink-50)" : "none",
      borderLeft: headStyle === "sideline" ? `3px solid ${accent}` : "none",
      paddingLeft: headStyle === "sideline" ? 8 : 0,
      paddingBottom: headStyle === "rule" ? 4 : 0 }}>{title}</div>
    {children}
  </section>
);

// ============================================================
// Saved & generated résumé library — the returning-user view.
// ============================================================
function ResumeLibrary() {
  const [q, setQ] = useRes("");
  const [status, setStatus] = useRes("all");
  const [sort, setSort] = useRes("recent");
  const [modal, setModal] = useRes(null); // { kind: "view" | "diff", r }

  const counts = GENERATED_RESUMES.reduce((m, r) => (m[r.status] = (m[r.status] || 0) + 1, m), {});
  const filters = [
    { key: "all", label: "All", n: GENERATED_RESUMES.length },
    { key: "submitted", label: "Submitted", n: counts.submitted || 0 },
    { key: "draft", label: "Drafts", n: counts.draft || 0 },
    { key: "saved", label: "Saved", n: counts.saved || 0 },
  ];
  let list = GENERATED_RESUMES.filter(r =>
    (status === "all" || r.status === status) &&
    (q.trim() === "" || `${r.co} ${r.job}`.toLowerCase().includes(q.trim().toLowerCase())));
  if (sort === "fit") list = [...list].sort((a, b) => b.fit - a.fit);

  return (
    <div className="cad-fade" style={{ display: "flex", flexDirection: "column", gap: 22 }}>
      {/* Saved base résumés */}
      <section>
        <div style={{ display: "flex", alignItems: "baseline", justifyContent: "space-between", marginBottom: 10 }}>
          <SectionLabel>Saved base résumés</SectionLabel>
          <span style={{ fontSize: 11.5, color: "var(--fg-2)" }}>{SAVED_RESUMES.length} versions · 10 GB storage</span>
        </div>
        <Panel pad={0}>
          {SAVED_RESUMES.map((r, i) => (
            <div key={r.id} style={{ display: "flex", alignItems: "center", gap: 14, padding: "13px 16px", borderBottom: i < SAVED_RESUMES.length - 1 ? "1px solid var(--ink-50)" : "none" }}>
              <span style={{ width: 38, height: 46, borderRadius: 5, background: "#fff", border: "1px solid var(--ink-100)", display: "grid", placeItems: "center", flexShrink: 0, color: "var(--fg-2)" }}>
                <Icon name="fileText" size={18}/>
              </span>
              <div style={{ flex: 1, minWidth: 0 }}>
                <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
                  <span style={{ fontSize: 14, fontWeight: 600 }}>{r.name}</span>
                  {r.current && <Chip tone="applied">Current master</Chip>}
                </div>
                <div style={{ fontSize: 12, color: "var(--fg-2)", marginTop: 2 }}>{r.template} template · {r.note}</div>
              </div>
              <span style={{ fontSize: 11.5, color: "var(--fg-2)", fontFamily: "var(--font-mono)", flexShrink: 0 }}>Saved {r.saved}</span>
              <div style={{ display: "flex", gap: 6, flexShrink: 0 }}>
                <Button variant="ghost" size="sm" icon="eye" onClick={() => setModal({ kind: "view", r })}>Open</Button>
                {!r.current && <Button variant="ghost" size="sm" icon="check">Set as base</Button>}
                <Button variant="ghost" size="sm" icon="download">PDF</Button>
              </div>
            </div>
          ))}
        </Panel>
      </section>

      {/* Generated, per-application résumés */}
      <section>
        <div style={{ display: "flex", alignItems: "baseline", justifyContent: "space-between", marginBottom: 12 }}>
          <SectionLabel>Generated résumés</SectionLabel>
          <span style={{ fontSize: 11.5, color: "var(--fg-2)" }}>{GENERATED_RESUMES.length} tailored from your base · across your search</span>
        </div>

        {/* Toolbar: search · filter · sort */}
        <div style={{ display: "flex", alignItems: "center", gap: 12, marginBottom: 12, flexWrap: "wrap" }}>
          <div style={{ display: "flex", alignItems: "center", gap: 8, flex: 1, minWidth: 200, maxWidth: 320, padding: "8px 12px", borderRadius: 8, background: "#fff", border: "1px solid var(--ink-100)" }}>
            <Icon name="search" size={15} style={{ color: "var(--fg-2)", flexShrink: 0 }}/>
            <input value={q} onChange={e => setQ(e.target.value)} placeholder="Search by company or role"
              style={{ flex: 1, minWidth: 0, border: "none", outline: "none", background: "transparent", fontFamily: "var(--font-sans)", fontSize: 13, color: "var(--fg-1)" }}/>
            {q && <button onClick={() => setQ("")} style={{ background: "transparent", border: "none", cursor: "pointer", color: "var(--fg-2)", display: "grid", placeItems: "center", padding: 0 }}><Icon name="close" size={13}/></button>}
          </div>
          <div style={{ display: "flex", gap: 6, flexWrap: "wrap" }}>
            {filters.map(f => {
              const on = status === f.key;
              return (
                <button key={f.key} onClick={() => setStatus(f.key)} style={{
                  display: "inline-flex", alignItems: "center", gap: 7, padding: "6px 12px", borderRadius: 999, cursor: "pointer",
                  fontFamily: "var(--font-sans)", fontSize: 12.5, fontWeight: 500, transition: "all 120ms",
                  background: on ? "rgba(140,21,21,0.10)" : "#fff", color: on ? "#5E0E0E" : "var(--fg-1)",
                  border: on ? "1px solid rgba(140,21,21,0.22)" : "1px solid var(--ink-100)",
                }}>
                  {f.label}
                  <span style={{ fontSize: 11, fontVariantNumeric: "tabular-nums", color: on ? "var(--cardinal)" : "var(--fg-2)" }}>{f.n}</span>
                </button>
              );
            })}
          </div>
          <span style={{ flex: 1 }}/>
          <Segmented value={sort} onChange={setSort} options={[{ value: "recent", label: "Recent" }, { value: "fit", label: "Best fit" }]}/>
        </div>

        {list.length === 0 ? (
          <Panel pad={0}>
            <div style={{ padding: "48px 24px", display: "flex", flexDirection: "column", alignItems: "center", gap: 10, textAlign: "center" }}>
              <span style={{ width: 44, height: 44, borderRadius: 999, background: "var(--paper-sunken)", display: "grid", placeItems: "center", color: "var(--fg-2)" }}><Icon name="search" size={20}/></span>
              <div style={{ fontFamily: "var(--font-display)", fontSize: 18, fontWeight: 500 }}>Nothing here yet</div>
              <div style={{ fontSize: 13, color: "var(--fg-2)", maxWidth: 340, lineHeight: 1.5 }}>
                No résumés match {q.trim() ? `"${q.trim()}"` : "this filter"}. Clear it, or tailor a new one for a job.
              </div>
              <div style={{ marginTop: 4 }}><Button variant="secondary" size="sm" icon="rotate" onClick={() => { setQ(""); setStatus("all"); }}>Clear filters</Button></div>
            </div>
          </Panel>
        ) : (
          <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fill, minmax(300px, 1fr))", gap: 12 }}>
            {list.map(r => <GeneratedCard key={r.id} r={r} onDiff={() => setModal({ kind: "diff", r })} onView={() => setModal({ kind: "view", r })}/>)}
          </div>
        )}
      </section>

      {modal && <ResumeModal entry={modal} onClose={() => setModal(null)} onSwitch={setModal}/>}
    </div>
  );
}

function GeneratedCard({ r, onDiff, onView }) {
  const st = RESUME_STATUS[r.status] || RESUME_STATUS.saved;
  const tone = TONES[r.tone] || TONES.neutral;
  return (
    <Panel pad={0} accent={tone.color} style={{ overflow: "hidden" }}>
      <button onClick={onView} style={{ display: "block", width: "100%", textAlign: "left", background: "transparent", border: "none", cursor: "pointer", padding: "14px 16px 14px 18px", fontFamily: "var(--font-sans)" }}>
        <div style={{ display: "flex", alignItems: "flex-start", justifyContent: "space-between", gap: 10 }}>
          <div style={{ minWidth: 0 }}>
            <div style={{ fontSize: 14.5, fontWeight: 600, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{r.job}</div>
            <div style={{ fontSize: 12.5, color: "var(--fg-2)", marginTop: 1 }}>{r.co}</div>
          </div>
          <Chip tone={st.tone}>{st.label}</Chip>
        </div>

        <div style={{ display: "flex", alignItems: "center", gap: 8, marginTop: 12, flexWrap: "wrap" }}>
          <FitBadge value={r.fit} size="sm"/>
          <span style={{ fontSize: 11.5, color: "var(--fg-2)", display: "inline-flex", alignItems: "center", gap: 5 }}>
            <Icon name="fileText" size={13}/> {r.template}
          </span>
          <span style={{ fontSize: 11.5, color: "var(--fg-2)", display: "inline-flex", alignItems: "center", gap: 5 }}>
            <Icon name="edit" size={13}/> {r.changes} tailored bullets
          </span>
        </div>
      </button>
      <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", gap: 8, padding: "9px 12px 9px 18px", borderTop: "1px solid var(--ink-50)", background: "var(--paper)" }}>
        <span style={{ fontSize: 11, color: "var(--fg-3)", fontFamily: "var(--font-mono)" }}>{r.date}</span>
        <div style={{ display: "flex", gap: 4 }}>
          <Button variant="ghost" size="sm" icon="eye" onClick={onDiff}>View diff</Button>
          <Button variant="ghost" size="sm" icon="copy">Duplicate</Button>
          <Button variant="ghost" size="sm" icon="download">PDF</Button>
        </div>
      </div>
    </Panel>
  );
}

// ============================================================
// Modal: open a résumé (rendered doc) or view its tailoring diff.
// ============================================================
function ResumeModal({ entry, onClose, onSwitch }) {
  const { kind, r } = entry;
  const isGen = !!r.job; // generated résumés carry a job; saved bases don't
  const tplName = r.template;
  const t = TEMPLATES.find(x => x.name === tplName) || TEMPLATES.find(x => x.key === "executive");
  const title = isGen ? `${r.job}` : r.name;
  const sub = isGen ? `${r.co} · tailored from your base` : `${r.template} template · ${r.note}`;

  return ReactDOM.createPortal((
    <div className="cad-fade" onClick={onClose} style={{ position: "fixed", inset: 0, zIndex: 200, background: "rgba(31,27,22,0.32)", display: "grid", placeItems: "center", padding: 24 }}>
      <div className="cad-rise" onClick={e => e.stopPropagation()} style={{ width: kind === "diff" ? 680 : 640, maxHeight: "90vh", display: "flex", flexDirection: "column", background: "#fff", borderRadius: 14, boxShadow: "0 32px 64px rgba(31,27,22,0.28)", overflow: "hidden" }}>
        {/* Header */}
        <div style={{ padding: "16px 20px", borderBottom: "1px solid var(--ink-100)", display: "flex", alignItems: "center", gap: 12, flexShrink: 0 }}>
          <span style={{ width: 36, height: 36, borderRadius: 8, background: "var(--cardinal-50)", color: "var(--cardinal)", display: "grid", placeItems: "center", flexShrink: 0 }}>
            <Icon name={kind === "diff" ? "edit" : "fileText"} size={18}/>
          </span>
          <div style={{ flex: 1, minWidth: 0 }}>
            <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
              <span style={{ fontFamily: "var(--font-display)", fontSize: 18, fontWeight: 500, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>
                {kind === "diff" ? "What Offerroom changed for this role" : title}
              </span>
              {isGen && <Chip tone={(RESUME_STATUS[r.status] || RESUME_STATUS.saved).tone}>{(RESUME_STATUS[r.status] || RESUME_STATUS.saved).label}</Chip>}
            </div>
            <div style={{ fontSize: 12, color: "var(--fg-2)", marginTop: 1, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>
              {kind === "diff" ? `${r.job} · ${r.co}` : sub}
            </div>
          </div>
          {/* Switch between diff and document for generated résumés */}
          {isGen && (
            <Segmented value={kind} onChange={(v) => onSwitch({ kind: v, r })}
              options={[{ value: "diff", label: "Diff" }, { value: "view", label: "Document" }]}/>
          )}
          <button onClick={onClose} style={{ width: 30, height: 30, borderRadius: 6, border: "1px solid var(--ink-100)", background: "#fff", cursor: "pointer", display: "grid", placeItems: "center", flexShrink: 0 }}><Icon name="close" size={15}/></button>
        </div>

        {/* Body */}
        <div style={{ flex: 1, overflow: "auto", background: kind === "diff" ? "#fff" : "var(--paper-sunken)" }}>
          {kind === "diff" ? <DiffView r={r}/> : (
            <>
              {isGen && (
                <div style={{ display: "flex", alignItems: "center", gap: 10, padding: "11px 16px", background: "var(--cardinal-50)", borderBottom: "1px solid var(--cardinal-100)", position: "sticky", top: 0, zIndex: 1 }}>
                  <Icon name="sparkles" size={15} style={{ color: "var(--cardinal)", flexShrink: 0 }}/>
                  <span style={{ fontSize: 12.5, color: "var(--cardinal-700)", flex: 1, minWidth: 0 }}>
                    Tailored for <b style={{ fontWeight: 600 }}>{r.co}</b> · Offerroom's rewrites from your base are highlighted below
                  </span>
                  <Button variant="ghost" size="sm" icon="edit" onClick={() => onSwitch({ kind: "diff", r })}>See changes</Button>
                </div>
              )}
              <div style={{ padding: 24, display: "grid", placeItems: "center" }}>
                <ResumeDoc t={t} density="balanced" accentOn={true} tailored={isGen} pageSize="letter" pageCount={1}/>
              </div>
            </>
          )}
        </div>

        {/* Footer */}
        <div style={{ padding: "12px 18px", borderTop: "1px solid var(--ink-100)", display: "flex", alignItems: "center", justifyContent: "space-between", gap: 10, flexShrink: 0, background: "var(--paper)" }}>
          <span style={{ fontSize: 11.5, color: "var(--fg-2)", display: "inline-flex", alignItems: "center", gap: 6 }}>
            <Icon name="check" size={13} style={{ color: "#5A7150" }}/> ATS-safe · selectable text · single-file PDF
          </span>
          <div style={{ display: "flex", gap: 8 }}>
            {kind === "diff" && <Button variant="ghost" size="sm" icon="fileText" onClick={() => onSwitch({ kind: "view", r })}>Open document</Button>}
            <Button variant="secondary" size="sm" icon="edit">Edit</Button>
            <Button variant="primary" size="sm" icon="download">Export PDF</Button>
          </div>
        </div>
      </div>
    </div>
  ), document.body);
}

// Per-bullet tailoring diff, reusing the kit's diff vocabulary.
function DiffView({ r }) {
  const rewritten = RESUME_DIFF.reduce((n, s) => n + s.bullets.filter(b => b.status === "rewritten").length, 0);
  return (
    <div style={{ padding: "16px 22px 22px" }}>
      <div style={{ display: "flex", alignItems: "center", gap: 14, marginBottom: 14 }}>
        <FitBadge value={r.fit} size="sm"/>
        <span style={{ display: "inline-flex", alignItems: "center", gap: 5, fontSize: 11.5, color: "var(--fg-2)" }}><span style={{ width: 6, height: 6, borderRadius: 999, background: "#8C1515" }}/>{rewritten} rewritten</span>
        <span style={{ display: "inline-flex", alignItems: "center", gap: 5, fontSize: 11.5, color: "var(--fg-2)" }}><span style={{ width: 6, height: 6, borderRadius: 999, background: "var(--ink-300)" }}/>Kept</span>
        <span style={{ flex: 1 }}/>
        <span style={{ fontSize: 11, color: "var(--fg-3)" }}>Hover a highlighted line for its source</span>
      </div>
      {RESUME_DIFF.map((sec, i) => (
        <div key={i} style={{ marginTop: i === 0 ? 0 : 18 }}>
          <div style={{ fontSize: 11, fontWeight: 600, letterSpacing: "0.06em", textTransform: "uppercase", color: "var(--cardinal)", marginBottom: 10 }}>{sec.section}</div>
          <ul style={{ margin: 0, padding: 0, listStyle: "none", display: "flex", flexDirection: "column", gap: 14 }}>
            {sec.bullets.map((b, j) => <DiffRow key={j} b={b}/>)}
          </ul>
        </div>
      ))}
    </div>
  );
}

const DiffRow = ({ b }) => {
  const isRewrite = b.status === "rewritten";
  return (
    <li style={{ position: "relative", paddingLeft: 16 }}>
      <span style={{ position: "absolute", left: 0, top: 7, width: 5, height: 5, borderRadius: 999, background: isRewrite ? "#8C1515" : "var(--ink-300)" }}/>
      {isRewrite && b.old && (
        <div style={{ fontSize: 11.5, lineHeight: 1.5, color: "var(--ink-300)", textDecoration: "line-through", marginBottom: 3 }}>{b.old}</div>
      )}
      <div style={{ fontSize: 12.5, lineHeight: 1.55, color: "var(--ink-700)" }}>
        {isRewrite ? (
          <Provenance trail={b.prov}>
            <span style={{ background: "rgba(74,88,104,0.08)", borderRadius: 3, padding: "0 2px" }}>{b.new}</span>
          </Provenance>
        ) : b.new}
      </div>
      <div style={{ display: "flex", alignItems: "center", gap: 7, marginTop: 4 }}>
        {isRewrite ? <Chip tone="info" dot={true}>Rewritten</Chip> : <Chip tone="neutral" dot={false}>Kept</Chip>}
        <span style={{ fontSize: 11, color: "var(--fg-2)", lineHeight: 1.4 }}>{b.why}</span>
      </div>
    </li>
  );
};

// ----- Controls helpers -----
const CtrlRow = ({ label, children }) => (
  <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", gap: 10 }}>
    <span style={{ fontSize: 12, color: "var(--fg-2)" }}>{label}</span>
    {children}
  </div>
);

const ToggleRow = ({ label, sub, on, onClick }) => (
  <div style={{ display: "flex", alignItems: "flex-start", justifyContent: "space-between", gap: 12 }}>
    <div style={{ minWidth: 0 }}>
      <div style={{ fontSize: 13, color: "var(--fg-1)" }}>{label}</div>
      {sub && <div style={{ fontSize: 11, color: "var(--fg-2)", marginTop: 2, lineHeight: 1.4 }}>{sub}</div>}
    </div>
    <div style={{ flexShrink: 0, paddingTop: 1 }}><Toggle on={on} onClick={onClick}/></div>
  </div>
);

// Upload-your-own-template button (real file input; records name + extension).
function TemplateUpload({ onUpload }) {
  const ref = React.useRef(null);
  const [hover, setHover] = React.useState(false);
  return (
    <>
      <input ref={ref} type="file" accept=".docx,.doc,.pdf,.tex" style={{ display: "none" }}
        onChange={e => {
          const f = e.target.files && e.target.files[0];
          if (!f) return;
          const ext = (f.name.split(".").pop() || "").toLowerCase();
          onUpload(f.name, ext);
          e.target.value = "";
        }}/>
      <button onClick={() => ref.current && ref.current.click()}
        onMouseEnter={() => setHover(true)} onMouseLeave={() => setHover(false)}
        style={{ marginTop: 10, width: "100%", display: "flex", alignItems: "center", gap: 10, padding: "11px 12px", borderRadius: 8, cursor: "pointer",
          background: hover ? "rgba(140,21,21,0.04)" : "rgba(31,27,22,0.015)",
          border: `1.5px dashed ${hover ? "rgba(140,21,21,0.3)" : "rgba(31,27,22,0.18)"}`,
          fontFamily: "var(--font-sans)", textAlign: "left", transition: "all 120ms" }}>
        <span style={{ width: 30, height: 30, borderRadius: 7, background: "#fff", border: "1px solid var(--ink-100)", display: "grid", placeItems: "center", color: "var(--cardinal)", flexShrink: 0 }}><Icon name="upload" size={15}/></span>
        <span style={{ minWidth: 0 }}>
          <span style={{ display: "block", fontSize: 12.5, fontWeight: 600, color: "var(--fg-1)" }}>Upload your own</span>
          <span style={{ display: "block", fontSize: 11, color: "var(--fg-2)", marginTop: 1 }}>.docx · .pdf · .tex</span>
        </span>
      </button>
    </>
  );
}

// Live page-fill gauge: reads the doc's measured height against the page target.
function PageFitGauge({ fit, pageCount, autoFit }) {
  const innerH = fit ? fit.innerH : 1;
  const contentH = fit ? fit.contentH : 0;
  const used = contentH ? Math.max(1, Math.ceil(contentH / innerH)) : 1;
  const ratio = contentH ? contentH / (innerH * pageCount) : 0;
  const pct = Math.round(ratio * 100);
  const over = used > pageCount;
  const tight = !over && ratio >= 0.9;
  const tone = over ? { bar: "#B08A3E", tint: "#F7F1E1", line: "rgba(176,138,62,0.32)", text: "#6E5419" }
    : tight ? { bar: "#4A5868", tint: "#E8ECEF", line: "rgba(74,88,104,0.26)", text: "#2A3744" }
    : { bar: "#5A7150", tint: "#E7EDE3", line: "rgba(90,113,80,0.26)", text: "#2F4528" };
  const label = over ? `Over · runs to page ${used}` : tight ? `Fits · ${pct}% of the page` : `Fits · ${pct}% used`;
  const sub = over
    ? `Past your ${pageCount}-page limit. Tighten spacing, add a page, or turn on auto-fit.`
    : `of ${pageCount} ${pageCount > 1 ? "pages" : "page"}${ratio > 0 && ratio < 0.7 ? " · plenty of room" : ratio < 0.9 ? " · room to spare" : ""}.`;
  return (
    <div style={{ background: tone.tint, border: `1px solid ${tone.line}`, borderRadius: 9, padding: "11px 12px" }}>
      <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 8 }}>
        <span style={{ fontSize: 12.5, fontWeight: 600, color: tone.text, display: "inline-flex", alignItems: "center", gap: 6 }}>
          <Icon name={over ? "layers" : "check"} size={13}/> {label}
        </span>
        {autoFit && <span style={{ fontSize: 9, fontFamily: "var(--font-mono)", letterSpacing: "0.06em", color: tone.text, opacity: 0.75 }}>AUTO</span>}
      </div>
      <div style={{ position: "relative", height: 7, borderRadius: 999, background: "#fff", border: `1px solid ${tone.line}`, overflow: "hidden" }}>
        <div style={{ position: "absolute", left: 0, top: 0, bottom: 0, width: `${Math.max(3, Math.min(ratio, 1) * 100)}%`, background: tone.bar, borderRadius: 999, transition: "width 220ms cubic-bezier(0.2,0.7,0.1,1)" }}/>
        {pageCount > 1 && <span style={{ position: "absolute", left: "50%", top: 0, bottom: 0, width: 1, background: "rgba(31,27,22,0.16)" }}/>}
      </div>
      <div style={{ fontSize: 11, color: tone.text, opacity: 0.9, marginTop: 6, lineHeight: 1.4 }}>{sub}</div>
    </div>
  );
}

// Inline formatting toolbar shown while editing the base résumé.
function FormatBar({ docFont, setDocFont, fontPt, setFontPt }) {
  const [act, setAct] = React.useState({ bold: false, italic: false, underline: false });
  React.useEffect(() => {
    const upd = () => { try { setAct({ bold: document.queryCommandState("bold"), italic: document.queryCommandState("italic"), underline: document.queryCommandState("underline") }); } catch (e) {} };
    document.addEventListener("selectionchange", upd);
    return () => document.removeEventListener("selectionchange", upd);
  }, []);
  const exec = (cmd) => { try { document.execCommand(cmd, false, null); } catch (e) {} try { setAct(a => ({ ...a, [cmd]: document.queryCommandState(cmd) })); } catch (e) {} };
  const FmtBtn = ({ cmd, label, style }) => (
    <button onMouseDown={(e) => e.preventDefault()} onClick={() => exec(cmd)} title={cmd[0].toUpperCase() + cmd.slice(1)}
      style={{ width: 30, height: 28, borderRadius: 6, cursor: "pointer", display: "grid", placeItems: "center",
        border: act[cmd] ? "1px solid rgba(140,21,21,0.3)" : "1px solid var(--ink-100)",
        background: act[cmd] ? "var(--cardinal-50)" : "#fff", color: act[cmd] ? "var(--cardinal)" : "var(--fg-1)",
        fontFamily: "var(--font-sans)", lineHeight: 1, ...style }}>{label}</button>
  );
  const StepBtn = ({ dir }) => (
    <button onClick={() => setFontPt(p => Math.min(13, Math.max(9, Math.round((p + dir * 0.5) * 2) / 2)))}
      style={{ width: 26, height: 26, border: "none", background: "transparent", cursor: "pointer", display: "grid", placeItems: "center", color: "var(--fg-1)", fontSize: 16, lineHeight: 1 }}>{dir < 0 ? "\u2212" : "+"}</button>
  );
  return (
    <div style={{ display: "flex", alignItems: "center", gap: 10, padding: "8px 16px", borderBottom: "1px solid var(--ink-50)", background: "#fff", flexWrap: "wrap" }}>
      <div style={{ display: "flex", gap: 4 }}>
        <FmtBtn cmd="bold" label="B" style={{ fontWeight: 800, fontSize: 14.5 }}/>
        <FmtBtn cmd="italic" label="I" style={{ fontStyle: "italic", fontFamily: "var(--font-display)", fontSize: 15.5 }}/>
        <FmtBtn cmd="underline" label="U" style={{ textDecoration: "underline", fontSize: 14.5 }}/>
      </div>
      <span style={{ width: 1, height: 20, background: "var(--ink-100)" }}/>
      <select value={docFont} onChange={(e) => setDocFont(e.target.value)} title="Document font"
        style={{ height: 28, borderRadius: 6, border: "1px solid var(--ink-100)", background: "#fff", color: "var(--fg-1)",
          fontFamily: "var(--font-sans)", fontSize: 12.5, padding: "0 8px", cursor: "pointer", maxWidth: 156 }}>
        {DOC_FONTS.map(f => <option key={f.value} value={f.value}>{f.label}</option>)}
      </select>
      <div style={{ display: "flex", alignItems: "center", border: "1px solid var(--ink-100)", borderRadius: 6, overflow: "hidden", height: 28 }} title="Type size">
        <StepBtn dir={-1}/>
        <span style={{ minWidth: 48, textAlign: "center", fontSize: 12.5, fontVariantNumeric: "tabular-nums", color: "var(--fg-1)" }}>{fontPt.toFixed(1).replace(/\.0$/, "")} pt</span>
        <StepBtn dir={1}/>
      </div>
      <span style={{ flex: 1, minWidth: 8 }}/>
      <span style={{ fontSize: 11, color: "var(--fg-2)", whiteSpace: "nowrap" }}>Select text to format · saved with the template</span>
    </div>
  );
}

// ============================================================
// Generated .tex source viewer — the customization, shown as the
// LaTeX the backend actually compiles. Read-only, copyable.
// ============================================================
function TexSourceModal({ design, t, pageSize, fontPt, density, onClose }) {
  const [copied, setCopied] = React.useState(false);
  const adv = design.adv || DEFAULT_ADV;
  const accent = (design.accentColor || t.accent).replace("#", "");
  const head = HEAD_STYLES.find(h => h.value === design.headStyle) || HEAD_STYLES[0];
  const bullet = BULLETS.find(b => b.value === adv.bullet) || BULLETS[0];
  const lh = adv.lh || (DENS[density] || DENS.balanced).lh;
  const active = (design.sections || DEFAULT_SECTIONS).filter(s => s.on);
  const hidden = (design.sections || DEFAULT_SECTIONS).filter(s => !s.on);
  const headFmt = design.headStyle === "rule"
    ? "\\titleformat{\\section}{\\scshape\\color{accent}}{}{0pt}{}[\\titlerule]"
    : design.headStyle === "sideline"
    ? "\\titleformat{\\section}{\\scshape\\color{accent}}{\\rule[-2pt]{2.5pt}{9pt}\\hspace{6pt}}{0pt}{}"
    : "\\titleformat{\\section}{\\scshape\\color{accent}}{}{0pt}{}";
  const lines = [
    "% Offerroom · base résumé — regenerates as you customize",
    `% Template: ${t.name} · compiled by the Offerroom LaTeX backend`,
    `\\documentclass[${fontPt}pt,${pageSize === "a4" ? "a4paper" : "letterpaper"}]{article}`,
    `\\usepackage[margin=${(MARGINS[design.margin] || MARGINS.normal).tex}]{geometry}`,
    "\\usepackage{titlesec,enumitem,xcolor}",
    `\\definecolor{accent}{HTML}{${accent.toUpperCase()}}`,
    headFmt,
    `\\setlist[itemize]{label=${bullet.tex}, leftmargin=1.2em}`,
    `\\linespread{${lh.toFixed(2)}}${adv.lh ? "  % manual override" : "  % from Spacing preset"}`,
    `\\pagestyle{${adv.pageNums ? "plain" : "empty"}}`,
    "\\begin{document}",
    `\\namehead{${CANDIDATE.fullName}}{${adv.nameSize}pt}`,
    `\\contactline[${adv.contact}]{${CANDIDATE.email}}{${CANDIDATE.location}}{${CANDIDATE.linkedin}}`,
    ...active.map(s => `\\section{${s.label}}${s.side === "side" ? "  % sidebar on two-column templates" : ""}`),
    ...hidden.map(s => `% \\section{${s.label}}  — hidden`),
    "\\end{document}",
  ];
  const raw = lines.join("\n");
  const copy = () => {
    try { navigator.clipboard.writeText(raw); } catch (e) {}
    setCopied(true);
    setTimeout(() => setCopied(false), 1600);
  };
  return ReactDOM.createPortal((
    <div className="cad-fade" onClick={onClose} style={{ position: "fixed", inset: 0, zIndex: 200, background: "rgba(31,27,22,0.32)", display: "grid", placeItems: "center", padding: 24 }}>
      <div className="cad-rise" onClick={e => e.stopPropagation()} style={{ width: 620, maxHeight: "86vh", display: "flex", flexDirection: "column", background: "#fff", borderRadius: 14, boxShadow: "0 32px 64px rgba(31,27,22,0.28)", overflow: "hidden" }}>
        <div style={{ padding: "14px 18px", borderBottom: "1px solid var(--ink-100)", display: "flex", alignItems: "center", gap: 12, flexShrink: 0 }}>
          <span style={{ width: 34, height: 34, borderRadius: 8, background: "var(--cardinal-50)", color: "var(--cardinal)", display: "grid", placeItems: "center", flexShrink: 0 }}><Icon name="fileText" size={17}/></span>
          <div style={{ flex: 1, minWidth: 0 }}>
            <div style={{ fontFamily: "var(--font-display)", fontSize: 17, fontWeight: 500 }}>Generated .tex source</div>
            <div style={{ fontSize: 12, color: "var(--fg-2)", marginTop: 1 }}>What the backend compiles. Updates live with every control.</div>
          </div>
          <Chip tone="sage" dot={false}>{t.name}.tex</Chip>
          <button onClick={onClose} style={{ width: 30, height: 30, borderRadius: 6, border: "1px solid var(--ink-100)", background: "#fff", cursor: "pointer", display: "grid", placeItems: "center", flexShrink: 0 }}><Icon name="close" size={15}/></button>
        </div>
        <div style={{ flex: 1, overflow: "auto", background: "#1F1B16", padding: "16px 0" }}>
          <pre style={{ margin: 0, fontFamily: "var(--font-mono)", fontSize: 12, lineHeight: 1.75 }}>
            {lines.map((ln, i) => (
              <div key={i} style={{ display: "flex", padding: "0 18px" }}>
                <span style={{ width: 26, flexShrink: 0, textAlign: "right", marginRight: 14, color: "rgba(255,255,255,0.25)", userSelect: "none" }}>{i + 1}</span>
                <span style={{ whiteSpace: "pre-wrap", color: ln.trimStart().startsWith("%") ? "rgba(255,255,255,0.4)" : ln.includes("%") ? "#EDE4D8" : "#EDE4D8" }}>
                  {ln.trimStart().startsWith("%") ? ln : (() => {
                    const ci = ln.indexOf("  %");
                    if (ci < 0) return ln;
                    return <>{ln.slice(0, ci)}<span style={{ color: "rgba(255,255,255,0.4)" }}>{ln.slice(ci)}</span></>;
                  })()}
                </span>
              </div>
            ))}
          </pre>
        </div>
        <div style={{ padding: "12px 18px", borderTop: "1px solid var(--ink-100)", display: "flex", alignItems: "center", justifyContent: "space-between", gap: 10, flexShrink: 0, background: "var(--paper)" }}>
          <span style={{ fontSize: 11.5, color: "var(--fg-2)" }}><Icon name="check" size={13} style={{ color: "#5A7150", verticalAlign: "-2px" }}/> Read-only preview · content sections expand at compile time</span>
          <div style={{ display: "flex", gap: 8 }}>
            <Button variant="secondary" size="sm" icon={copied ? "check" : "copy"} onClick={copy}>{copied ? "Copied" : "Copy source"}</Button>
            <Button variant="primary" size="sm" icon="download">Download .tex</Button>
          </div>
        </div>
      </div>
    </div>
  ), document.body);
}

window.ScrResume = ScrResume;
window.ResumeDoc = ResumeDoc;
window.TEMPLATES = TEMPLATES;
