// Main App: wires jobs rail + candidates column + candidate detail + tweaks
const { color: AC } = window.FF;

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "layout": "attention",
  "vocab": "applied-sourced",
  "jobCardSplit": "aggregated",
  "aiActivity": "off",
  "receiptTone": "calm"
}/*EDITMODE-END*/;

// ── Hash routing ────────────────────────────────────────────────────────────
// Friendly URL names for the layouts we actually demo, so a call can switch
// versions from the address bar instead of the Tweaks panel (which lists every
// old exploration). Add a line here when a new demo-able layout lands.
//   /manage-jobs-demo/                 → default (unchanged)
//   /manage-jobs-demo/#action-needed   → the current direction
const HASH_LAYOUTS = {
  'action-needed': 'attention',
  'focus':         'focus',
  'all-jobs':      'alljobs',
  'activity':      'activity',
  'stacked':       'stacked',
  'two-surfaces':  'surfaces',
  'current':       'current',
};
// Unknown/absent hash returns null so the default layout stands.
function layoutFromHash() {
  const key = (window.location.hash || '').replace(/^#\/?/, '').trim().toLowerCase();
  return HASH_LAYOUTS[key] || null;
}

function App() {
  // Resolve the hash before the first render so there's no flash of the
  // default layout when someone opens a #deep-link.
  const initialTweaks = React.useMemo(() => {
    const l = layoutFromHash();
    return l ? { ...TWEAK_DEFAULTS, layout: l } : TWEAK_DEFAULTS;
  }, []);
  const [t, setTweak] = useTweaks(initialTweaks);

  // Swap layouts in place on hash change — mid-demo that keeps the selected
  // candidate, scroll position and expanded sections instead of reloading.
  React.useEffect(() => {
    const onHash = () => { const l = layoutFromHash(); if (l) setTweak('layout', l); };
    window.addEventListener('hashchange', onHash);
    return () => window.removeEventListener('hashchange', onHash);
  }, [setTweak]);

  const [selectedJobId, setSelectedJobId] = React.useState((window.__JOBS__ && window.__JOBS__.find(j => j.selected) || {}).id || 'awl');
  const [selectedCandidateId, setSelectedCandidateId] = React.useState(window.__SELECTED_CANDIDATE__ || (window.__CANDIDATES__ && window.__CANDIDATES__[0] && window.__CANDIDATES__[0].id));
  const [drawerId, setDrawerId] = React.useState(null);
  // Attention filter lives in the jobs rail but scopes the candidates panel,
  // so App owns it. Only the Focus layout surfaces the control.
  const [focusOnly, setFocusOnly] = React.useState(false);
  // Where the cross-job takeover should return you to.
  const prevLayout = React.useRef('focus');

  React.useEffect(() => {
    if (!drawerId) return;
    const onKey = (e) => { if (e.key === 'Escape') setDrawerId(null); };
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, [drawerId]);

  const jobs = window.__JOBS__;
  const candidates = window.__CANDIDATES__;
  const selectedCandidate = candidates.find(c => c.id === selectedCandidateId) || candidates[0];

  // Per-job Action-needed counts for the job cards.
  const actionCounts = React.useMemo(() => {
    const m = {};
    candidates.forEach(c => { if (atTrigger(c)) m[c.jobId] = (m[c.jobId] || 0) + 1; });
    return m;
  }, [candidates]);

  const isTakeover = t.layout === 'decision' || t.layout === 'copilot' || t.layout === 'spine' || t.layout === 'desk' || t.layout === 'alljobs';

  return (
    <React.Fragment>
    {isTakeover && t.layout === 'decision' && (
      <LayoutDecision candidates={candidates} onExit={()=>setTweak('layout','match')}/>
    )}
    {isTakeover && t.layout === 'copilot' && (
      <LayoutCopilot candidates={candidates} onExit={()=>setTweak('layout','match')}/>
    )}
    {isTakeover && t.layout === 'spine' && (
      <LayoutSpine candidates={candidates} onExit={()=>setTweak('layout','match')}/>
    )}
    {isTakeover && t.layout === 'desk' && (
      <LayoutDesk candidates={candidates} onExit={()=>setTweak('layout','match')}/>
    )}
    {isTakeover && t.layout === 'alljobs' && (
      <LayoutAllJobsTakeover candidates={candidates} onExit={()=>setTweak('layout', prevLayout.current || 'focus')}/>
    )}
    <div style={{ display:'flex', minHeight:'100vh', background:'#fff', fontFamily:"'Inter',system-ui,sans-serif", color: AC.shade[880], visibility: isTakeover ? 'hidden' : 'visible' }}>
      {/* Narrow icon nav rail */}
      <DesktopRail/>

      {/* Saved jobs */}
      <JobsRail
        jobs={jobs}
        selectedId={selectedJobId}
        onSelect={setSelectedJobId}
        vocab={t.vocab}
        splitBySource={t.jobCardSplit === 'split'}
        actionable={t.layout === 'linear'}
        focus={t.layout === 'focus' ? { on: focusOnly, onToggle: () => setFocusOnly(v => !v) } : null}
        onOpenAllJobs={t.layout === 'focus' ? () => { prevLayout.current = t.layout; setTweak('layout','alljobs'); } : null}
        actionCounts={(t.layout === 'focus' || t.layout === 'alljobs') ? actionCounts : null}
      />

      {t.layout === 'linear' ? (
        <React.Fragment>
          <LayoutLinear candidates={candidates} selectedId={drawerId} onSelect={setDrawerId}/>
          {drawerId && (
            <aside style={{ flex:'none', width:'min(460px, 42vw)', borderLeft:`1px solid ${AC.tint[80]}`, background:'#fff', display:'flex', flexDirection:'column', position:'relative', minHeight:'100vh', animation:'ff-drawer-in .2s cubic-bezier(.2,.8,.2,1)' }}>
              <style>{`@keyframes ff-drawer-in{from{opacity:.5;transform:translateX(12px)}to{opacity:1;transform:translateX(0)}}`}</style>
              <button onClick={()=>setDrawerId(null)} title="Close (Esc)" style={{ position:'absolute', top:14, right:18, zIndex:2, width:30, height:30, borderRadius:7, border:`1px solid ${AC.tint[100]}`, background:'#fff', cursor:'pointer', fontSize:14, color: AC.shade[700] }}>✕</button>
              <CandidateDetail candidate={candidates.find(c=>c.id===drawerId)} vocab={t.vocab}/>
            </aside>
          )}
        </React.Fragment>
      ) : (
      <React.Fragment>
      {/* Candidates column */}
      <CandidatesColumn
        candidates={candidates}
        selectedId={selectedCandidateId}
        onSelect={setSelectedCandidateId}
        layout={t.layout}
        vocab={t.vocab}
        aiActivity={t.aiActivity}
        receiptTone={t.receiptTone}
        focusOnly={focusOnly}
        selectedJobId={selectedJobId}
      />

      {/* Right detail */}
      <CandidateDetail candidate={selectedCandidate} vocab={t.vocab}/>
      </React.Fragment>
      )}

      {/* Tweaks panel */}
      <TweaksPanel title="Tweaks">
        <TweakSection label="The options — fused → disentangled"/>
        <div style={{ fontSize:11, lineHeight:1.45, color: AC.shade[700], padding:'0 2px 8px' }}>
          Ordered by how far each pulls <strong style={{ color: AC.shade[820] }}>attention</strong> (who to look at now)
          apart from <strong style={{ color: AC.shade[820] }}>tracking</strong> (where someone is in your process).
        </div>

        <SpectrumButton
          n="01" label="Today" tag="fully fused"
          desc="One set of statuses does attention + tracking + show-the-work."
          onClick={()=>setTweak({ layout:'current', vocab:'applied-sourced', jobCardSplit:'aggregated', aiActivity:'off' })}
        />
        <SpectrumButton
          n="02" label="Rename tabs" tag="still fused"
          desc="Clearer words, same model. The cheapest possible move."
          onClick={()=>setTweak({ layout:'current', vocab:'inbound-outbound', jobCardSplit:'aggregated', aiActivity:'off' })}
        />
        <SpectrumButton
          n="S" label="Source-first" tag="origin = nav"
          desc="Strawman, built to lose. Nav becomes Applied / AI Sourced / Imported / Re-engaged. Tests whether anyone secretly wants origin-based queues. (They don't.)"
          onClick={()=>setTweak({ layout:'sourcefirst', vocab:'applied-sourced', jobCardSplit:'aggregated', aiActivity:'off' })}
        />
        <SpectrumButton
          n="I" label="Intent-first" tag="temperature = nav"
          desc="Kill source language. Cold → Warming → Interested → Ready. Tests the opposite pole: maybe they care how warm someone is, not where they came from."
          onClick={()=>setTweak({ layout:'intent', vocab:'applied-sourced', jobCardSplit:'aggregated', aiActivity:'off' })}
        />
        <SpectrumButton
          n="03" label="Match-with-owner" tag="attention split"
          desc="Lanes become owner states — AI working → ready for you → done. Tracking still rides along."
          onClick={()=>setTweak({ layout:'match', vocab:'applied-sourced', jobCardSplit:'aggregated', aiActivity:'off' })}
        />
        <SpectrumButton
          n="★" label="Handoff overlay" tag="smallest real move" hot
          desc="Keep the ATS stages users know — just draw the line between 'AI working' and 'Ready for you', and fix New = new-to-you. Source stays a luggage tag. The version the call re-read endorses."
          onClick={()=>setTweak({ layout:'handoff', vocab:'applied-sourced', jobCardSplit:'aggregated', aiActivity:'off' })}
        />
        <SpectrumButton
          n="R" label="Receipt layer" tag="proof, not source" hot
          desc="Every candidate carries a plain-language receipt of what the AI did. Source becomes one fact in a sentence. Toggle the tone below: calm ↔ brutally honest."
          onClick={()=>setTweak({ layout:'receipt', vocab:'applied-sourced', jobCardSplit:'aggregated', aiActivity:'off' })}
        />
        <SpectrumButton
          n="04" label="Segment-aware" tag="split by audience"
          desc="Staffing gets a power queue; direct employers get a calm decision view."
          onClick={()=>setTweak({ layout:'segment', vocab:'applied-sourced', jobCardSplit:'aggregated', aiActivity:'off' })}
        />
        <SpectrumButton
          n="05" label="Campaign" tag="staffing's model"
          desc="The page is one outreach campaign. In progress vs Review. Tom's world."
          onClick={()=>setTweak({ layout:'campaign', vocab:'applied-sourced', jobCardSplit:'aggregated', aiActivity:'off' })}
        />
        <SpectrumButton
          n="06" label="Two surfaces" tag="fully disentangled" hot
          desc="Inbox (what needs you — drains to zero) + Pipeline (where everyone is). Attention and tracking become separate screens. The direct answer to the question."
          onClick={()=>setTweak({ layout:'surfaces', vocab:'applied-sourced', jobCardSplit:'aggregated', aiActivity:'off' })}
        />
        <SpectrumButton
          n="07" label="Action list" tag="the page IS the queue" hot
          desc="Scraps the list→detail split. One full-width grouped list — Needs review / In conversation / Waiting / AI working — every row carries its action. Job rail shows what needs you per req. (Linear-style.)"
          onClick={()=>setTweak({ layout:'linear', vocab:'applied-sourced', jobCardSplit:'aggregated', aiActivity:'off' })}
        />
        <SpectrumButton
          n="07" label="Decision Mode" tag="attention only" hot
          desc="Throws tracking away entirely. One card, three buttons. Are humans here to decide or to manage a list?"
          onClick={()=>setTweak({ layout:'decision', vocab:'applied-sourced', jobCardSplit:'aggregated', aiActivity:'off' })}
        />
        <SpectrumButton
          n="08" label="Co-pilot Chat" tag="fully disentangled" hot
          desc="AI surfaces who needs you (attention); the ATS becomes scaffolding it quietly operates (tracking). The chat-native version of the same idea."
          onClick={()=>setTweak({ layout:'copilot', vocab:'applied-sourced', jobCardSplit:'aggregated', aiActivity:'off' })}
        />
        <SpectrumButton
          n="🔥" label="No board" tag="kills status columns" hot
          desc="No tabs, no New/Engaged/Review, no drag. One self-sorting list ordered by who's next — and you physically can't refile anyone. Tracking ripped from your hands."
          onClick={()=>setTweak({ layout:'autorank', vocab:'applied-sourced', jobCardSplit:'aggregated', aiActivity:'off' })}
        />
        <SpectrumButton
          n="🔥" label="Sealed sourcing" tag="kills the Sourcing tab" hot
          desc="No browsable sourced list. Just a counter: 'AI is working 27' — you can't open it. People appear only when they cross into needs-you. Murders the backwards-icon confusion at its root."
          onClick={()=>setTweak({ layout:'sealed', vocab:'applied-sourced', jobCardSplit:'aggregated', aiActivity:'off' })}
        />
        <SpectrumButton
          n="🔥" label="Stage Spine" tag="funnel across the top" hot
          desc="No middle/detail panels. The funnel runs as a horizontal spine; the 'in play' middle is the whole screen; pre-engaged and review+ collapse to dim slivers at the edges."
          onClick={()=>setTweak({ layout:'spine', vocab:'applied-sourced', jobCardSplit:'aggregated', aiActivity:'off' })}
        />
        <SpectrumButton
          n="🔥" label="The Desk" tag="dissolves jobs" hot
          desc="No jobs rail. One wall of in-play candidates across every req, each tagged with its job, worked by priority. Tests: do recruiters want to work a job, or work their desk?"
          onClick={()=>setTweak({ layout:'desk', vocab:'applied-sourced', jobCardSplit:'aggregated', aiActivity:'off' })}
        />


        <TweakSection label="Older sketches"/>
        <TweakButton
          secondary label="Badges + source filter"
          onClick={()=>setTweak({ layout:'badges', vocab:'applied-sourced', jobCardSplit:'aggregated', aiActivity:'off' })}
        />
        <TweakButton
          secondary label="Source-first lanes"
          onClick={()=>setTweak({ layout:'lanes', vocab:'applied-sourced', jobCardSplit:'split', aiActivity:'panel' })}
        />
        <TweakButton
          secondary label="Side-by-side split"
          onClick={()=>setTweak({ layout:'split', vocab:'applied-sourced', jobCardSplit:'split', aiActivity:'panel' })}
        />
        <TweakButton
          secondary label="Workspace mode (Engaged-first)"
          onClick={()=>setTweak({ layout:'workspace', vocab:'applied-sourced', jobCardSplit:'aggregated', aiActivity:'off' })}
        />

        <TweakSection label="Fine tuning"/>
        <TweakRadio
          label="Receipt tone (Receipt layer)"
          value={t.receiptTone}
          options={[
            { value:'calm',  label:'Calm' },
            { value:'blunt', label:'Brutally honest' },
          ]}
          onChange={(v)=>setTweak('receiptTone', v)}
        />
        <TweakSelect
          label="Vocabulary"
          value={t.vocab}
          options={[
            { value:'applied-sourced',  label:'Applied / Sourced' },
            { value:'inbound-outbound', label:'Inbound / Outbound' },
            { value:'you-them',         label:'Came to you / We reached out' },
          ]}
          onChange={(v)=>setTweak('vocab', v)}
        />
        <TweakRadio
          label="Left-rail job counts"
          value={t.jobCardSplit}
          options={[
            { value:'aggregated', label:'Aggregated' },
            { value:'split',      label:'By source' },
          ]}
          onChange={(v)=>setTweak('jobCardSplit', v)}
        />
        <TweakRadio
          label="AI recruiter visibility"
          value={t.aiActivity}
          options={[
            { value:'off',   label:'Off' },
            { value:'strip', label:'Strip' },
            { value:'panel', label:'Panel' },
          ]}
          onChange={(v)=>setTweak('aiActivity', v)}
        />
      </TweaksPanel>
    </div>
    </React.Fragment>
  );
}

/* ============================================================
   Narrow icon rail — left edge
   ============================================================ */
function DesktopRail(){
  // Canonical FactoryFix app shell (ported from the design skill's prototype-template).
  const css = `
    .ffnav{background:#0F172A;color:#fff;flex:none;display:flex;flex-direction:column;align-items:center;justify-content:space-between;padding:8px;min-height:100vh}
    .ffnav .top,.ffnav .bot{display:flex;flex-direction:column;align-items:center}
    .ffnav .bot{width:48px}
    .ffnav .di{display:flex;height:48px;width:48px;align-items:center;justify-content:center;cursor:pointer;border-radius:8px;transition:background 150ms ease;position:relative;margin-bottom:2px}
    .ffnav .di:hover{background:rgba(255,255,255,.08)}
    .ffnav .di.active{background:#6C40E5}
    .ffnav .di svg{width:24px;height:24px;stroke:#BAC5D6;stroke-width:2;fill:none;stroke-linecap:round;stroke-linejoin:round;color:#BAC5D6}
    .ffnav .di.active svg,.ffnav .di:hover svg{stroke:#fff;color:#fff}
    .ffnav .di.mb2{margin-bottom:8px}
    .ffnav .logo{display:flex;height:48px;width:48px;align-items:center;justify-content:center;margin-bottom:2px}
    .ffnav .badge{position:absolute;right:8px;top:6px;display:flex;height:16px;width:16px;align-items:center;justify-content:center;border-radius:9999px;background:#F83D6A;color:#fff;font-size:8px;font-weight:800}
    .ffnav .slots{margin-bottom:8px;border-top:1px solid #334155;border-bottom:1px solid #334155;padding:14px 0;width:100%;display:flex;flex-direction:column;align-items:center;font-size:10px;line-height:1.35}
    .ffnav .slots b{font-weight:700;color:#fff}
    .ffnav .avatar{display:flex;height:48px;width:48px;align-items:center;justify-content:center;cursor:pointer}
    .ffnav .avatar i{display:flex;height:32px;width:32px;align-items:center;justify-content:center;border-radius:9999px;background:#DEFAEA;font-size:12px;font-weight:700;color:#184F32;font-style:normal}
  `;
  const html = `
    <style>${css}</style>
    <div class="top">
      <a class="logo" title="Home"><svg viewBox="0 0 28 24" fill="none" style="width:27px;height:24px"><path d="M27.7142 12L20.8571 24H7.14279L0.285645 12L7.14279 0H20.8571L27.7142 12Z" fill="#53D58B"/><path d="M13.9998 4.28564H18.2855L16.1426 8.14279L17.8569 11.9999H16.1426V19.7142H11.8569V8.14279L13.9998 4.28564Z" fill="#0F172A"/></svg></a>
      <div class="di mb2" title="Activity Feed"><svg viewBox="0 0 25 24"><path d="M15.4997 19C15.4997 20.6569 14.1566 22 12.4997 22C10.8429 22 9.49972 20.6569 9.49972 19M18.4997 11.2C18.4997 9.82087 17.8676 8.49823 16.7424 7.52304C15.6171 6.54786 14.091 6 12.4997 6C10.9084 6 9.3823 6.54786 8.25708 7.52304C7.13186 8.49823 6.49972 9.82087 6.49972 11.2C6.49972 13.4818 5.93385 15.1506 5.22778 16.3447C4.42306 17.7056 4.0207 18.3861 4.03659 18.5486C4.05476 18.7346 4.08824 18.7933 4.23906 18.9036C4.37089 19 5.03323 19 6.35791 19H18.6415C19.9662 19 20.6286 19 20.7604 18.9036C20.9112 18.7933 20.9447 18.7346 20.9629 18.5486C20.9787 18.3861 20.5764 17.7056 19.7717 16.3447C19.0656 15.1506 18.4997 13.4818 18.4997 11.2Z"/></svg><span class="badge">10</span></div>
      <a class="di active" title="Manage Jobs"><svg viewBox="0 0 24 24"><path d="M16 7C16 6.07003 16 5.60504 15.8978 5.22354C15.6204 4.18827 14.8117 3.37962 13.7765 3.10222C13.395 3 12.93 3 12 3C11.07 3 10.605 3 10.2235 3.10222C9.18827 3.37962 8.37962 4.18827 8.10222 5.22354C8 5.60504 8 6.07003 8 7M5.2 21H18.8C19.9201 21 20.4802 21 20.908 20.782C21.2843 20.5903 21.5903 20.2843 21.782 19.908C22 19.4802 22 18.9201 22 17.8V10.2C22 9.07989 22 8.51984 21.782 8.09202C21.5903 7.71569 21.2843 7.40973 20.908 7.21799C20.4802 7 19.9201 7 18.8 7H5.2C4.07989 7 3.51984 7 3.09202 7.21799C2.71569 7.40973 2.40973 7.71569 2.21799 8.09202C2 8.51984 2 9.07989 2 10.2V17.8C2 18.9201 2 19.4802 2.21799 19.908C2.40973 20.2843 2.71569 20.5903 3.09202 20.782C3.51984 21 4.0799 21 5.2 21Z"/></svg></a>
      <a class="di" title="Candidate Archive"><svg viewBox="0 0 24 24"><path d="M14 23C14.5523 23 15 22.5523 15 22C15 21.4477 14.5523 21 14 21V23ZM3 20V7H1V20H3ZM4 6H9.65242V4H4V6ZM3 7C3 6.44772 3.44772 6 4 6V4C2.34315 4 1 5.34315 1 7H3ZM1 20C1 21.6569 2.34315 23 4 23V21C3.44772 21 3 20.5523 3 20H1Z" fill="currentColor" stroke="none"/><path d="M20 19.5L22.5 22"/><circle cx="18.5" cy="17.5" r="2.5"/></svg></a>
      <a class="di" title="FactoryFix Talent Search"><svg viewBox="0 0 24 24"><path d="M12 15H8C6.13623 15 5.20435 15 4.46927 15.3045C3.48915 15.7105 2.71046 16.4892 2.30448 17.4693C2 18.2044 2 19.1362 2 21M13.5 7C13.5 9.20914 11.7091 11 9.5 11C7.29086 11 5.5 9.20914 5.5 7C5.5 4.79086 7.29086 3 9.5 3C11.7091 3 13.5 4.79086 13.5 7Z"/><path d="M19 18.5L21.5 21"/><circle cx="17.5" cy="16.5" r="2.5"/></svg></a>
      <a class="di" title="Performance Dashboard"><svg viewBox="0 0 24 24"><path d="M17.2 14C17.477 14 17.6155 14 17.7278 14.0615C17.8204 14.1122 17.9065 14.2075 17.9478 14.3047C17.9978 14.4225 17.9852 14.5479 17.96 14.7987C17.8296 16.0987 17.3822 17.3514 16.6518 18.4445C15.7727 19.7601 14.5233 20.7855 13.0615 21.391C11.5997 21.9965 9.99113 22.155 8.43928 21.8463C6.88743 21.5376 5.46197 20.7757 4.34315 19.6568C3.22433 18.538 2.4624 17.1126 2.15372 15.5607C1.84504 14.0089 2.00347 12.4003 2.60897 10.9385C3.21447 9.47671 4.23985 8.22728 5.55544 7.34823C6.64856 6.61783 7.90125 6.17039 9.20131 6.03995C9.45207 6.01479 9.57745 6.00221 9.69528 6.0522C9.79249 6.09344 9.88776 6.17964 9.9385 6.27224C10 6.38449 10 6.52299 10 6.79999V13.2C10 13.48 10 13.62 10.0545 13.727C10.1024 13.8211 10.1789 13.8976 10.273 13.9455C10.38 14 10.52 14 10.8 14H17.2Z"/><path d="M14 2.79999C14 2.52298 14 2.38448 14.0615 2.27223C14.1122 2.17963 14.2075 2.09344 14.3047 2.0522C14.4225 2.0022 14.5479 2.01478 14.7987 2.03993C16.6271 2.22333 18.346 3.03229 19.6569 4.34313C20.9677 5.65398 21.7767 7.37289 21.9601 9.20129C21.9852 9.45206 21.9978 9.57744 21.9478 9.69527C21.9066 9.79248 21.8204 9.88774 21.7278 9.93848C21.6155 9.99998 21.477 9.99999 21.2 9.99999L14.8 9.99999C14.52 9.99999 14.38 9.99999 14.273 9.94549C14.1789 9.89755 14.1024 9.82106 14.0545 9.72698C14 9.62003 14 9.48001 14 9.19999V2.79999Z"/></svg></a>
      <div class="di" title="Labor Market Reports"><svg viewBox="0 0 24 24"><path d="M18 12C20 10 22 8.20914 22 6C22 3.79086 20.2091 2 18 2C15.7909 2 14 3.79086 14 6C14 8.20914 16 10 18 12Z"/><circle cx="18" cy="6" r="1" fill="currentColor"/><path d="M2 4C2 2.89543 2.89543 2 4 2H6C7.10457 2 8 2.89543 8 4V22H2V4Z"/><path d="M8 14C8 12.8954 8.89543 12 10 12H12C13.1046 12 14 12.8954 14 14V22H8V14Z"/><path d="M14 19C14 17.8954 14.8954 17 16 17H18C19.1046 17 20 17.8954 20 19V22H14V19Z"/></svg></div>
      <a class="di" title="My AI Recruiting Team"><svg viewBox="0 0 24 24"><path d="M12 15H8C6.13623 15 5.20435 15 4.46927 15.3045C3.48915 15.7105 2.71046 16.4892 2.30448 17.4693C2 18.2044 2 19.1362 2 21M15.5 3.29076C16.9659 3.88415 18 5.32131 18 7C18 8.67869 16.9659 10.1159 15.5 10.7092M13.5 7C13.5 9.20914 11.7091 11 9.5 11C7.29086 11 5.5 9.20914 5.5 7C5.5 4.79086 7.29086 3 9.5 3C11.7091 3 13.5 4.79086 13.5 7Z"/><path d="M20.3643 11.0513C20.4355 11.0939 20.4905 11.1601 20.5205 11.2391C20.5505 11.3181 20.5536 11.4052 20.5294 11.4863L19.2196 15.8751H21.6362C21.7073 15.875 21.7767 15.8964 21.8361 15.9367C21.8954 15.9769 21.9421 16.0341 21.9702 16.1014C21.9984 16.1686 22.0068 16.2429 21.9945 16.315C21.9822 16.3871 21.9497 16.454 21.9009 16.5073L16.083 22.8819C16.0267 22.9436 15.9518 22.9839 15.8705 22.9961C15.7891 23.0083 15.7062 22.9917 15.6352 22.9491C15.5642 22.9065 15.5092 22.8403 15.4794 22.7614C15.4495 22.6824 15.4464 22.5954 15.4706 22.5144L16.7804 18.1249H14.3638C14.2927 18.125 14.2233 18.1035 14.1639 18.0633C14.1046 18.0231 14.0579 17.9658 14.0298 17.8986C14.0016 17.8314 13.9932 17.7571 14.0055 17.685C14.0178 17.6128 14.0503 17.546 14.0991 17.4927L19.917 11.1181C19.9732 11.0564 20.048 11.0162 20.1292 11.004C20.2104 10.9917 20.2933 11.0088 20.3643 11.0513Z" fill="currentColor" stroke="none"/></svg></a>
    </div>
    <div class="bot">
      <div class="slots"><span>Job Slots</span><b>8/30</b></div>
      <div class="di mb2" title="Referral"><svg viewBox="0 0 24 24" style="stroke:#53D58B;color:#53D58B"><path d="M12 6V22M12 6H8.46429C7.94332 6 7.4437 5.78929 7.07533 5.41421C6.70695 5.03914 6.5 4.53043 6.5 4C6.5 3.46957 6.70695 2.96086 7.07533 2.58579C7.4437 2.21071 7.94332 2 8.46429 2C11.2143 2 12 6 12 6ZM12 6H15.5357C16.0567 6 16.5563 5.78929 16.9247 5.41421C17.293 5.03914 17.5 4.53043 17.5 4C17.5 3.46957 17.293 2.96086 16.9247 2.58579C16.5563 2.21071 16.0567 2 15.5357 2C12.7857 2 12 6 12 6ZM20 11V18.8C20 19.9201 20 20.4802 19.782 20.908C19.5903 21.2843 19.2843 21.5903 18.908 21.782C18.4802 22 17.9201 22 16.8 22L7.2 22C6.07989 22 5.51984 22 5.09202 21.782C4.71569 21.5903 4.40973 21.2843 4.21799 20.908C4 20.4802 4 19.9201 4 18.8V11M2 7.6L2 9.4C2 9.96005 2 10.2401 2.10899 10.454C2.20487 10.6422 2.35785 10.7951 2.54601 10.891C2.75992 11 3.03995 11 3.6 11L20.4 11C20.9601 11 21.2401 11 21.454 10.891C21.6422 10.7951 21.7951 10.6422 21.891 10.454C22 10.2401 22 9.96005 22 9.4V7.6C22 7.03995 22 6.75992 21.891 6.54601C21.7951 6.35785 21.6422 6.20487 21.454 6.10899C21.2401 6 20.9601 6 20.4 6L3.6 6C3.03995 6 2.75992 6 2.54601 6.10899C2.35785 6.20487 2.20487 6.35785 2.10899 6.54601C2 6.75992 2 7.03995 2 7.6Z"/></svg></div>
      <div class="di mb2" title="Invite Teammate"><svg viewBox="0 0 24 24"><path d="M12 15.5H7.5C6.10444 15.5 5.40665 15.5 4.83886 15.6722C3.56045 16.06 2.56004 17.0605 2.17224 18.3389C2 18.9067 2 19.6044 2 21M19 21V15M16 18H22M14.5 7.5C14.5 9.98528 12.4853 12 10 12C7.51472 12 5.5 9.98528 5.5 7.5C5.5 5.01472 7.51472 3 10 3C12.4853 3 14.5 5.01472 14.5 7.5Z"/></svg></div>
      <div class="di mb2" title="Hide sensitive data"><svg viewBox="0 0 24 24"><path d="M2.42 12.7135C2.28795 12.4975 2.22192 12.3895 2.18348 12.2338C2.15539 12.1215 2.15539 11.8785 2.18348 11.7662C2.22192 11.6105 2.28795 11.5025 2.42 11.2865C3.53529 9.50484 6.8155 5 12 5C17.1845 5 20.4647 9.50484 21.58 11.2865C21.7121 11.5025 21.7781 11.6105 21.8165 11.7662C21.8446 11.8785 21.8446 12.1215 21.8165 12.2338C21.7781 12.3895 21.7121 12.4975 21.58 12.7135C20.4647 14.4952 17.1845 19 12 19C6.8155 19 3.53529 14.4952 2.42 12.7135Z"/><path d="M12 15C13.6569 15 15 13.6569 15 12C15 10.3431 13.6569 9 12 9C10.3431 9 9 10.3431 9 12C9 13.6569 10.3431 15 12 15Z"/></svg></div>
      <div class="avatar" title="Account"><i>AP</i></div>
    </div>
  `;
  return <aside className="ffnav" dangerouslySetInnerHTML={{ __html: html }}/>;
}

/* ============================================================
   SpectrumButton — one option on the fused→disentangled axis
   ============================================================ */
function SpectrumButton({ n, label, tag, desc, hot, onClick }){
  const [hover, setHover] = React.useState(false);
  return (
    <button onClick={onClick}
      onMouseEnter={()=>setHover(true)} onMouseLeave={()=>setHover(false)}
      style={{
        display:'block', width:'100%', textAlign:'left', marginBottom:6,
        padding:'9px 11px', cursor:'pointer',
        background: hover ? AC.tint[20] : '#fff',
        border:`1px solid ${hover ? AC.shade[840] : AC.tint[80]}`,
        borderRadius:8,
      }}>
      <div style={{ display:'flex', alignItems:'center', gap:8, marginBottom:3 }}>
        <span style={{
          fontFamily:'ui-monospace,SFMono-Regular,monospace', fontSize:10,
          fontWeight:700, color: AC.shade[600], flex:'none',
        }}>{n}</span>
        <span style={{ fontSize:13, fontWeight:700, color: AC.shade[880], flex:1 }}>{label}</span>
        <span style={{
          fontSize:9.5, fontWeight:700, letterSpacing:'.04em', textTransform:'uppercase',
          padding:'2px 6px', borderRadius:9999, flex:'none',
          background: hot ? AC.critical[50] : AC.tint[40],
          color: hot ? AC.critical[700] : AC.shade[700],
        }}>{tag}</span>
      </div>
      <div style={{ fontSize:11, lineHeight:1.4, color: AC.shade[700] }}>{desc}</div>
    </button>
  );
}

ReactDOM.createRoot(document.getElementById('app')).render(<App/>);
