// =================================================================
// screens-auth.jsx — Unauthenticated full-page flows.
//
//   sign-in           SignInPage         email + password, OAuth, SSO
//   sign-up           SignUpPage         full sign-up form w/ strength meter
//   forgot-password   ForgotPasswordPage email entry → "check your inbox"
//   check-email       CheckEmailPage     post-submit confirmation
//   reset-password    ResetPasswordPage  new password + confirm
//   verify-email      VerifyEmailPage    6-digit code entry
//   two-factor        TwoFactorPage      2FA OTP after sign-in
//   sso               SsoSignInPage      enter org domain
//
// These render WITHOUT the app shell. app.jsx detects an AUTH_ROUTES
// hit and short-circuits the full layout in favor of <AuthLayout>.
// =================================================================

const AUTH_ROUTES = new Set([
  "sign-in", "sign-up",
  "forgot-password", "check-email", "reset-password",
  "verify-email", "two-factor",
  "sso",
]);

// ---------- Inline SVG marks (Google, GitHub, eye, etc.) ----------
const SvgGoogle = ({ size = 16 }) => (
  <svg width={size} height={size} viewBox="0 0 24 24" aria-hidden="true">
    <path fill="#4285F4" d="M23.49 12.27c0-.79-.07-1.54-.19-2.27H12v4.51h6.46c-.28 1.49-1.13 2.75-2.41 3.6v3h3.9c2.28-2.1 3.54-5.2 3.54-8.84Z"/>
    <path fill="#34A853" d="M12 24c3.24 0 5.96-1.08 7.95-2.91l-3.9-3c-1.08.72-2.46 1.16-4.05 1.16-3.12 0-5.76-2.1-6.7-4.94H1.27v3.09C3.25 21.31 7.31 24 12 24Z"/>
    <path fill="#FBBC05" d="M5.3 14.31c-.24-.72-.38-1.49-.38-2.31s.14-1.59.38-2.31V6.6H1.27C.46 8.22 0 10.06 0 12s.46 3.78 1.27 5.4l4.03-3.09Z"/>
    <path fill="#EA4335" d="M12 4.75c1.77 0 3.35.61 4.6 1.8l3.44-3.44C17.96 1.19 15.24 0 12 0 7.31 0 3.25 2.69 1.27 6.6L5.3 9.69C6.24 6.85 8.88 4.75 12 4.75Z"/>
  </svg>
);

const SvgGithub = ({ size = 16 }) => (
  <svg width={size} height={size} viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
    <path d="M12 .5C5.65.5.5 5.65.5 12c0 5.08 3.29 9.39 7.86 10.91.58.1.79-.25.79-.56v-2.16c-3.2.7-3.87-1.37-3.87-1.37-.52-1.33-1.27-1.68-1.27-1.68-1.04-.71.08-.7.08-.7 1.15.08 1.76 1.18 1.76 1.18 1.02 1.76 2.69 1.25 3.35.96.1-.74.4-1.25.73-1.54-2.56-.29-5.24-1.28-5.24-5.7 0-1.26.45-2.29 1.18-3.1-.12-.29-.51-1.46.11-3.04 0 0 .97-.31 3.18 1.18a11 11 0 0 1 5.78 0c2.2-1.49 3.17-1.18 3.17-1.18.63 1.58.23 2.75.12 3.04.74.81 1.18 1.84 1.18 3.1 0 4.43-2.69 5.41-5.25 5.69.41.36.78 1.06.78 2.14v3.18c0 .31.21.67.79.56C20.21 21.39 23.5 17.08 23.5 12 23.5 5.65 18.35.5 12 .5Z"/>
  </svg>
);

const SvgEye = ({ size = 14 }) => (
  <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
    <path d="M2 12s3.5-7 10-7 10 7 10 7-3.5 7-10 7S2 12 2 12Z"/><circle cx="12" cy="12" r="3"/>
  </svg>
);

const SvgEyeOff = ({ size = 14 }) => (
  <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
    <path d="M4 4l16 16"/><path d="M10.7 6.2A10.3 10.3 0 0 1 12 6c6.5 0 10 6 10 6a17 17 0 0 1-3.4 4"/><path d="M6.6 7.6A17 17 0 0 0 2 12s3.5 6 10 6c1.4 0 2.7-.3 3.8-.7"/><path d="M9.9 9.9a3 3 0 1 0 4.2 4.2"/>
  </svg>
);

const SvgMail = ({ size = 22 }) => (
  <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
    <rect x="3" y="5" width="18" height="14" rx="2"/><path d="m3 7 9 6 9-6"/>
  </svg>
);

const SvgLock = ({ size = 22 }) => (
  <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
    <rect x="5" y="11" width="14" height="9" rx="2"/><path d="M8 11V8a4 4 0 1 1 8 0v3"/>
  </svg>
);

