// portal.jsx — OnboardIQ new-hire portal
// Separate shell from the admin app. Mobile-first (390). White-label by default.
//
// Three screens in this prototype: welcome / tasks / sign.
// Screen switcher lives in the tweaks panel.
//
// Brand-token system: customer name, glyph, accent. Tweak flips white-label
// on/off + swaps customer preset. OnboardIQ attribution lives in the footer.

// ─── brand presets ──────────────────────────────────────────
const BRANDS = {
  meridian: {
    name: "Meridian Federal",
    short: "Meridian",
    glyph: "M",
    accent:   "#1A3A52",     // institutional blue
    accent100:"#D7DEE9",
    accent50: "#E9EDF2",
    accent700:"#0E2538",
    sector:  "Federal contractor",
    domain:  "onboarding.meridianfed.com",
    privacyHref: "meridianfed.com/privacy",
    hrName: "Sarah Chen",
    hrTitle: "Director of People Operations",
    hrAvatar: "Sarah Chen",
    handbookName: "Meridian Federal Employee Handbook · 2026 edition",
  },
  northwind: {
    name: "Northwind PEO",
    short: "Northwind",
    glyph: "N",
    accent:   "#2D5F3D",     // forest
    accent100:"#D9E5DC",
    accent50: "#EAF0EC",
    accent700:"#1B3E27",
    sector:  "Professional employer org",
    domain:  "onboarding.northwindpeo.com",
    privacyHref: "northwindpeo.com/privacy",
    hrName: "James Mwangi",
    hrTitle: "PEO Onboarding Lead",
    hrAvatar: "James Mwangi",
    handbookName: "Northwind PEO Standard Handbook · client edition",
  },
  hyperion: {
    name: "Hyperion Health",
    short: "Hyperion",
    glyph: "H",
    accent:   "#1F5773",     // medical teal
    accent100:"#D5E1E9",
    accent50: "#E7EDF1",
    accent700:"#11364A",
    sector:  "Regional healthcare network",
    domain:  "onboarding.hyperionhealth.org",
    privacyHref: "hyperionhealth.org/privacy",
    hrName: "Diane Volkov",
    hrTitle: "Clinical Onboarding Coordinator",
    hrAvatar: "Diane Volkov",
    handbookName: "Hyperion Health · Clinical & Administrative Handbook · 2026",
  },
  // OnboardIQ default (when white-label is OFF)
  oiq: {
    name: "OnboardIQ",
    short: "OnboardIQ",
    glyph: "OI",
    accent:   "#437D6D",     // verdigris
    accent100:"#D6E5DF",
    accent50: "#E9F0EC",
    accent700:"#1F4A3F",
    sector:  "Default branding",
    domain:  "onboarding.onboardiq.app",
    privacyHref: "onboardiq.app/privacy",
    hrName: "Ren Mahoney",
    hrTitle: "HR Coordinator",
    hrAvatar: "Ren Mahoney",
    handbookName: "OnboardIQ Demo Handbook · v2026.04",
  },
};

function brandTokens(b) {
  return {
    '--brand-accent':     b.accent,
    '--brand-accent-100': b.accent100,
    '--brand-accent-50':  b.accent50,
    '--brand-accent-700': b.accent700,
  };
}

// ─── shell ─────────────────────────────────────────────────
function PortalShell({ brand, dark, back, children }) {
  return (
    <div className="oiq" data-theme={dark ? "dark" : "light"} data-accent="verdigris"
      style={{
        ...brandTokens(brand),
        background: 'var(--paper-50)',
        color: 'var(--ink-900)',
        minHeight: '100%',
        display: 'flex',
        flexDirection: 'column',
      }}>
      <PortalHeader brand={brand} back={back} />
      <div style={{ flex: 1 }}>{children}</div>
      <PortalFooter brand={brand} />
    </div>
  );
}

function PortalHeader({ brand, back }) {
  return (
    <header style={{
      position: 'sticky', top: 0, zIndex: 40,
      background: 'rgba(251,249,244,.94)',
      backdropFilter: 'blur(10px) saturate(160%)',
      WebkitBackdropFilter: 'blur(10px) saturate(160%)',
      borderBottom: '1px solid var(--paper-300)',
      padding: '14px 18px',
      display: 'flex', alignItems: 'center', gap: 12,
    }}>
      {back ? (
        <button onClick={back.onClick} style={{
          all: 'unset', cursor: 'pointer',
          width: 34, height: 34, borderRadius: 'var(--r-2)',
          display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
          color: 'var(--ink-700)',
          border: '1px solid var(--paper-300)',
        }}>
          <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="square"><path d="M15 5l-7 7 7 7" /></svg>
        </button>
      ) : null}
      <BrandLockup brand={brand} />
      <div style={{ flex: 1 }} />
      <button style={{
        all: 'unset', cursor: 'pointer',
        width: 34, height: 34, borderRadius: 'var(--r-2)',
        display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
        color: 'var(--ink-700)',
        border: '1px solid var(--paper-300)',
      }}>
        <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="square"><path d="M4 7h16M4 12h16M4 17h16" /></svg>
      </button>
    </header>
  );
}