// ---------- Shared layout ----------
const AuthLayout = ({ children, narrow }) => {
  const cfg = window.APP_CONFIG;
  return (
    <div className={`hx-auth ${narrow ? "hx-auth-narrow" : ""}`}>
      <section className="hx-auth-form-col">
        <a className="hx-auth-brand" href="#/sign-in" onClick={(e) => { e.preventDefault(); window.__nav("sign-in"); }}>
          {cfg.brand.showLogo && <Logo size={28}/>}
          <span className="hx-auth-brand-name">
            {cfg.brand.name}{cfg.brand.suffix && <span className="hx-auth-brand-dot">{cfg.brand.suffix}</span>}
          </span>
        </a>
        <div className="hx-auth-form-inner">
          {children}
        </div>
        <footer className="hx-auth-foot">
          <span>© 2026 {cfg.brand.productName}</span>
          <span className="hx-auth-foot-sep">·</span>
          <a href="#" onClick={(e) => e.preventDefault()}>Terms</a>
          <a href="#" onClick={(e) => e.preventDefault()}>Privacy</a>
          <a href="#" onClick={(e) => e.preventDefault()}>Status</a>
        </footer>
      </section>

      <aside className="hx-auth-side" aria-hidden="true">
        <div className="hx-auth-side-mesh"/>
        <div className="hx-auth-side-rings">
          <span/><span/><span/>
        </div>
        <div className="hx-auth-side-inner">
          <div className="hx-auth-side-eyebrow">{cfg.brand.productName} platform</div>
          <h2 className="hx-auth-side-title">
            Upload files, run scripts, and download clean catalogue outputs.
          </h2>
          <ul className="hx-auth-side-list">
            <li><span className="hx-auth-tick"><IconCheck size={11}/></span> Script runner for PDF, Excel, image, and catalogue workflows</li>
            <li><span className="hx-auth-tick"><IconCheck size={11}/></span> Credits, subscriptions, artifacts, and job history in one place</li>
            <li><span className="hx-auth-tick"><IconCheck size={11}/></span> Admin package approval, support, and usage analytics</li>
          </ul>
          <figure className="hx-auth-quote">
            <blockquote>
              "We turned price-list PDFs into clean Excel files with linked images and a repeatable workflow."
            </blockquote>
            <figcaption>
              <Avatar name="Priya Nair" size={32}/>
              <span>
                <span className="hx-auth-quote-name">Priya Nair</span>
                <span className="hx-auth-quote-role">Operations lead</span>
              </span>
            </figcaption>
          </figure>
        </div>
      </aside>

      <AuthStyles/>
    </div>
  );
};

// ---------- Header inside the form column ----------
const AuthHeader = ({ icon, title, subtitle }) => (
  <header className="hx-auth-head">
    {icon && <div className="hx-auth-head-icon">{icon}</div>}
    <h1>{title}</h1>
    {subtitle && <p>{subtitle}</p>}
  </header>
);

// ---------- Reusable bits ----------
const OauthRow = ({ disabled, mode = "sign-in" }) => {
  const verb = mode === "sign-up" ? "Sign up" : "Continue";
  return (
    <div className="hx-auth-oauth">
      <button type="button" className="hx-oauth-btn" disabled={disabled} onClick={() => window.__toast(`${verb} with Google (demo)`)}>
        <SvgGoogle size={16}/><span>Google</span>
      </button>
      <button type="button" className="hx-oauth-btn" disabled={disabled} onClick={() => window.__toast(`${verb} with GitHub (demo)`)}>
        <SvgGithub size={16}/><span>GitHub</span>
      </button>
      <button type="button" className="hx-oauth-btn" disabled={disabled} onClick={() => window.__nav("sso")}>
        <IconKey size={15}/><span>SSO</span>
      </button>
    </div>
  );
};

const AuthDivider = ({ children }) => (
  <div className="hx-auth-divider"><span>{children}</span></div>
);

const PasswordInput = ({ value, onChange, placeholder = "••••••••", autoFocus, autoComplete = "current-password", ...rest }) => {
  const [show, setShow] = React.useState(false);
  return (
    <Input
      type={show ? "text" : "password"}
      value={value}
      onChange={onChange}
      placeholder={placeholder}
      autoFocus={autoFocus}
      autoComplete={autoComplete}
      {...rest}
      suffix={
        <button type="button" className="hx-pw-eye" onClick={() => setShow((s) => !s)} aria-label={show ? "Hide password" : "Show password"}>
          {show ? <SvgEyeOff size={15}/> : <SvgEye size={15}/>}
        </button>
      }
    />
  );
};

// Password strength heuristic — returns 0..4
const scorePassword = (pw) => {
  if (!pw) return -1;
  if (pw.length < 8) return 0;
  let s = 1;
  if (pw.length >= 12) s++;
  if (/[A-Z]/.test(pw) && /[a-z]/.test(pw)) s++;
  if (/\d/.test(pw)) s++;
  if (/[^A-Za-z0-9]/.test(pw)) s++;
  return Math.min(4, s);
};
const STRENGTH_LABEL = ["Too short", "Weak", "Fair", "Strong", "Excellent"];

const PasswordStrength = ({ password }) => {
  const s = scorePassword(password);
  const colors = ["var(--bad)", "var(--warn)", "#b88a00", "var(--good)", "var(--good)"];
  return (
    <div className="hx-pwstr">
      <div className="hx-pwstr-bars">
        {[0,1,2,3].map((i) => (
          <span key={i} style={{background: s > i ? colors[s] : "var(--line)"}}/>
        ))}
      </div>
      <span className="hx-pwstr-label" style={{color: s >= 0 ? colors[s] : "var(--muted)"}}>
        {s >= 0 ? STRENGTH_LABEL[s] : "8+ chars, mix of letters, numbers, symbols"}
      </span>
    </div>
  );
};

// 6-digit OTP input with auto-advance, backspace, and paste handling.
const OtpInput = ({ length = 6, value, onChange, autoFocus }) => {
  const refs = React.useRef([]);
  React.useEffect(() => { if (autoFocus) refs.current[0]?.focus(); }, [autoFocus]);

  const handleChange = (idx, v) => {
    const ch = v.replace(/\D/g, "").slice(-1);
    const next = value.padEnd(length, " ").split("");
    next[idx] = ch || " ";
    onChange(next.join("").replace(/\s+$/g, "").replace(/\s/g, "").slice(0, length));
    if (ch && idx < length - 1) refs.current[idx + 1]?.focus();
  };
  const handleKey = (idx, e) => {
    if (e.key === "Backspace" && !value[idx] && idx > 0) {
      refs.current[idx - 1]?.focus();
      e.preventDefault();
      const next = value.split("");
      next[idx - 1] = "";
      onChange(next.join(""));
    }
    if (e.key === "ArrowLeft" && idx > 0) refs.current[idx - 1]?.focus();
    if (e.key === "ArrowRight" && idx < length - 1) refs.current[idx + 1]?.focus();
  };
  const handlePaste = (e) => {
    const txt = (e.clipboardData.getData("text") || "").replace(/\D/g, "").slice(0, length);
    if (txt) {
      e.preventDefault();
      onChange(txt);
      refs.current[Math.min(txt.length, length - 1)]?.focus();
    }
  };

  return (
    <div className="hx-otp" onPaste={handlePaste}>
      {Array.from({ length }).map((_, i) => (
        <input
          key={i}
          ref={(el) => (refs.current[i] = el)}
          inputMode="numeric"
          pattern="\d*"
          maxLength={1}
          value={value[i] || ""}
          onChange={(e) => handleChange(i, e.target.value)}
          onKeyDown={(e) => handleKey(i, e)}
          aria-label={`Digit ${i + 1}`}
        />
      ))}
    </div>
  );
};

// =================================================================
// SignInPage — /sign-in
// =================================================================
const SignInPage = () => {
  const [email, setEmail] = React.useState("");
  const [password, setPassword] = React.useState("");
  const [remember, setRemember] = React.useState(true);
  const [busy, setBusy] = React.useState(false);
  const [error, setError] = React.useState(null);

  const valid = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email) && password.length >= 4;

  const onSubmit = (e) => {
    e.preventDefault();
    if (!valid) return;
    setBusy(true); setError(null);
    setTimeout(() => {
      setBusy(false);
      // Demo branch: trigger 2FA if email matches admin@cataloguemaker.dev
      if (email.toLowerCase() === "admin@cataloguemaker.dev") {
        window.__nav("two-factor");
        return;
      }
      window.__toast("Signed in");
      window.__nav("dashboard");
    }, 700);
  };

  return (
    <AuthLayout>
      <AuthHeader title="Sign in to your account" subtitle="Welcome back. Continue your work on Catalogue Maker."/>

      <OauthRow disabled={busy}/>
      <AuthDivider>or continue with email</AuthDivider>

      {error && <Banner tone="warn" icon={<IconInfo size={16}/>}>{error}</Banner>}

      <form className="hx-auth-form" onSubmit={onSubmit} noValidate>
        <FormField label="Work email">
          <Input type="email" autoComplete="email" autoFocus value={email} onChange={(e) => setEmail(e.target.value)} placeholder="you@company.com"/>
        </FormField>
        <FormField label={
          <span className="hx-auth-label-split">
            <span>Password</span>
            <a href="#" onClick={(e) => { e.preventDefault(); window.__nav("forgot-password"); }}>Forgot password?</a>
          </span>
        }>
          <PasswordInput value={password} onChange={(e) => setPassword(e.target.value)} autoComplete="current-password"/>
        </FormField>
        <label className="hx-auth-check">
          <input type="checkbox" checked={remember} onChange={(e) => setRemember(e.target.checked)}/>
          <span>Keep me signed in for 30 days on this device</span>
        </label>
        <Btn type="submit" kind="primary" size="lg" disabled={!valid || busy} className="hx-auth-submit">
          {busy ? "Signing in…" : "Sign in"}
        </Btn>
      </form>

      <div className="hx-auth-alt">
        Don't have an account? <a href="#" onClick={(e) => { e.preventDefault(); window.__nav("sign-up"); }}>Create one</a>
      </div>
    </AuthLayout>
  );
};