function BrandLockup({ brand }) {
  const isOiq = brand.glyph === "OI";
  return (
    <div style={{ display: 'inline-flex', alignItems: 'center', gap: 8, minWidth: 0 }}>
      <span style={{
        width: isOiq ? 30 : 28, height: 28,
        display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
        background: 'var(--brand-accent)', color: '#FBF9F4',
        fontFamily: 'var(--mono)', fontSize: isOiq ? 10 : 13, fontWeight: 600,
        letterSpacing: '0.04em',
        borderRadius: 'var(--r-1)',
      }}>{brand.glyph}</span>
      <span style={{
        fontFamily: 'var(--sans)', fontSize: 14, fontWeight: 500,
        color: 'var(--ink-900)', letterSpacing: '-0.01em',
        overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap',
      }}>{brand.name}</span>
    </div>
  );
}

function PortalFooter({ brand }) {
  return (
    <footer style={{
      padding: '20px 18px 28px',
      borderTop: '1px solid var(--paper-300)',
      background: 'var(--paper-100)',
    }}>
      <div className="oiq-mono" style={{
        fontSize: 10, color: 'var(--ink-500)', letterSpacing: '0.04em',
        lineHeight: 1.6,
      }}>
        <div style={{ marginBottom: 4 }}>{brand.domain}</div>
        <div style={{ marginBottom: 10 }}>
          <a href="#" style={{ color: 'var(--ink-600)', textDecoration: 'underline', marginRight: 12 }}>privacy</a>
          <a href="#" style={{ color: 'var(--ink-600)', textDecoration: 'underline', marginRight: 12 }}>help</a>
          <a href="#" style={{ color: 'var(--ink-600)', textDecoration: 'underline' }}>contact</a>
        </div>
        <div style={{
          paddingTop: 10, borderTop: '1px solid var(--paper-300)',
          color: 'var(--ink-500)', fontSize: 9.5, letterSpacing: '0.06em',
          display: 'flex', alignItems: 'center', gap: 6,
        }}>
          {brand.glyph !== "OI" && (
            <React.Fragment>
              <span>Powered by</span>
              <Lockup size={11} color="var(--ink-700)" />
              <span>· An ITC product</span>
            </React.Fragment>
          )}
          {brand.glyph === "OI" && <span>© IT Custom Solution LLC · New York</span>}
        </div>
      </div>
    </footer>
  );
}

// ─── shared primitives ────────────────────────────────────
function BrandBtn({ children, full, kind = "primary", disabled, onClick, icon }) {
  const base = {
    display: 'inline-flex', alignItems: 'center', justifyContent: 'center', gap: 8,
    fontFamily: 'var(--sans)', fontWeight: 500, fontSize: 15,
    padding: '14px 18px', minHeight: 48,
    borderRadius: 'var(--r-2)',
    border: '1px solid transparent',
    cursor: disabled ? 'not-allowed' : 'pointer',
    opacity: disabled ? 0.5 : 1,
    width: full ? '100%' : 'auto',
    letterSpacing: '-0.005em',
    transition: 'background 120ms, color 120ms',
  };
  const styles = kind === "primary" ? {
    background: 'var(--brand-accent)', color: '#FBF9F4',
  } : kind === "secondary" ? {
    background: 'var(--paper-50)', color: 'var(--ink-900)', borderColor: 'var(--paper-400)',
  } : {
    background: 'transparent', color: 'var(--ink-700)',
  };
  return (
    <button onClick={onClick} disabled={disabled} style={{ ...base, ...styles }}>
      {icon}
      <span>{children}</span>
    </button>
  );
}

function ProgressStrip({ done, total, brand }) {
  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline' }}>
        <span className="oiq-mono" style={{ fontSize: 10.5, color: 'var(--ink-500)', letterSpacing: '0.08em', textTransform: 'uppercase' }}>progress</span>
        <span className="oiq-mono oiq-tabular" style={{ fontSize: 12, color: 'var(--ink-900)' }}>
          {done} of {total} complete · {total - done} to go
        </span>
      </div>
      <div style={{ display: 'flex', gap: 4 }}>
        {Array.from({ length: total }).map((_, i) => (
          <div key={i} style={{
            flex: 1, height: 6, borderRadius: 999,
            background: i < done ? 'var(--brand-accent)' : 'var(--paper-200)',
            border: i < done ? 'none' : '1px solid var(--paper-300)',
          }} />
        ))}
      </div>
    </div>
  );
}

// ─── tasks data ───────────────────────────────────────────
const TASKS = [
  { n: "01", type: "sig",   title: "Sign your offer letter",            time: "2 min",  status: "complete", note: "Signed Friday, May 9 at 4:42 PM" },
  { n: "02", type: "form",  title: "Fill out Form I-9 Section 1",       time: "5 min",  status: "complete", note: "Submitted Friday, May 9 at 5:01 PM" },
  { n: "03", type: "form",  title: "Set up direct deposit",             time: "3 min",  status: "complete", note: "Bank verified · ending in 4421" },
  { n: "04", type: "sig",   title: "Acknowledge the employee handbook", time: "10 min", status: "next",     note: "Read and sign. Includes the code of conduct and the IP assignment clause." },
  { n: "05", type: "eq",    title: "Order your equipment",              time: "4 min",  status: "locked",   note: "Locked until you finish the handbook acknowledgement." },
  { n: "06", type: "check", title: "Schedule your Day-1 orientation",   time: "2 min",  status: "waiting",  note: "Waiting on Meridian Federal to confirm available times for Monday." },
];

// ─── SCREEN 1 · welcome ─────────────────────────────────
function WelcomeScreen({ brand, goTo }) {
  const nextTask = TASKS.find(t => t.status === "next");
  const done = TASKS.filter(t => t.status === "complete").length;
  const total = TASKS.length;
  return (
    <div style={{ padding: '24px 18px 28px', display: 'flex', flexDirection: 'column', gap: 24 }}>

      {/* Greeting */}
      <div>
        <div className="oiq-mono" style={{ fontSize: 10.5, color: 'var(--ink-500)', letterSpacing: '0.08em', textTransform: 'uppercase', marginBottom: 8 }}>
          {brand.short.toLowerCase()} · onboarding
        </div>
        <h1 className="oiq-display" style={{
          fontSize: 38, lineHeight: 1.02, letterSpacing: '-0.025em',
          fontWeight: 500, color: 'var(--ink-900)', margin: 0,
        }}>
          Welcome, Daniel.
        </h1>
        <p style={{
          fontSize: 15.5, lineHeight: 1.55, color: 'var(--ink-700)',
          marginTop: 14, marginBottom: 0, letterSpacing: '-0.005em',
        }}>
          {brand.name} is getting you ready for your start date on{' '}
          <span style={{ color: 'var(--ink-900)', fontWeight: 500 }}>Monday, May 26</span>.
        </p>
      </div>

      <ProgressStrip done={done} total={total} brand={brand} />

      {/* Next-up card */}
      <div style={{
        border: '1px solid var(--paper-300)',
        borderLeft: '4px solid var(--brand-accent)',
        borderRadius: 'var(--r-2)',
        padding: '16px 16px 18px',
        background: 'var(--paper-50)',
        display: 'flex', flexDirection: 'column', gap: 12,
      }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
          <span className="oiq-mono" style={{ fontSize: 9.5, color: 'var(--brand-accent)', letterSpacing: '0.1em', textTransform: 'uppercase', fontWeight: 600 }}>up next</span>
          <span className="oiq-mono" style={{ fontSize: 10, color: 'var(--ink-500)', letterSpacing: '0.04em' }}>· task {nextTask.n} of {total} · {nextTask.time}</span>
        </div>
        <div style={{ fontSize: 19, fontWeight: 500, color: 'var(--ink-900)', letterSpacing: '-0.015em', lineHeight: 1.25 }}>
          {nextTask.title}.
        </div>
        <div style={{ fontSize: 13.5, color: 'var(--ink-700)', lineHeight: 1.5 }}>
          {nextTask.note}
        </div>
        <BrandBtn full onClick={() => goTo('tasks')}>
          Open task
          <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="square"><path d="M9 5l7 7-7 7" /></svg>
        </BrandBtn>
      </div>

      {/* Timeline preview */}
      <div>
        <div className="oiq-mono" style={{ fontSize: 10, color: 'var(--ink-500)', letterSpacing: '0.08em', textTransform: 'uppercase', marginBottom: 10 }}>
          your first 90 days
        </div>
        <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
          {[
            { d: "Day 1",  l: "Onboarding day · in-office at Arlington" },
            { d: "Day 30", l: "Manager check-in · with Theo Bramwell" },
            { d: "Day 90", l: "Goal review · 30/60/90 plan complete" },
          ].map(s => (
            <div key={s.d} style={{
              display: 'grid', gridTemplateColumns: '64px 1fr',
              gap: 10, alignItems: 'center',
              padding: '10px 12px',
              background: 'var(--paper-100)',
              border: '1px solid var(--paper-300)',
              borderRadius: 'var(--r-2)',
            }}>
              <span className="oiq-mono" style={{ fontSize: 11, color: 'var(--brand-accent)', fontWeight: 600, letterSpacing: '0.04em' }}>{s.d}</span>
              <span style={{ fontSize: 13, color: 'var(--ink-800)' }}>{s.l}</span>
            </div>
          ))}
        </div>
      </div>

      {/* HR contact */}
      <div style={{
        border: '1px solid var(--paper-300)',
        borderRadius: 'var(--r-2)',
        padding: '14px 16px',
        background: 'var(--brand-accent-50)',
        display: 'flex', alignItems: 'center', gap: 12,
      }}>
        <Avatar name={brand.hrAvatar} size={36} color="var(--brand-accent)" />
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ fontSize: 13.5, color: 'var(--ink-900)', fontWeight: 500, lineHeight: 1.3 }}>
            Stuck? Message {brand.hrName.split(' ')[0]}.
          </div>
          <div style={{ fontSize: 11.5, color: 'var(--ink-700)', lineHeight: 1.4, marginTop: 2 }}>
            {brand.hrTitle}, {brand.short}. Reply within 4 business hours.
          </div>
        </div>
        <button style={{
          all: 'unset', cursor: 'pointer',
          padding: '6px 10px',
          background: 'var(--paper-50)',
          border: '1px solid var(--paper-300)',
          borderRadius: 'var(--r-1)',
          fontFamily: 'var(--sans)', fontSize: 12, fontWeight: 500,
          color: 'var(--ink-900)',
        }}>
          Message
        </button>
      </div>

      {/* Earned photo slot */}
      <PhotoSlot
        kind="portal · onboarding"
        aspect="5/3"
        src="/photos/phone-onboarding.jpg"
        alt="Hands holding a phone mid-task, blurred workspace background, no face visible"
        objectPosition="center 35%"
        subject="A real new hire reading their onboarding email on their phone, mid-commute. Setting: commuter train window seat at morning light, or kitchen counter with breakfast and a mug, or a couch with a laptop closed beside them. Not a posed business shot, not a smiling-at-camera frame. Phone screen is the subject; the person is anonymous from the elbow up."
        treatment="Documentary editorial. Available light, warm. Subject's hands and phone in focus; the surroundings are real and unstaged. Vertical-friendly crop available for mobile-only contexts. Use across /portal welcome, /onboarding marketing pages, and on customer-facing 'your first day with us' emails."
        dims="1600 × 960"
      />

      {/* All tasks link */}
      <button onClick={() => goTo('tasks')} style={{
        all: 'unset', cursor: 'pointer',
        padding: '14px 16px',
        textAlign: 'center',
        border: '1px solid var(--paper-300)',
        borderRadius: 'var(--r-2)',
        fontFamily: 'var(--sans)', fontSize: 14, fontWeight: 500,
        color: 'var(--ink-900)',
        background: 'var(--paper-50)',
      }}>
        See all your tasks →
      </button>
    </div>
  );
}