// =================================================================
// SignUpPage — /sign-up
// =================================================================
const SignUpPage = () => {
  const [form, setForm] = React.useState({ name: "", email: "", password: "", org: "" });
  const [agree, setAgree] = React.useState(false);
  const [busy, setBusy] = React.useState(false);

  const set = (k, v) => setForm((f) => ({ ...f, [k]: v }));
  const strength = scorePassword(form.password);
  const emailValid = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(form.email);
  const valid = form.name.trim().length >= 2 && emailValid && strength >= 2 && form.org.trim().length >= 2 && agree;

  const onSubmit = (e) => {
    e.preventDefault();
    if (!valid) return;
    setBusy(true);
    setTimeout(() => {
      setBusy(false);
      window.__nav("verify-email");
    }, 800);
  };

  return (
    <AuthLayout>
      <AuthHeader
        title="Create your Catalogue Maker account"
        subtitle="Spin up a workspace in under a minute. No credit card required."/>

      <OauthRow disabled={busy} mode="sign-up"/>
      <AuthDivider>or sign up with email</AuthDivider>

      <form className="hx-auth-form" onSubmit={onSubmit} noValidate>
        <div className="hx-auth-grid-2">
          <FormField label="Full name">
            <Input value={form.name} autoComplete="name" autoFocus onChange={(e) => set("name", e.target.value)} placeholder="Ada Lovelace"/>
          </FormField>
          <FormField label="Organization">
            <Input value={form.org} autoComplete="organization" onChange={(e) => set("org", e.target.value)} placeholder="Cohort Labs"/>
          </FormField>
        </div>
        <FormField label="Work email" hint={form.email && !emailValid ? <span style={{color:"var(--bad)"}}>Enter a valid email address.</span> : "We'll send a verification code to this inbox."}>
          <Input type="email" autoComplete="email" value={form.email} onChange={(e) => set("email", e.target.value)} placeholder="you@company.com"/>
        </FormField>
        <FormField label="Password">
          <PasswordInput value={form.password} onChange={(e) => set("password", e.target.value)} autoComplete="new-password"/>
          <PasswordStrength password={form.password}/>
        </FormField>

        <label className="hx-auth-check">
          <input type="checkbox" checked={agree} onChange={(e) => setAgree(e.target.checked)}/>
          <span>
            I agree to the <a href="#" onClick={(e) => e.preventDefault()}>Terms of Service</a> and acknowledge the <a href="#" onClick={(e) => e.preventDefault()}>Privacy Policy</a>.
          </span>
        </label>

        <Btn type="submit" kind="primary" size="lg" disabled={!valid || busy} className="hx-auth-submit">
          {busy ? "Creating account…" : "Create account"}
        </Btn>
      </form>

      <div className="hx-auth-alt">
        Already have an account? <a href="#" onClick={(e) => { e.preventDefault(); window.__nav("sign-in"); }}>Sign in</a>
      </div>
    </AuthLayout>
  );
};

// =================================================================
// ForgotPasswordPage — /forgot-password
// =================================================================
const ForgotPasswordPage = () => {
  const [email, setEmail] = React.useState("");
  const [busy, setBusy] = React.useState(false);
  const valid = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);

  const onSubmit = (e) => {
    e.preventDefault();
    if (!valid) return;
    setBusy(true);
    setTimeout(() => { setBusy(false); window.__nav("check-email", encodeURIComponent(email)); }, 600);
  };

  return (
    <AuthLayout>
      <AuthHeader
        icon={<SvgLock/>}
        title="Forgot your password?"
        subtitle="Enter the email tied to your Catalogue Maker account and we'll send a reset link."/>

      <form className="hx-auth-form" onSubmit={onSubmit} noValidate>
        <FormField label="Email">
          <Input type="email" autoFocus value={email} onChange={(e) => setEmail(e.target.value)} placeholder="you@company.com"/>
        </FormField>
        <Btn type="submit" kind="primary" size="lg" disabled={!valid || busy} className="hx-auth-submit">
          {busy ? "Sending link…" : "Send reset link"}
        </Btn>
      </form>

      <div className="hx-auth-alt">
        Remembered it? <a href="#" onClick={(e) => { e.preventDefault(); window.__nav("sign-in"); }}>Back to sign in</a>
      </div>
    </AuthLayout>
  );
};

// =================================================================
// CheckEmailPage — /check-email (success state for forgot-password)
// =================================================================
const CheckEmailPage = ({ routeParam }) => {
  const email = routeParam ? decodeURIComponent(routeParam) : "your inbox";
  const [resent, setResent] = React.useState(false);

  return (
    <AuthLayout>
      <AuthHeader
        icon={<SvgMail/>}
        title="Check your email"
        subtitle={<>We sent a password reset link to <strong>{email}</strong>. It expires in 30 minutes.</>}/>

      <div className="hx-auth-tip">
        <IconInfo size={14}/>
        <span>Didn't see anything? Check spam, or click below to send a new link.</span>
      </div>

      <div className="hx-auth-actions">
        <Btn kind="primary" size="lg" className="hx-auth-submit" onClick={() => { window.__nav("reset-password"); }}>
          Open reset link
        </Btn>
        <Btn kind="secondary" size="lg" className="hx-auth-submit"
          disabled={resent}
          onClick={() => { setResent(true); window.__toast("New reset link sent"); setTimeout(() => setResent(false), 8000); }}>
          {resent ? "Email sent · resend in 8s" : "Resend email"}
        </Btn>
      </div>

      <div className="hx-auth-alt">
        Wrong address? <a href="#" onClick={(e) => { e.preventDefault(); window.__nav("forgot-password"); }}>Try a different one</a>
      </div>
    </AuthLayout>
  );
};