// ─── SCREEN 2 · tasks ───────────────────────────────────
function TasksScreen({ brand, goTo }) {
  const done = TASKS.filter(t => t.status === "complete").length;
  return (
    <div style={{ padding: '20px 18px 28px', display: 'flex', flexDirection: 'column', gap: 20 }}>
      <div>
        <h1 className="oiq-display" style={{
          fontSize: 32, lineHeight: 1.04, letterSpacing: '-0.025em',
          fontWeight: 500, color: 'var(--ink-900)', margin: 0,
        }}>
          Your tasks.
        </h1>
        <p style={{
          fontSize: 14.5, lineHeight: 1.5, color: 'var(--ink-700)',
          marginTop: 10, marginBottom: 0,
        }}>
          In order. Top to bottom. Each one tells you when you'll need to come back if anything's
          pending.
        </p>
      </div>

      <ProgressStrip done={done} total={TASKS.length} brand={brand} />

      <ol style={{ listStyle: 'none', padding: 0, margin: 0, display: 'flex', flexDirection: 'column', gap: 10 }}>
        {TASKS.map(t => <TaskRow key={t.n} task={t} goTo={goTo} />)}
      </ol>

      <div className="oiq-mono" style={{
        marginTop: 4, padding: '12px 14px',
        background: 'var(--paper-100)',
        border: '1px solid var(--paper-300)',
        borderRadius: 'var(--r-2)',
        fontSize: 10.5, color: 'var(--ink-600)', lineHeight: 1.55,
      }}>
        tip · you can pause and come back. progress is saved.
        nothing is submitted until you tap submit on the task itself.
      </div>
    </div>
  );
}

function TaskRow({ task, goTo }) {
  const STATUS = {
    complete: { label: "complete", color: "var(--green-500)", bg: "var(--green-100)", fg: "var(--green-700)", border: "var(--paper-300)" },
    next:     { label: "next",     color: "var(--brand-accent)", bg: "var(--brand-accent-100)", fg: "var(--brand-accent-700)", border: "var(--brand-accent)" },
    locked:   { label: "locked",   color: "var(--ink-400)", bg: "var(--paper-200)", fg: "var(--ink-600)", border: "var(--paper-300)" },
    waiting:  { label: "waiting",  color: "var(--accent-500)", bg: "var(--amber-100)", fg: "var(--amber-700)", border: "var(--paper-300)" },
  }[task.status];

  const isClickable = task.status === "next" || task.status === "complete";

  return (
    <li>
      <button onClick={() => isClickable && goTo('sign')} disabled={!isClickable} style={{
        all: 'unset',
        display: 'block', width: '100%',
        cursor: isClickable ? 'pointer' : 'default',
        padding: '16px 16px 18px',
        background: 'var(--paper-50)',
        border: '1px solid ' + (task.status === "next" ? 'var(--brand-accent)' : 'var(--paper-300)'),
        borderLeftWidth: task.status === "next" ? 4 : 1,
        borderRadius: 'var(--r-2)',
        opacity: task.status === "locked" ? 0.7 : 1,
      }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 8 }}>
          <span className="oiq-mono" style={{ fontSize: 11, color: 'var(--ink-500)', letterSpacing: '0.08em' }}>{task.n}</span>
          <span style={{ color: 'var(--ink-700)' }}><StepIcon type={task.type} size={14} /></span>
          <span style={{ flex: 1 }} />
          <span className="oiq-mono" style={{
            fontSize: 9.5, padding: '2px 8px',
            background: STATUS.bg, color: STATUS.fg,
            letterSpacing: '0.08em', textTransform: 'uppercase',
            borderRadius: 'var(--r-pill)', fontWeight: 600,
          }}>{STATUS.label}</span>
        </div>
        <div style={{
          fontSize: 16, fontWeight: 500, color: 'var(--ink-900)',
          letterSpacing: '-0.01em', lineHeight: 1.3,
        }}>{task.title}.</div>
        <div style={{
          marginTop: 6, fontSize: 12.5, color: 'var(--ink-600)', lineHeight: 1.5,
        }}>{task.note}</div>
        {task.status !== "locked" && task.status !== "waiting" && task.status !== "complete" && (
          <div style={{
            marginTop: 10, paddingTop: 10, borderTop: '1px solid var(--paper-200)',
            display: 'flex', alignItems: 'center', justifyContent: 'space-between',
          }}>
            <span className="oiq-mono" style={{ fontSize: 10.5, color: 'var(--ink-500)', letterSpacing: '0.04em' }}>~{task.time}</span>
            <span style={{ display: 'inline-flex', alignItems: 'center', gap: 6, fontSize: 12.5, color: 'var(--brand-accent)', fontWeight: 500 }}>
              open
              <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="square"><path d="M9 5l7 7-7 7" /></svg>
            </span>
          </div>
        )}
        {task.status === "complete" && (
          <div style={{
            marginTop: 10, paddingTop: 10, borderTop: '1px solid var(--paper-200)',
            display: 'inline-flex', alignItems: 'center', gap: 6, fontSize: 11.5, color: 'var(--green-700)',
          }}>
            <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="square"><path d="M4 12l5 5L20 6" /></svg>
            <span className="oiq-mono">view audit certificate</span>
          </div>
        )}
      </button>
    </li>
  );
}

// ─── SCREEN 3 · sign offer letter ────────────────────────
function SignScreen({ brand, goTo }) {
  const [scrolled, setScrolled] = React.useState(false);
  const [name, setName]         = React.useState('');
  const [signed, setSigned]     = React.useState(false);
  const [done, setDone]         = React.useState(false);

  const allReady = scrolled && name.trim().length >= 4 && signed && !done;

  const onSubmit = () => setDone(true);

  if (done) return <SignComplete brand={brand} goTo={goTo} name={name} />;

  return (
    <div style={{ padding: '16px 18px 28px', display: 'flex', flexDirection: 'column', gap: 18 }}>
      <button onClick={() => goTo('tasks')} style={{
        all: 'unset', cursor: 'pointer',
        display: 'inline-flex', alignItems: 'center', gap: 6,
        fontSize: 13, color: 'var(--ink-600)',
        fontFamily: 'var(--sans)',
      }}>
        <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="square"><path d="M15 5l-7 7 7 7" /></svg>
        Back to your tasks
      </button>

      <div>
        <div className="oiq-mono" style={{ fontSize: 10, color: 'var(--ink-500)', letterSpacing: '0.08em', textTransform: 'uppercase', marginBottom: 8 }}>
          task 01 of 06 · e-signature
        </div>
        <h1 className="oiq-display" style={{
          fontSize: 30, lineHeight: 1.04, letterSpacing: '-0.025em',
          fontWeight: 500, color: 'var(--ink-900)', margin: 0,
        }}>
          Sign your offer letter.
        </h1>
        <p style={{
          fontSize: 14.5, lineHeight: 1.55, color: 'var(--ink-700)',
          marginTop: 10, marginBottom: 0,
        }}>
          This is the binding agreement between you and {brand.name}. Take the time you need.
        </p>
      </div>

      {/* Three-step status */}
      <div style={{
        padding: '12px 14px',
        background: 'var(--paper-100)',
        border: '1px solid var(--paper-300)',
        borderRadius: 'var(--r-2)',
        display: 'flex', flexDirection: 'column', gap: 8,
      }}>
        <CeremonyStep n="1" label="Read the document" done={scrolled} />
        <CeremonyStep n="2" label="Confirm your legal name" done={name.trim().length >= 4} />
        <CeremonyStep n="3" label="Sign" done={signed} />
      </div>

      {/* Offer letter document */}
      <OfferLetter brand={brand} onReachEnd={() => setScrolled(true)} />

      {/* Identity confirm */}
      <div>
        <label className="oiq-mono" style={{ fontSize: 10, color: 'var(--ink-500)', letterSpacing: '0.08em', textTransform: 'uppercase' }}>type your full legal name</label>
        <input
          type="text"
          value={name}
          onChange={(e) => setName(e.target.value)}
          placeholder="Daniel A. Okafor"
          style={{
            width: '100%', marginTop: 6,
            padding: '12px 14px',
            background: 'var(--paper-50)',
            border: '1.5px solid var(--paper-300)',
            borderRadius: 'var(--r-2)',
            fontFamily: 'var(--sans)', fontSize: 16, color: 'var(--ink-900)',
            outline: 'none',
            boxSizing: 'border-box',
          }}
        />
        <div className="oiq-mono" style={{ fontSize: 10, color: 'var(--ink-500)', marginTop: 6, letterSpacing: '0.02em' }}>
          must match the name on the offer letter exactly
        </div>
      </div>

      {/* Signature pad */}
      <SignaturePad
        name={name}
        signed={signed}
        setSigned={setSigned}
        scrolled={scrolled}
      />

      {/* Audit-trail disclosure */}
      <div className="oiq-mono" style={{
        padding: '12px 14px',
        background: 'var(--paper-100)',
        border: '1px solid var(--paper-300)',
        borderRadius: 'var(--r-2)',
        fontSize: 10.5, color: 'var(--ink-600)', lineHeight: 1.6,
      }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 6, color: 'var(--ink-900)', marginBottom: 6, fontWeight: 600 }}>
          <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="square"><rect x="5" y="11" width="14" height="10" /><path d="M8 11V7a4 4 0 018 0v4" /></svg>
          chain of custody
        </div>
        this signature will be captured with timestamp, ip address, device fingerprint, and a
        cryptographic hash of the document. the audit certificate will be available to download
        after completion.
      </div>

      <BrandBtn full disabled={!allReady} onClick={onSubmit}>
        Sign offer letter
        <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="square"><path d="M4 12l5 5L20 6" /></svg>
      </BrandBtn>
    </div>
  );
}