// =================================================================
// ResetPasswordPage — /reset-password
// =================================================================
const ResetPasswordPage = () => {
  const [pw, setPw] = React.useState("");
  const [confirm, setConfirm] = React.useState("");
  const [busy, setBusy] = React.useState(false);

  const strength = scorePassword(pw);
  const match = pw && pw === confirm;
  const valid = strength >= 2 && match;

  const onSubmit = (e) => {
    e.preventDefault();
    if (!valid) return;
    setBusy(true);
    setTimeout(() => {
      setBusy(false);
      window.__toast("Password updated. Welcome back.");
      window.__nav("sign-in");
    }, 700);
  };

  return (
    <AuthLayout>
      <AuthHeader
        icon={<SvgLock/>}
        title="Choose a new password"
        subtitle="Your new password must be different from the last 3 you've used."/>

      <form className="hx-auth-form" onSubmit={onSubmit} noValidate>
        <FormField label="New password">
          <PasswordInput value={pw} onChange={(e) => setPw(e.target.value)} autoFocus autoComplete="new-password"/>
          <PasswordStrength password={pw}/>
        </FormField>
        <FormField label="Confirm new password" hint={confirm && !match ? <span style={{color:"var(--bad)"}}>Passwords don't match.</span> : null}>
          <PasswordInput value={confirm} onChange={(e) => setConfirm(e.target.value)} autoComplete="new-password"/>
        </FormField>

        <ul className="hx-pw-rules">
          <li className={pw.length >= 8 ? "ok" : ""}><IconCheck size={12}/> At least 8 characters</li>
          <li className={/[A-Z]/.test(pw) && /[a-z]/.test(pw) ? "ok" : ""}><IconCheck size={12}/> Upper and lowercase letters</li>
          <li className={/\d/.test(pw) ? "ok" : ""}><IconCheck size={12}/> At least one number</li>
          <li className={/[^A-Za-z0-9]/.test(pw) ? "ok" : ""}><IconCheck size={12}/> One symbol (recommended)</li>
        </ul>

        <Btn type="submit" kind="primary" size="lg" disabled={!valid || busy} className="hx-auth-submit">
          {busy ? "Updating password…" : "Update password"}
        </Btn>
      </form>

      <div className="hx-auth-alt">
        <a href="#" onClick={(e) => { e.preventDefault(); window.__nav("sign-in"); }}>Back to sign in</a>
      </div>
    </AuthLayout>
  );
};

// =================================================================
// VerifyEmailPage — /verify-email (post-signup)
// =================================================================
const VerifyEmailPage = () => {
  const [code, setCode] = React.useState("");
  const [busy, setBusy] = React.useState(false);
  const [resentAt, setResentAt] = React.useState(null);
  const valid = code.length === 6;

  // tick to refresh countdown
  const [, setNow] = React.useState(0);
  React.useEffect(() => {
    if (!resentAt) return;
    const t = setInterval(() => setNow((n) => n + 1), 1000);
    return () => clearInterval(t);
  }, [resentAt]);

  const cooldown = resentAt ? Math.max(0, 30 - Math.floor((Date.now() - resentAt) / 1000)) : 0;

  const onSubmit = (e) => {
    e.preventDefault();
    if (!valid) return;
    setBusy(true);
    setTimeout(() => {
      setBusy(false);
      window.__toast("Email verified");
      window.__nav("dashboard");
    }, 600);
  };

  return (
    <AuthLayout>
      <AuthHeader
        icon={<SvgMail/>}
        title="Verify your email"
        subtitle={<>We sent a 6-digit code to <strong>you@company.com</strong>. Enter it below to activate your account.</>}/>

      <form className="hx-auth-form hx-auth-form-otp" onSubmit={onSubmit} noValidate>
        <OtpInput value={code} onChange={setCode} autoFocus/>
        <Btn type="submit" kind="primary" size="lg" disabled={!valid || busy} className="hx-auth-submit">
          {busy ? "Verifying…" : "Verify and continue"}
        </Btn>
      </form>

      <div className="hx-auth-resend">
        Didn't get the code?{" "}
        {cooldown > 0
          ? <span style={{color:"var(--muted)"}}>Resend in {cooldown}s</span>
          : <button type="button" className="hx-link-btn" onClick={() => { setResentAt(Date.now()); window.__toast("New code sent"); }}>Resend code</button>
        }
      </div>

      <div className="hx-auth-alt">
        Wrong email? <a href="#" onClick={(e) => { e.preventDefault(); window.__nav("sign-up"); }}>Change it</a>
      </div>
    </AuthLayout>
  );
};

// =================================================================
// TwoFactorPage — /two-factor
// =================================================================
const TwoFactorPage = () => {
  const [code, setCode] = React.useState("");
  const [busy, setBusy] = React.useState(false);
  const [method, setMethod] = React.useState("app"); // app | sms | backup
  const valid = code.length === 6;

  const onSubmit = (e) => {
    e.preventDefault();
    if (!valid) return;
    setBusy(true);
    setTimeout(() => {
      setBusy(false);
      window.__toast("Signed in");
      window.__nav("dashboard");
    }, 600);
  };

  const COPY = {
    app:    { sub: "Open your authenticator app and enter the 6-digit code for Catalogue Maker." },
    sms:    { sub: "We just texted a 6-digit code to •••• •• 4082." },
    backup: { sub: "Enter one of the 10 backup codes you saved when setting up 2FA." },
  };

  return (
    <AuthLayout>
      <AuthHeader
        icon={<IconShield size={22}/>}
        title="Two-factor authentication"
        subtitle={COPY[method].sub}/>

      <form className="hx-auth-form hx-auth-form-otp" onSubmit={onSubmit} noValidate>
        <OtpInput value={code} onChange={setCode} autoFocus length={6}/>
        <Btn type="submit" kind="primary" size="lg" disabled={!valid || busy} className="hx-auth-submit">
          {busy ? "Verifying…" : "Verify and sign in"}
        </Btn>
      </form>

      <div className="hx-auth-2fa-alt">
        <div className="hx-auth-2fa-alt-label">Use a different method</div>
        <div className="hx-auth-2fa-options">
          {method !== "app"    && <button type="button" className="hx-auth-2fa-opt" onClick={() => { setCode(""); setMethod("app"); }}><IconShield size={14}/>Authenticator app</button>}
          {method !== "sms"    && <button type="button" className="hx-auth-2fa-opt" onClick={() => { setCode(""); setMethod("sms"); }}><IconPlug size={14}/>Text message</button>}
          {method !== "backup" && <button type="button" className="hx-auth-2fa-opt" onClick={() => { setCode(""); setMethod("backup"); }}><IconKey size={14}/>Backup code</button>}
        </div>
      </div>

      <div className="hx-auth-alt">
        <a href="#" onClick={(e) => { e.preventDefault(); window.__nav("sign-in"); }}>Back to sign in</a>
      </div>
    </AuthLayout>
  );
};

// =================================================================
// SsoSignInPage — /sso (enter organization domain)
// =================================================================
const SsoSignInPage = () => {
  const [domain, setDomain] = React.useState("");
  const [busy, setBusy] = React.useState(false);
  const valid = /[a-z0-9-]+\.[a-z]{2,}/i.test(domain);

  const onSubmit = (e) => {
    e.preventDefault();
    if (!valid) return;
    setBusy(true);
    setTimeout(() => {
      setBusy(false);
      window.__toast(`Redirecting to ${domain} IdP (demo)`);
      window.__nav("dashboard");
    }, 700);
  };

  return (
    <AuthLayout>
      <AuthHeader
        icon={<IconKey size={22}/>}
        title="Sign in with SSO"
        subtitle="Enter your organization's email domain to continue with your identity provider (Okta, Google Workspace, Azure AD, etc.)."/>

      <form className="hx-auth-form" onSubmit={onSubmit} noValidate>
        <FormField label="Company domain" hint="The part after the @ in your work email.">
          <Input value={domain} autoFocus onChange={(e) => setDomain(e.target.value)} placeholder="company.com"/>
        </FormField>
        <Btn type="submit" kind="primary" size="lg" disabled={!valid || busy} className="hx-auth-submit">
          {busy ? "Redirecting…" : "Continue with SSO"}
        </Btn>
      </form>

      <div className="hx-auth-alt">
        <a href="#" onClick={(e) => { e.preventDefault(); window.__nav("sign-in"); }}>Back to sign in</a>
      </div>
    </AuthLayout>
  );
};

// ---------- Shared styles ----------
const AuthStyles = () => (
  <style>{`
    .hx-auth {
      display: grid;
      grid-template-columns: minmax(0, 1fr) minmax(0, 1.05fr);
      min-height: 100vh;
      background: var(--bg);
      color: var(--ink);
    }

    /* --- Form column --- */
    .hx-auth-form-col {
      display: flex; flex-direction: column;
      padding: 32px 32px 24px;
      min-height: 100vh;
      position: relative;
    }
    .hx-auth-brand {
      display: inline-flex; align-items: center; gap: 8px;
      font-weight: 600; font-size: 17px;
      color: var(--ink); text-decoration: none;
      align-self: flex-start;
    }
    .hx-auth-brand-dot { color: var(--accent); }

    .hx-auth-form-inner {
      flex: 1;
      display: flex; flex-direction: column; justify-content: center;
      gap: 18px;
      width: 100%; max-width: 420px;
      margin: 0 auto;
      padding: 32px 0;
    }

    .hx-auth-head { display: flex; flex-direction: column; gap: 8px; margin-bottom: 4px; }
    .hx-auth-head-icon {
      width: 44px; height: 44px;
      border-radius: 12px;
      background: var(--accent-soft); color: var(--accent);
      display: inline-flex; align-items: center; justify-content: center;
      margin-bottom: 8px;
    }
    .hx-auth-head h1 { font-size: 26px; font-weight: 600; letter-spacing: -.02em; margin: 0; line-height: 1.2; }
    .hx-auth-head p { color: var(--muted); font-size: 14px; line-height: 1.55; margin: 4px 0 0; max-width: 380px; }

    /* OAuth row */
    .hx-auth-oauth {
      display: grid;
      grid-template-columns: 1fr 1fr 1fr;
      gap: 8px;
    }
    .hx-oauth-btn {
      display: inline-flex; align-items: center; justify-content: center; gap: 8px;
      height: 42px;
      background: var(--panel); color: var(--ink);
      border: 1px solid var(--line); border-radius: 8px;
      font: inherit; font-size: 13.5px; font-weight: 500;
      cursor: pointer;
      transition: background .12s, border-color .12s;
    }
    .hx-oauth-btn:hover:not(:disabled) { background: var(--hover); border-color: color-mix(in oklab, var(--ink) 30%, transparent); }
    .hx-oauth-btn:disabled { opacity: .55; cursor: not-allowed; }
    .hx-oauth-btn svg { flex-shrink: 0; }

    /* Divider with text */
    .hx-auth-divider {
      display: flex; align-items: center; gap: 12px;
      color: var(--muted); font-size: 12px; text-transform: uppercase; letter-spacing: .08em;
      margin: 2px 0;
    }
    .hx-auth-divider::before, .hx-auth-divider::after { content: ""; flex: 1; height: 1px; background: var(--line); }

    /* Form */
    .hx-auth-form { display: flex; flex-direction: column; gap: 2px; }
    .hx-auth-form .hx-ff { margin-bottom: 12px; }
    .hx-auth-form-otp { gap: 18px; align-items: stretch; }
    .hx-auth-grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
    @media (max-width: 480px) { .hx-auth-grid-2 { grid-template-columns: 1fr; } }

    .hx-auth-label-split { display: flex; justify-content: space-between; align-items: center; }
    .hx-auth-label-split a { color: var(--accent); text-decoration: none; font-size: 12.5px; font-weight: 500; }
    .hx-auth-label-split a:hover { text-decoration: underline; }

    .hx-pw-eye {
      background: transparent; border: none; cursor: pointer;
      color: var(--muted); padding: 4px; border-radius: 4px;
      display: inline-flex; align-items: center; justify-content: center;
    }
    .hx-pw-eye:hover { color: var(--ink-2); background: var(--hover); }

    /* Password strength meter */
    .hx-pwstr { display: flex; align-items: center; gap: 12px; margin-top: 8px; }
    .hx-pwstr-bars { display: flex; gap: 4px; flex: 1; }
    .hx-pwstr-bars span { flex: 1; height: 4px; border-radius: 2px; background: var(--line); transition: background .15s; }
    .hx-pwstr-label { font-size: 11.5px; font-weight: 500; letter-spacing: .01em; white-space: nowrap; }

    /* Password rules list */
    .hx-pw-rules {
      list-style: none; padding: 12px 14px; margin: 4px 0 6px;
      background: var(--panel-2); border: 1px solid var(--line); border-radius: 10px;
      display: grid; grid-template-columns: 1fr 1fr; gap: 6px 14px;
      font-size: 12px;
    }
    .hx-pw-rules li { display: inline-flex; align-items: center; gap: 6px; color: var(--muted); }
    .hx-pw-rules li svg { color: var(--muted-2); }
    .hx-pw-rules li.ok { color: var(--good); }
    .hx-pw-rules li.ok svg { color: var(--good); }
    @media (max-width: 480px) { .hx-pw-rules { grid-template-columns: 1fr; } }

    /* Checkboxes */
    .hx-auth-check {
      display: flex; gap: 10px; align-items: flex-start;
      font-size: 13px; color: var(--ink-2); line-height: 1.55;
      cursor: pointer; padding: 4px 0;
    }
    .hx-auth-check input { margin-top: 3px; accent-color: var(--accent); flex-shrink: 0; }
    .hx-auth-check a { color: var(--accent); text-decoration: none; }
    .hx-auth-check a:hover { text-decoration: underline; }

    /* Submit button — full width */
    .hx-auth-submit { width: 100%; justify-content: center; margin-top: 6px; }
    .hx-auth-actions { display: flex; flex-direction: column; gap: 8px; }

    /* OTP input */
    .hx-otp { display: flex; gap: 8px; justify-content: space-between; }
    .hx-otp input {
      width: 100%; max-width: 56px; height: 56px;
      font-family: var(--mono); font-size: 22px; font-weight: 500;
      text-align: center;
      border: 1px solid var(--line); border-radius: 10px;
      background: var(--panel); color: var(--ink);
      font-feature-settings: "tnum";
      transition: border-color .12s, box-shadow .12s;
    }
    .hx-otp input:focus {
      outline: none;
      border-color: var(--accent);
      box-shadow: 0 0 0 3px color-mix(in oklab, var(--accent) 18%, transparent);
    }
    @media (max-width: 480px) {
      .hx-otp { gap: 6px; }
      .hx-otp input { height: 48px; max-width: 48px; font-size: 19px; }
    }

    /* Resend code line */
    .hx-auth-resend {
      text-align: center; font-size: 13px; color: var(--muted);
      padding: 4px 0;
    }
    .hx-auth-resend .hx-link-btn { font-size: 13px; font-weight: 500; }

    /* Tip box (check-email) */
    .hx-auth-tip {
      display: flex; gap: 10px; align-items: flex-start;
      padding: 12px 14px; background: var(--info-soft); color: var(--info-ink);
      border-radius: 10px; font-size: 13px; line-height: 1.5;
    }
    .hx-auth-tip svg { flex-shrink: 0; margin-top: 2px; }

    /* 2FA alt methods */
    .hx-auth-2fa-alt {
      border-top: 1px solid var(--line-2);
      padding-top: 16px;
      display: flex; flex-direction: column; gap: 8px;
    }
    .hx-auth-2fa-alt-label { font-size: 12px; color: var(--muted); font-weight: 500; letter-spacing: .03em; text-transform: uppercase; }
    .hx-auth-2fa-options { display: flex; flex-wrap: wrap; gap: 8px; }
    .hx-auth-2fa-opt {
      display: inline-flex; align-items: center; gap: 6px;
      padding: 7px 12px; background: var(--panel-2);
      border: 1px solid var(--line); border-radius: 8px;
      cursor: pointer; font: inherit; font-size: 13px; color: var(--ink-2);
      transition: background .12s;
    }
    .hx-auth-2fa-opt:hover { background: var(--hover); color: var(--ink); }

    /* "Don't have an account?" line */
    .hx-auth-alt {
      text-align: center; font-size: 13.5px; color: var(--muted);
      padding: 6px 0;
    }
    .hx-auth-alt a { color: var(--accent); text-decoration: none; font-weight: 500; }
    .hx-auth-alt a:hover { text-decoration: underline; }

    /* Footer */
    .hx-auth-foot {
      display: flex; gap: 10px; align-items: center; flex-wrap: wrap;
      font-size: 12px; color: var(--muted);
      padding-top: 12px;
    }
    .hx-auth-foot a { color: var(--muted); text-decoration: none; }
    .hx-auth-foot a:hover { color: var(--ink-2); }
    .hx-auth-foot-sep { color: var(--muted-2); }

    /* --- Side panel --- */
    .hx-auth-side {
      position: relative;
      overflow: hidden;
      background: linear-gradient(165deg, var(--ink) 0%, #14171e 60%, #0b0d12 100%);
      color: #f3f4f7;
      display: flex; align-items: center; justify-content: center;
      padding: 56px;
      border-left: 1px solid var(--line);
    }
    body[data-theme="light"] .hx-auth-side {
      background: linear-gradient(165deg, #14171e 0%, #1f2330 55%, #0b0d12 100%);
    }
    .hx-auth-side-mesh {
      position: absolute; inset: 0;
      background:
        radial-gradient(60% 50% at 90% 10%, color-mix(in oklab, var(--accent) 35%, transparent) 0%, transparent 60%),
        radial-gradient(50% 40% at 0% 100%, color-mix(in oklab, var(--accent) 22%, transparent) 0%, transparent 60%),
        radial-gradient(30% 30% at 40% 60%, color-mix(in oklab, var(--accent) 12%, transparent) 0%, transparent 60%);
      opacity: .9;
    }
    .hx-auth-side-rings {
      position: absolute;
      top: 50%; right: -120px;
      transform: translateY(-50%);
      width: 700px; height: 700px;
      pointer-events: none;
    }
    .hx-auth-side-rings span {
      position: absolute; top: 50%; left: 50%;
      transform: translate(-50%, -50%);
      border-radius: 50%;
      border: 1px solid color-mix(in oklab, #fff 12%, transparent);
    }
    .hx-auth-side-rings span:nth-child(1) { width: 320px; height: 320px; }
    .hx-auth-side-rings span:nth-child(2) { width: 500px; height: 500px; border-color: color-mix(in oklab, #fff 8%, transparent); }
    .hx-auth-side-rings span:nth-child(3) { width: 700px; height: 700px; border-color: color-mix(in oklab, #fff 5%, transparent); }
    .hx-auth-side-inner {
      position: relative; z-index: 2;
      max-width: 480px;
      display: flex; flex-direction: column; gap: 22px;
    }
    .hx-auth-side-eyebrow {
      font-size: 11.5px; letter-spacing: .14em; text-transform: uppercase;
      color: color-mix(in oklab, #fff 60%, transparent);
      font-weight: 500;
    }
    .hx-auth-side-title {
      font-size: 32px; font-weight: 600; line-height: 1.2; letter-spacing: -.02em;
      margin: 0;
      color: #fff;
    }
    .hx-auth-side-list {
      list-style: none; padding: 0; margin: 6px 0 0;
      display: flex; flex-direction: column; gap: 12px;
    }
    .hx-auth-side-list li {
      display: flex; align-items: flex-start; gap: 12px;
      font-size: 14.5px; line-height: 1.55;
      color: color-mix(in oklab, #fff 85%, transparent);
    }
    .hx-auth-tick {
      width: 20px; height: 20px; border-radius: 50%;
      background: color-mix(in oklab, var(--accent) 90%, transparent);
      color: white;
      display: inline-flex; align-items: center; justify-content: center;
      flex-shrink: 0; margin-top: 1px;
    }

    .hx-auth-quote {
      margin: 18px 0 0; padding: 22px 0 0;
      border-top: 1px solid color-mix(in oklab, #fff 12%, transparent);
    }
    .hx-auth-quote blockquote {
      margin: 0; font-size: 15px; line-height: 1.55;
      color: color-mix(in oklab, #fff 88%, transparent);
      font-weight: 400;
    }
    .hx-auth-quote figcaption {
      display: flex; gap: 12px; align-items: center;
      margin-top: 14px;
    }
    .hx-auth-quote-name { display: block; font-size: 13px; font-weight: 600; color: #fff; }
    .hx-auth-quote-role { display: block; font-size: 12px; color: color-mix(in oklab, #fff 55%, transparent); margin-top: 1px; }

    /* Responsive — collapse side panel */
    @media (max-width: 960px) {
      .hx-auth { grid-template-columns: 1fr; }
      .hx-auth-side { display: none; }
      .hx-auth-form-col { padding: 24px 20px; }
    }
  `}</style>
);

Object.assign(window, {
  AUTH_ROUTES,
  SignInPage, SignUpPage,
  ForgotPasswordPage, CheckEmailPage, ResetPasswordPage,
  VerifyEmailPage, TwoFactorPage, SsoSignInPage,
});