function CeremonyStep({ n, label, done }) {
  return (
    <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
      <span style={{
        width: 20, height: 20, borderRadius: '50%',
        background: done ? 'var(--brand-accent)' : 'transparent',
        border: done ? 'none' : '1.5px solid var(--paper-400)',
        color: '#FBF9F4',
        display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
        flexShrink: 0,
      }}>
        {done && <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.4" strokeLinecap="square"><path d="M4 12l5 5L20 6" /></svg>}
      </span>
      <span style={{ fontSize: 13, color: done ? 'var(--ink-900)' : 'var(--ink-600)', fontWeight: done ? 500 : 400 }}>{label}</span>
    </div>
  );
}

// ─── offer letter (Plex Serif body for document feel) ────
function OfferLetter({ brand, onReachEnd }) {
  const scrollRef = React.useRef(null);
  React.useEffect(() => {
    const el = scrollRef.current;
    if (!el) return;
    const handle = () => {
      if (el.scrollTop + el.clientHeight >= el.scrollHeight - 20) onReachEnd();
    };
    el.addEventListener('scroll', handle);
    return () => el.removeEventListener('scroll', handle);
  }, [onReachEnd]);

  return (
    <div style={{
      border: '1.5px solid var(--paper-400)',
      borderRadius: 'var(--r-2)',
      background: 'var(--paper-50)',
      overflow: 'hidden',
      boxShadow: 'var(--shadow-2)',
    }}>
      {/* Document chrome */}
      <div style={{
        display: 'flex', alignItems: 'center', gap: 8,
        padding: '8px 12px',
        background: 'var(--paper-100)',
        borderBottom: '1px solid var(--paper-300)',
      }}>
        <Icon name="documents" size={12} />
        <span className="oiq-mono" style={{ fontSize: 9.5, color: 'var(--ink-700)', letterSpacing: '0.08em', textTransform: 'uppercase' }}>
          offer letter · {brand.short.toLowerCase()} · v2
        </span>
        <span style={{ flex: 1 }} />
        <span className="oiq-mono" style={{ fontSize: 9, color: 'var(--ink-500)' }}>scroll to end</span>
      </div>

      {/* Scrollable document body */}
      <div ref={scrollRef} style={{
        height: 360,
        overflowY: 'auto',
        background: 'var(--paper-50)',
      }}>
        <div style={{ padding: '24px 22px' }}>

          {/* Letterhead */}
          <div style={{ display: 'flex', alignItems: 'center', gap: 10, paddingBottom: 16, borderBottom: '1px solid var(--paper-300)' }}>
            <span style={{
              width: 36, height: 36,
              display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
              background: 'var(--brand-accent)', color: '#FBF9F4',
              fontFamily: 'var(--mono)', fontSize: 16, fontWeight: 600,
              borderRadius: 'var(--r-1)',
            }}>{brand.glyph}</span>
            <div>
              <div style={{ fontFamily: 'var(--sans)', fontSize: 15, fontWeight: 600, color: 'var(--ink-900)', letterSpacing: '-0.01em' }}>{brand.name}</div>
              <div className="oiq-mono" style={{ fontSize: 9.5, color: 'var(--ink-500)' }}>{brand.sector.toLowerCase()} · arlington va</div>
            </div>
          </div>

          {/* Letter body in Plex Serif */}
          <div style={{ fontFamily: 'var(--serif)', fontSize: 14, lineHeight: 1.65, color: 'var(--ink-900)', marginTop: 18 }}>
            <div style={{ marginBottom: 14, fontFamily: 'var(--mono)', fontSize: 10.5, color: 'var(--ink-600)', letterSpacing: '0.04em' }}>
              MAY 9, 2026
            </div>

            <p style={{ margin: '0 0 12px' }}>Daniel A. Okafor<br/>1422 Quincy Street NW<br/>Washington, DC 20011</p>

            <p style={{ margin: '0 0 14px', fontWeight: 500 }}>
              Re: Offer of Employment, Cloud Engineer
            </p>

            <p style={{ margin: '0 0 14px' }}>Dear Daniel,</p>

            <p style={{ margin: '0 0 14px' }}>
              On behalf of {brand.name}, I am pleased to offer you the position of{' '}
              <span style={{ fontWeight: 500 }}>Cloud Engineer</span>, reporting to{' '}
              <span style={{ fontWeight: 500 }}>Theo Bramwell, Director of Infrastructure</span>.
              Your primary work location will be our Arlington, Virginia office, with hybrid flexibility
              of two days remote per week after the probationary period.
            </p>

            <p style={{ margin: '0 0 14px', fontWeight: 500 }}>Compensation and start date</p>
            <p style={{ margin: '0 0 14px' }}>
              Your annual base salary will be{' '}
              <span style={{ fontWeight: 500 }}>$145,000</span>, paid in twenty-six equal installments.
              You will be eligible for the company performance bonus pool, with a target of 10% of base
              salary, reviewed annually each February. Your start date is{' '}
              <span style={{ fontWeight: 500 }}>Monday, May 26, 2026</span>.
            </p>

            <p style={{ margin: '0 0 14px', fontWeight: 500 }}>Position contingencies</p>
            <p style={{ margin: '0 0 14px' }}>
              This offer is contingent upon the successful completion of (a) employment verification,
              including I-9 with E-Verify; (b) a standard pre-employment background check pursuant to
              the FCRA disclosure provided separately; and (c) verification of your interim Top Secret
              clearance, sponsored under contract designation 24-OPM-7714. Your access to classified
              systems will be limited until the final adjudication is received.
            </p>

            <p style={{ margin: '0 0 14px', fontWeight: 500 }}>Benefits</p>
            <p style={{ margin: '0 0 14px' }}>
              You are eligible to enroll in our medical, dental, and vision plans effective on your
              start date. We contribute 80% of the premium for employee-only coverage. The 401(k) plan
              includes a 4% match, vesting on a three-year graded schedule. You will accrue paid time
              off at the rate of 20 days per year, with 11 paid federal holidays.
            </p>

            <p style={{ margin: '0 0 14px', fontWeight: 500 }}>At-will employment</p>
            <p style={{ margin: '0 0 14px' }}>
              Your employment with {brand.name} is at-will, meaning either you or the company may
              terminate the employment relationship at any time, with or without cause or notice.
              Nothing in this letter creates an express or implied contract of employment for any
              specific duration.
            </p>

            <p style={{ margin: '0 0 14px', fontWeight: 500 }}>Acceptance</p>
            <p style={{ margin: '0 0 14px' }}>
              To accept this offer, please sign below by Friday, May 16, 2026. If you have any
              questions, contact {brand.hrName}, {brand.hrTitle}, at the address above.
            </p>

            <p style={{ margin: '0 0 8px' }}>Sincerely,</p>
            <p style={{ margin: '0 0 4px', fontStyle: 'italic', fontSize: 16 }}>{brand.hrName}</p>
            <div className="oiq-mono" style={{ fontSize: 9.5, color: 'var(--ink-500)', marginTop: 4, letterSpacing: '0.04em' }}>
              {brand.hrTitle.toUpperCase()} · {brand.short.toUpperCase()}
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}

// ─── signature pad ──────────────────────────────────────
function SignaturePad({ name, signed, setSigned, scrolled }) {
  const [mode, setMode] = React.useState('type');     // 'type' or 'draw'
  const canvasRef = React.useRef(null);
  const drawing = React.useRef(false);
  const [hasDrawing, setHasDrawing] = React.useState(false);

  const start = (e) => {
    if (!scrolled || !name) return;
    drawing.current = true;
    const ctx = canvasRef.current.getContext('2d');
    ctx.beginPath();
    const r = canvasRef.current.getBoundingClientRect();
    const pt = e.touches ? e.touches[0] : e;
    ctx.moveTo(pt.clientX - r.left, pt.clientY - r.top);
  };
  const move = (e) => {
    if (!drawing.current) return;
    e.preventDefault();
    const ctx = canvasRef.current.getContext('2d');
    const r = canvasRef.current.getBoundingClientRect();
    const pt = e.touches ? e.touches[0] : e;
    ctx.lineTo(pt.clientX - r.left, pt.clientY - r.top);
    ctx.strokeStyle = '#16140F';
    ctx.lineWidth = 2.4;
    ctx.lineCap = 'round';
    ctx.stroke();
    setHasDrawing(true);
  };
  const end = () => {
    if (drawing.current) {
      drawing.current = false;
      if (hasDrawing) setSigned(true);
    }
  };
  const clear = () => {
    const c = canvasRef.current;
    if (!c) return;
    c.getContext('2d').clearRect(0, 0, c.width, c.height);
    setHasDrawing(false);
    setSigned(false);
  };

  React.useEffect(() => {
    if (mode === 'type') setSigned(name.trim().length >= 4);
  }, [mode, name, setSigned]);

  const ready = scrolled && name.trim().length >= 4;

  return (
    <div>
      <div className="oiq-mono" style={{ fontSize: 10, color: 'var(--ink-500)', letterSpacing: '0.08em', textTransform: 'uppercase', marginBottom: 6 }}>
        sign · choose one
      </div>
      <div style={{ display: 'flex', gap: 6, marginBottom: 10 }}>
        {['type', 'draw'].map(m => (
          <button key={m} onClick={() => { setMode(m); clear(); setSigned(false); }} style={{
            all: 'unset', cursor: 'pointer',
            padding: '8px 14px',
            background: mode === m ? 'var(--ink-900)' : 'var(--paper-50)',
            color: mode === m ? 'var(--paper-50)' : 'var(--ink-700)',
            border: '1px solid ' + (mode === m ? 'var(--ink-900)' : 'var(--paper-300)'),
            borderRadius: 'var(--r-2)',
            fontFamily: 'var(--sans)', fontSize: 13, fontWeight: 500,
            textTransform: 'capitalize',
          }}>{m === 'type' ? 'Type signature' : 'Draw signature'}</button>
        ))}
      </div>

      {mode === 'type' ? (
        <div style={{
          border: '1.5px dashed var(--paper-400)',
          borderRadius: 'var(--r-2)',
          padding: '24px 18px',
          background: ready ? 'var(--paper-50)' : 'var(--paper-100)',
          textAlign: 'center',
          minHeight: 80,
          display: 'flex', alignItems: 'center', justifyContent: 'center',
        }}>
          {ready ? (
            <span style={{ fontFamily: 'var(--serif)', fontSize: 32, fontStyle: 'italic', color: 'var(--ink-900)', letterSpacing: '-0.01em' }}>
              {name}
            </span>
          ) : (
            <span className="oiq-mono" style={{ fontSize: 11, color: 'var(--ink-500)', letterSpacing: '0.04em' }}>
              {scrolled ? "type your full legal name above to confirm" : "scroll the offer letter to the end first"}
            </span>
          )}
        </div>
      ) : (
        <div>
          <div style={{
            border: '1.5px dashed var(--paper-400)',
            borderRadius: 'var(--r-2)',
            background: ready ? 'var(--paper-50)' : 'var(--paper-100)',
            position: 'relative',
            height: 140,
            touchAction: 'none',
          }}>
            <canvas
              ref={canvasRef}
              width={350} height={140}
              style={{ width: '100%', height: '100%', display: 'block', cursor: ready ? 'crosshair' : 'not-allowed' }}
              onMouseDown={start} onMouseMove={move} onMouseUp={end} onMouseLeave={end}
              onTouchStart={start} onTouchMove={move} onTouchEnd={end}
            />
            {!hasDrawing && (
              <div style={{
                position: 'absolute', inset: 0, pointerEvents: 'none',
                display: 'flex', alignItems: 'center', justifyContent: 'center',
              }}>
                <span className="oiq-mono" style={{ fontSize: 11, color: 'var(--ink-500)' }}>
                  {ready ? "draw your signature here" : "complete the steps above first"}
                </span>
              </div>
            )}
          </div>
          {hasDrawing && (
            <button onClick={clear} style={{
              all: 'unset', cursor: 'pointer',
              marginTop: 6, fontSize: 11, color: 'var(--ink-500)',
              textDecoration: 'underline',
            }}>clear signature</button>
          )}
        </div>
      )}
    </div>
  );
}

function SignComplete({ brand, goTo, name }) {
  return (
    <div style={{ padding: '40px 18px 28px', display: 'flex', flexDirection: 'column', gap: 22 }}>
      <div style={{
        width: 56, height: 56, borderRadius: '50%',
        background: 'var(--brand-accent)', color: '#FBF9F4',
        display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
      }}>
        <svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="square"><path d="M4 12l5 5L20 6" /></svg>
      </div>
      <div>
        <h1 className="oiq-display" style={{
          fontSize: 30, lineHeight: 1.04, letterSpacing: '-0.025em',
          fontWeight: 500, color: 'var(--ink-900)', margin: 0,
        }}>
          Offer letter signed.
        </h1>
        <p style={{
          fontSize: 14.5, lineHeight: 1.55, color: 'var(--ink-700)',
          marginTop: 10, marginBottom: 0,
        }}>
          Signed by <span style={{ color: 'var(--ink-900)', fontWeight: 500 }}>{name || "Daniel A. Okafor"}</span> on Monday, May 12 at 8:42 AM ET.
          Countersignature requested from {brand.hrName} at {brand.short}.
        </p>
      </div>

      <div style={{
        padding: '14px 16px',
        border: '1px solid var(--paper-300)',
        borderRadius: 'var(--r-2)',
        background: 'var(--paper-100)',
        display: 'flex', flexDirection: 'column', gap: 6,
      }}>
        <div className="oiq-mono" style={{ fontSize: 9.5, color: 'var(--ink-500)', letterSpacing: '0.08em', textTransform: 'uppercase' }}>audit certificate</div>
        <div className="oiq-mono" style={{ fontSize: 11, color: 'var(--ink-700)', lineHeight: 1.6 }}>
          sha-256 · 0x9e22…b41a<br/>
          rfc 3161 timestamp · 1747146126<br/>
          chain index · 14,329
        </div>
        <a href="#" style={{
          marginTop: 6, fontSize: 12.5, color: 'var(--ink-900)',
          textDecoration: 'none', borderBottom: '1px solid var(--ink-300)',
          paddingBottom: 2, alignSelf: 'flex-start',
        }}>
          Download certificate (PDF)
        </a>
      </div>

      <BrandBtn full onClick={() => goTo('tasks')}>Continue to next task</BrandBtn>
    </div>
  );
}

// ─── assembly ────────────────────────────────────────────
function Portal({ tweaks, setTweak }) {
  // Resolve brand
  const brand = tweaks.whitelabel
    ? BRANDS[tweaks.brand] || BRANDS.meridian
    : BRANDS.oiq;

  const goTo = (s) => setTweak('screen', s);
  const screen = tweaks.screen;

  return (
    <PortalShell brand={brand} dark={tweaks.dark} back={screen !== 'welcome' ? { onClick: () => goTo('welcome') } : null}>
      {screen === 'welcome' && <WelcomeScreen brand={brand} goTo={goTo} />}
      {screen === 'tasks'   && <TasksScreen   brand={brand} goTo={goTo} />}
      {screen === 'sign'    && <SignScreen    brand={brand} goTo={goTo} />}
    </PortalShell>
  );
}

Object.assign(window, { Portal, BRANDS });
