/* ClientBase, About, Contact, Login pages */

const AboutPage = ({ go }) => (
  <>
    <PageHeader eyebrow="À propos"
      title="Un petit projet français, au début de l'aventure."
      subtitle="ClientBase est en bêta. On cherche des indépendants pour construire l'outil avec nous."/>

    <section style={{ padding: "40px 0 80px" }}>
      <div className="container">
        <div style={{
          maxWidth: 760, margin: "0 auto",
          fontSize: 17, lineHeight: 1.7, color: "var(--ink-2)",
        }}>
          <p style={{ fontSize: 19, color: "var(--ink-2)" }}>
            ClientBase est né d'un constat simple : les outils existants pour les indépendants du service sont soit trop chers, soit trop compliqués, soit les deux. On s'est dit qu'on pouvait faire mieux, plus simple, plus juste.
          </p>
          <p style={{ marginTop: 24 }}>
            On est au tout début : l'app fonctionne, mais elle a besoin de vos retours pour grandir. C'est pour ça qu'on ouvre la bêta, vous utilisez gratuitement, vous nous dites ce qui va ou pas, et on adapte l'outil à la réalité de votre métier.
          </p>
          <p style={{ marginTop: 24 }}>
            Ce qu'on s'engage à tenir dès maintenant : un prix juste quand on lancera officiellement, une interface simple à comprendre, et un support humain, pas un bot. Pas de commission sur vos RDV, jamais.
          </p>
          <div style={{ fontFamily: "var(--ff-display)", fontSize: 18, fontWeight: 560, marginTop: 40, color: "var(--ink)" }}>
           , L'équipe ClientBase
          </div>
        </div>

        {/* Honest status */}
        <div style={{
          marginTop: 64,
          display: "grid", gridTemplateColumns: "repeat(4, 1fr)", gap: 16,
        }} className="nums-grid">
          {[
            ["Bêta", "statut du projet"],
            ["Gratuit", "pendant toute la bêta"],
            ["< 15 min", "pour être opérationnel"],
            ["🇫🇷", "hébergé en France"],
          ].map(([v, l]) => (
            <div key={l} style={{
              padding: "28px 24px",
              background: "var(--surface)", border: "1px solid var(--line)",
              borderRadius: 14, textAlign: "left",
            }}>
              <div style={{ fontFamily: "var(--ff-display)", fontSize: 38, fontWeight: 580, letterSpacing: "-0.035em" }}>{v}</div>
              <div style={{ fontSize: 13.5, color: "var(--ink-3)", marginTop: 4 }}>{l}</div>
            </div>
          ))}
        </div>

        {/* Values */}
        <div style={{ marginTop: 96 }}>
          <h2 style={{ textAlign: "center", fontSize: 32, marginBottom: 48 }}>Ce qui nous guide</h2>
          <div style={{ display: "grid", gridTemplateColumns: "repeat(3, 1fr)", gap: 20 }} className="values-grid">
            {[
              { icon: "shield", title: "Honnêteté", desc: "Un prix affiché, pas de frais cachés, pas de commission sur vos RDV. Ce que vous payez, c'est ce que vous payez." },
              { icon: "zap", title: "Simplicité", desc: "Chaque nouvelle fonctionnalité doit réussir le test du « ma mère peut-elle l'utiliser sans tuto ? »" },
              { icon: "heart", title: "Proximité", desc: "Un support humain, en français, qui comprend votre métier. Pas un bot qui tourne en rond." },
            ].map(v => (
              <div key={v.title} style={{
                padding: 28, border: "1px solid var(--line)", borderRadius: 14,
                background: "var(--surface)",
              }}>
                <div style={{
                  width: 40, height: 40, borderRadius: 10,
                  background: "var(--accent-soft)", color: "var(--accent-ink)",
                  display: "flex", alignItems: "center", justifyContent: "center",
                }}>
                  <Icon name={v.icon} size={20}/>
                </div>
                <h3 style={{ marginTop: 14, fontSize: 19 }}>{v.title}</h3>
                <p style={{ marginTop: 8, fontSize: 14.5 }}>{v.desc}</p>
              </div>
            ))}
          </div>
        </div>
      </div>
    </section>

    <FinalCTA go={go}/>
  </>
);

/* ============ CONTACT PAGE ============ */
// Adresse contact globale, affichée et utilisée pour les formulaires
const CB_CONTACT_EMAIL = "clientbase.fr@gmail.com";
// Endpoint FormSubmit, zéro setup, les mails arrivent directement
const CB_FORM_ENDPOINT = `https://formsubmit.co/ajax/${CB_CONTACT_EMAIL}`;

/** Envoie un message via FormSubmit.co. Retourne { ok } ou { error }. */
const sendContactMail = async ({ subject, from, replyTo, message, meta }) => {
  try {
    const res = await fetch(CB_FORM_ENDPOINT, {
      method: "POST",
      headers: { "Content-Type": "application/json", "Accept": "application/json" },
      body: JSON.stringify({
        _subject: subject,
        _replyto: replyTo,
        _template: "table",
        _captcha: "false",
        name: from, email: replyTo,
        message,
        ...(meta || {}),
      }),
    });
    const data = await res.json().catch(() => ({}));
    if (!res.ok || data.success === "false") {
      return { error: data.message || "Erreur d'envoi. Réessayez dans un instant." };
    }
    return { ok: true };
  } catch (e) {
    return { error: "Impossible d'envoyer (réseau). Réessayez." };
  }
};

const ContactPage = ({ audience = "pro" }) => {
  const [form, setForm] = React.useState({ name: "", email: "", subject: "Question générale", message: "" });
  const [sent, setSent] = React.useState(false);
  const [busy, setBusy] = React.useState(false);
  const [error, setError] = React.useState(null);
  const isMobile = useIsMobile(760);
  // Couleurs de la carte « Envoi direct » : audience-aware. Indigo brand
  // côté pro, cli-accent côté client — la page contact étant partagée,
  // c'est la prop audience qui fait la bascule visuelle.
  const isClient = audience === "client";
  const mailAccent     = isClient ? "var(--cli-accent)"   : "var(--accent)";
  const mailAccentInk  = isClient ? "var(--cli-ink)"      : "var(--accent-ink)";
  const mailAccentSoft = isClient ? "var(--cli-soft)"     : "var(--accent-soft)";
  const mailAccentSoft2= isClient ? "var(--cli-soft-2)"   : "var(--accent-soft-2)";

  const submit = async (e) => {
    e.preventDefault();
    setError(null);
    if (!form.name.trim()) return setError("Votre nom est requis.");
    if (!cbAuth.isValidEmail(form.email)) return setError("Email invalide. Exemple : prenom@exemple.fr");
    if (!form.message.trim() || form.message.trim().length < 10) return setError("Votre message est trop court.");

    setBusy(true);
    const res = await sendContactMail({
      subject: `[ClientBase, ${form.subject}] ${form.name}`,
      from: form.name,
      replyTo: form.email,
      message: form.message,
      meta: { Source: "Page vitrine /contact" },
    });
    setBusy(false);
    if (res.error) return setError(res.error);
    setSent(true);
  };

  // Carte « Envoi direct » : fond gradient audience-color (indigo pro /
  // cli-accent client) au lieu du rose qui détonnait sur la vitrine.
  const QuickMail = () => (
    <a href={`mailto:${CB_CONTACT_EMAIL}`} style={{
      padding: "16px 18px",
      background: `linear-gradient(135deg, ${mailAccentSoft} 0%, var(--surface) 70%)`,
      border: `1px solid ${mailAccentSoft2}`,
      borderRadius: 14, display: "flex", gap: 14, alignItems: "center",
      textDecoration: "none", color: "inherit",
    }}>
      <div style={{
        width: 42, height: 42, borderRadius: 11,
        background: mailAccent, color: "white",
        display: "flex", alignItems: "center", justifyContent: "center",
        flexShrink: 0, boxShadow: `0 6px 14px -6px ${mailAccent}`,
      }}>
        <Icon name="mail" size={18}/>
      </div>
      <div style={{ flex: 1, minWidth: 0 }}>
        <div style={{ fontSize: 12, color: "var(--ink-4)", fontWeight: 500 }}>Envoi direct</div>
        <div style={{ fontWeight: 560, fontSize: 15, color: "var(--ink)", marginTop: 2, wordBreak: "break-all" }}>
          {CB_CONTACT_EMAIL}
        </div>
        <div style={{ fontSize: 12, color: "var(--ink-4)", marginTop: 2 }}>Réponse sous <span style={{ whiteSpace: "nowrap" }}>24 h</span> ouvrées</div>
      </div>
      <Icon name="arrow" size={15} style={{ color: mailAccentInk, flexShrink: 0 }}/>
    </a>
  );

  return (
    <>
      <PageHeader eyebrow="Contact"
        title="On est là, vraiment."
        subtitle="Une question, une demande spécifique, ou juste envie de dire bonjour ? Écrivez-nous, on répond en moins de 24 h."/>

      <section style={{ padding: "20px 0 96px" }}>
        <div className="container">
          {isMobile ? (
            /* ===== Mobile : carte email rapide en haut, puis formulaire ===== */
            <div style={{ maxWidth: 560, margin: "0 auto", display: "flex", flexDirection: "column", gap: 16 }}>
              <QuickMail/>
              <div style={{
                padding: "10px 14px", background: "var(--bg-alt)",
                border: "1px solid var(--line)", borderRadius: 10,
                fontSize: 12.5, color: "var(--ink-3)", lineHeight: 1.5,
                display: "flex", gap: 10, alignItems: "center",
              }}>
                <Icon name="chat" size={14} style={{ color: "var(--accent-ink)", flexShrink: 0 }}/>
                <span>Déjà inscrit·e ? Contactez-nous directement depuis <strong>Paramètres → Nous contacter</strong> dans l'app.</span>
              </div>

              <form onSubmit={submit} style={{
                padding: 20, border: "1px solid var(--line)", borderRadius: 14,
                background: "var(--surface)",
              }}>
                {sent ? (
                  <div style={{ textAlign: "center", padding: "24px 12px" }}>
                    <div style={{
                      width: 52, height: 52, borderRadius: 50, margin: "0 auto",
                      background: "var(--sage-soft)", color: "var(--sage)",
                      display: "flex", alignItems: "center", justifyContent: "center",
                    }}>
                      <Icon name="check" size={26} stroke={2.5}/>
                    </div>
                    <h3 style={{ marginTop: 14, fontSize: 20 }}>Message envoyé !</h3>
                    <p style={{ marginTop: 8, fontSize: 14 }}>Réponse sous 24 h à <strong>{form.email}</strong>.</p>
                    <button className="btn btn-ghost btn-sm" style={{ marginTop: 16 }}
                      onClick={() => { setSent(false); setForm({ name: "", email: "", subject: "Question générale", message: "" }); }}>
                      Nouveau message
                    </button>
                  </div>
                ) : (
                  <>
                    <h3 style={{ fontSize: 17, marginBottom: 4 }}>Écrivez-nous</h3>
                    <p style={{ fontSize: 13, color: "var(--ink-3)", marginBottom: 16, lineHeight: 1.5 }}>
                      Arrive directement à {CB_CONTACT_EMAIL}.
                    </p>
                    {error && (
                      <div style={{
                        marginBottom: 14, padding: "10px 14px",
                        background: "oklch(96% 0.04 25)", border: "1px solid oklch(88% 0.06 25)",
                        color: "oklch(42% 0.15 25)", borderRadius: 10, fontSize: 13,
                      }}>{error}</div>
                    )}
                    <div style={{ display: "grid", gap: 14 }}>
                      <Field label="Votre nom" value={form.name} onChange={v => setForm({...form, name: v})} placeholder="Camille Dupont"/>
                      <Field label="Email" type="email" value={form.email} onChange={v => setForm({...form, email: v})} placeholder="vous@exemple.fr"/>
                      <div>
                        <label style={labelStyle}>Sujet</label>
                        <select value={form.subject} onChange={e => setForm({...form, subject: e.target.value})} style={{...inputStyle, appearance: "none"}}>
                          {["Question générale", "Support technique", "Démo personnalisée", "Presse / partenariat"].map(s => <option key={s}>{s}</option>)}
                        </select>
                      </div>
                      <div>
                        <label style={labelStyle}>Message</label>
                        <textarea value={form.message} onChange={e => setForm({...form, message: e.target.value})} rows={5}
                          style={{...inputStyle, resize: "vertical", minHeight: 120, fontFamily: "inherit"}}
                          placeholder="Parlez-nous de votre activité, on adore les détails…"/>
                      </div>
                      <button type="submit" disabled={busy} className="btn btn-accent btn-lg"
                        style={{ width: "100%", marginTop: 2, opacity: busy ? 0.7 : 1 }}>
                        {busy ? "Envoi…" : "Envoyer le message"} <Icon name="arrow" size={14}/>
                      </button>
                    </div>
                  </>
                )}
              </form>
            </div>
          ) : (
          /* ===== Desktop : grille info | formulaire ===== */
          <div style={{ display: "grid", gridTemplateColumns: "1fr 1.3fr", gap: 48, maxWidth: 1000, margin: "0 auto" }}>
            {/* Left, contact info */}
            <div style={{ display: "flex", flexDirection: "column", gap: 20 }}>
              {[
                { icon: "mail", title: "Email", value: CB_CONTACT_EMAIL, sub: "Réponse sous 24h ouvrées", href: `mailto:${CB_CONTACT_EMAIL}` },
                { icon: "chat", title: "Directement depuis l'app", value: "Menu Paramètres → Nous contacter", sub: "Recommandé si vous êtes inscrit·e" },
              ].map(c => (
                <a key={c.title} href={c.href || undefined}
                  style={{
                    padding: 22, border: "1px solid var(--line)", borderRadius: 12,
                    background: "var(--surface)", display: "flex", gap: 14,
                    textDecoration: "none", color: "inherit",
                  }}>
                  <div style={{
                    width: 36, height: 36, borderRadius: 9,
                    background: "var(--accent-soft)", color: "var(--accent-ink)",
                    display: "flex", alignItems: "center", justifyContent: "center",
                    flexShrink: 0,
                  }}>
                    <Icon name={c.icon} size={17}/>
                  </div>
                  <div>
                    <div style={{ fontSize: 13, color: "var(--ink-4)" }}>{c.title}</div>
                    <div style={{ fontWeight: 520, color: "var(--ink)", marginTop: 2, wordBreak: "break-all" }}>{c.value}</div>
                    <div style={{ fontSize: 12.5, color: "var(--ink-4)", marginTop: 2 }}>{c.sub}</div>
                  </div>
                </a>
              ))}
              <div style={{
                padding: 22, background: "var(--bg-alt)", borderRadius: 12,
                fontSize: 13, color: "var(--ink-2)", lineHeight: 1.6,
              }}>
                <div style={{ fontWeight: 520, color: "var(--ink)", fontSize: 13.5 }}>ClientBase</div>
                <div style={{ marginTop: 6, fontSize: 13 }}>Application web française · en bêta · aucune adresse physique à ce jour.</div>
              </div>
            </div>

            {/* Right, form */}
            <form onSubmit={submit} style={{
              padding: 32, border: "1px solid var(--line)", borderRadius: 14,
              background: "var(--surface)",
            }}>
              {sent ? (
                <div style={{ textAlign: "center", padding: "40px 20px" }}>
                  <div style={{
                    width: 56, height: 56, borderRadius: 50, margin: "0 auto",
                    background: "var(--sage-soft)", color: "var(--sage)",
                    display: "flex", alignItems: "center", justifyContent: "center",
                  }}>
                    <Icon name="check" size={28} stroke={2.5}/>
                  </div>
                  <h3 style={{ marginTop: 16, fontSize: 22 }}>Message envoyé !</h3>
                  <p style={{ marginTop: 8 }}>On vous répond sous 24h ouvrées à <strong>{form.email}</strong>.</p>
                  <button className="btn btn-ghost" style={{ marginTop: 20 }} onClick={() => { setSent(false); setForm({ name: "", email: "", subject: "Question générale", message: "" }); }}>
                    Nouveau message
                  </button>
                </div>
              ) : (
                <>
                  <h3 style={{ fontSize: 20, marginBottom: 6 }}>Envoyez-nous un message</h3>
                  <p style={{ fontSize: 13.5, marginBottom: 24 }}>
                    Arrive directement à <strong>{CB_CONTACT_EMAIL}</strong>.
                  </p>

                  {error && (
                    <div style={{
                      marginBottom: 16, padding: "10px 14px",
                      background: "oklch(96% 0.04 25)", border: "1px solid oklch(88% 0.06 25)",
                      color: "oklch(42% 0.15 25)", borderRadius: 10, fontSize: 13.5,
                    }}>{error}</div>
                  )}

                  <div style={{ display: "grid", gap: 16 }}>
                    <Field label="Votre nom" value={form.name} onChange={v => setForm({...form, name: v})} placeholder="Camille Dupont"/>
                    <Field label="Email" type="email" value={form.email} onChange={v => setForm({...form, email: v})} placeholder="vous@exemple.fr"/>
                    <div>
                      <label style={labelStyle}>Sujet</label>
                      <select value={form.subject} onChange={e => setForm({...form, subject: e.target.value})} style={{...inputStyle, appearance: "none"}}>
                        {["Question générale", "Support technique", "Démo personnalisée", "Presse / partenariat"].map(s => <option key={s}>{s}</option>)}
                      </select>
                    </div>
                    <div>
                      <label style={labelStyle}>Message</label>
                      <textarea value={form.message} onChange={e => setForm({...form, message: e.target.value})} rows={5} style={{...inputStyle, resize: "vertical", minHeight: 120, fontFamily: "inherit"}} placeholder="Parlez-nous de votre activité, on adore les détails…"/>
                    </div>
                    <button type="submit" disabled={busy} className="btn btn-primary btn-lg" style={{ width: "100%", marginTop: 6, opacity: busy ? 0.7 : 1 }}>
                      {busy ? "Envoi…" : "Envoyer le message"}
                    </button>
                  </div>
                </>
              )}
            </form>
          </div>
          )}
        </div>
      </section>

      {/* FAQ, déplacée depuis la page tarif */}
      <section style={{
        padding: "60px 0 96px",
        background: "var(--bg-section)", borderTop: "1px solid var(--line)",
      }}>
        <div className="container" style={{ maxWidth: 760 }}>
          <div style={{ textAlign: "center", marginBottom: 28 }}>
            <div style={{
              display: "inline-flex", alignItems: "center", gap: 8,
              padding: "5px 12px 5px 10px",
              background: "var(--accent-soft)", border: "1px solid var(--accent-soft-2)",
              borderRadius: 999, fontSize: 11.5, fontWeight: 600,
              color: "var(--accent-ink)", letterSpacing: "0.04em", textTransform: "uppercase",
            }}>
              <Icon name="chat" size={11}/>
              Questions fréquentes
            </div>
            <h2 style={{ fontSize: "clamp(24px, 3vw, 30px)", marginTop: 12, letterSpacing: "-0.025em" }}>
              On a peut-être déjà la réponse
            </h2>
          </div>
          <div style={{
            background: "var(--surface)", border: "1px solid var(--line)",
            borderRadius: 16, overflow: "hidden",
          }}>
            {(window.CONTACT_FAQ || []).map(([q, a], i, arr) => (
              <details key={i} style={{
                borderBottom: i < arr.length - 1 ? "1px solid var(--line)" : "none",
                padding: "18px 22px",
              }}>
                <summary style={{
                  fontSize: 15, fontWeight: 520, cursor: "pointer",
                  listStyle: "none", display: "flex", justifyContent: "space-between", alignItems: "center",
                  color: "var(--ink)", gap: 12,
                }}>
                  <span>{q}</span>
                  <Icon name="plus" size={15} style={{ color: "var(--ink-3)", flexShrink: 0 }}/>
                </summary>
                <p style={{ marginTop: 10, fontSize: 14, lineHeight: 1.6, color: "var(--ink-2)" }}>{a}</p>
              </details>
            ))}
          </div>
        </div>
      </section>
    </>
  );
};

/* ============ AUTH SHELL, template visuel partagé Pro/Client ============
   Utilisé par LoginPage (Pro) ET EspaceLogin (Client). Garantit que les deux
   parcours ont exactement le même look : split layout (form gauche, panneau
   marketing droite), eyebrow + h1 + subtitle, animations cohérentes.
   Seules les props et le contenu marketing changent selon le rôle. */
const AUTH_ASIDE_CONTENT = {
  pro: {
    eyebrow: "Programme bêta",
    title: "Ce que vous obtenez en rejoignant maintenant",
    bullets: [
      "Toutes les fonctionnalités, gratuitement, pendant toute la bêta",
      "Accès direct à l'équipe pour vos retours et demandes",
      "On fait évoluer l'outil selon vos vrais besoins du quotidien",
    ],
    contactLine: "Une question avant de vous inscrire ?",
  },
  client: {
    eyebrow: "Compte client centralisé",
    title: "Un seul compte pour tous vos pros ClientBase",
    bullets: [
      "Tous vos RDV chez tous vos pros ClientBase au même endroit",
      "Annulation et report en un clic, historique complet",
      "Gratuit, sans pub, RGPD : vos données ne sont jamais revendues",
    ],
    contactLine: "Un problème pour vous connecter ?",
  },
};

const AuthShell = ({
  role = "pro",          // "pro" | "client"
  eyebrow,               // override du badge en haut du form
  title,
  subtitle,
  error,
  info,
  topSlot,               // contenu personnalisé entre subtitle et form (ex : avatar live preview)
  children,              // les champs du formulaire (form fields)
  bottomSlot,            // contenu personnalisé sous le formulaire (ex : trust badges)
  onSubmit,              // (e) => void
  submitting,            // bool
  submitLabel = "Continuer",
  switchLink,            // { text, action } pour basculer login/signup
}) => {
  const aside = AUTH_ASIDE_CONTENT[role] || AUTH_ASIDE_CONTENT.pro;
  return (
    <section style={{ minHeight: "calc(100vh - 64px)", display: "flex", alignItems: "stretch", position: "relative", overflow: "hidden" }}>
      <style>{`
        @keyframes cbAuthFadeUp {
          from { opacity: 0; transform: translateY(10px); }
          to   { opacity: 1; transform: translateY(0); }
        }
        @keyframes cbAuthSparkle {
          0%, 100% { transform: rotate(0) scale(1); opacity: 1; }
          50%      { transform: rotate(180deg) scale(1.15); opacity: 0.85; }
        }
        @keyframes cbAuthBadgePulse {
          0%, 100% { box-shadow: 0 4px 12px -3px var(--cb-auth-glow), 0 0 0 0 color-mix(in oklab, var(--cb-auth-glow) 40%, transparent); }
          50%      { box-shadow: 0 6px 16px -3px var(--cb-auth-glow), 0 0 0 8px color-mix(in oklab, var(--cb-auth-glow) 0%, transparent); }
        }
        @keyframes cbAuthBadgeFloat {
          0%, 100% { transform: translateY(0) rotate(0); }
          50%      { transform: translateY(-1.5px) rotate(-3deg); }
        }
        @keyframes cbAuthFieldPulse {
          0%, 100% { opacity: 0.65; transform: translateY(0); }
          50%      { opacity: 1;    transform: translateY(-1px); }
        }
        .cb-auth-badge:hover .cb-auth-badge-icon {
          transform: rotate(15deg) scale(1.08);
        }
        .cb-auth-field { animation: cbAuthFadeUp .5s cubic-bezier(.22,1,.36,1) both; }
        .cb-auth-field:nth-child(1) { animation-delay: 0.05s; }
        .cb-auth-field:nth-child(2) { animation-delay: 0.10s; }
        .cb-auth-field:nth-child(3) { animation-delay: 0.15s; }
        .cb-auth-field:nth-child(4) { animation-delay: 0.20s; }
        .cb-auth-field:nth-child(5) { animation-delay: 0.25s; }
        @media (max-width: 900px) {
          .cb-auth-aside { display: none !important; }
        }
      `}</style>

      <div aria-hidden style={{
        position: "absolute", inset: 0, pointerEvents: "none",
        background: "radial-gradient(ellipse 50% 45% at 50% 20%, var(--accent-soft) 0%, transparent 70%)",
        opacity: 0.6,
      }}/>

      <div style={{ flex: 1, display: "flex", alignItems: "center", justifyContent: "center", padding: "40px 24px", position: "relative" }}>
        <div style={{ width: "100%", maxWidth: 440 }}>
          {/* Eyebrow = compteur live « X utilisateurs sur ClientBase » à la
              place de l'ancien badge de rôle. La couleur reste audience-aware
              (indigo pour pro, cli-accent pour client) pour ne pas perdre
              le repère visuel pro/client. */}
          <div style={{
            marginBottom: 18,
            animation: "cbAuthFadeUp .45s cubic-bezier(.22,1,.36,1) both",
          }}>
            {window.LiveProsBadge
              ? React.createElement(window.LiveProsBadge, {
                  tone: role === "client" ? "var(--cli-accent)" : "var(--accent)",
                })
              : null}
          </div>

          <h1 style={{ fontSize: "clamp(28px, 4vw, 36px)", letterSpacing: "-0.025em", lineHeight: 1.1, margin: 0 }}>
            {title}
          </h1>
          {subtitle && (
            <p style={{ marginTop: 10, fontSize: 15, color: "var(--ink-3)" }}>{subtitle}</p>
          )}

          {topSlot}

          {error && (typeof error === "object" && error.kind === "wrongAudience" ? (
            // Variante riche : message + CTA vers le bon flow.
            <div style={{
              marginTop: 20, padding: "14px 16px",
              background: "var(--accent-soft)", border: "1px solid var(--accent-soft-2)",
              borderRadius: 12,
            }}>
              <div style={{
                fontSize: 13.5, fontWeight: 600, color: "var(--accent-ink)",
                display: "flex", alignItems: "flex-start", gap: 8,
              }}>
                <span aria-hidden style={{ fontSize: 16, lineHeight: 1 }}>⚠️</span>
                <span style={{ flex: 1 }}>{error.text}</span>
              </div>
              <div style={{ fontSize: 12.5, color: "var(--ink-2)", marginTop: 6, lineHeight: 1.5 }}>
                On a pré-enregistré votre email pour vous éviter de tout retaper.
              </div>
              <a href={error.ctaHref}
                style={{
                  display: "inline-flex", alignItems: "center", gap: 6,
                  marginTop: 12, padding: "9px 14px",
                  background: "var(--accent)", color: "#fff",
                  borderRadius: 999, textDecoration: "none",
                  fontSize: 13, fontWeight: 580,
                }}>
                {error.ctaLabel}
              </a>
            </div>
          ) : (
            <div style={{
              marginTop: 20, padding: "10px 14px",
              background: "oklch(96% 0.04 25)", border: "1px solid oklch(88% 0.06 25)",
              color: "oklch(42% 0.15 25)", borderRadius: 10, fontSize: 13.5,
            }}>{typeof error === "object" ? (error.text || "Erreur") : error}</div>
          ))}
          {info && (
            <div style={{
              marginTop: 20, padding: "12px 14px",
              background: "var(--sage-soft)", border: "1px solid oklch(88% 0.03 160)",
              color: "oklch(38% 0.08 160)", borderRadius: 10, fontSize: 13.5,
              display: "flex", gap: 10, alignItems: "flex-start",
            }}>
              <Icon name="mail" size={16} style={{ flexShrink: 0, marginTop: 2 }}/>
              <div>{info}</div>
            </div>
          )}

          <form onSubmit={onSubmit} style={{ marginTop: 22, display: "grid", gap: 14 }}>
            {children}
            {/* Submit en couleur d'audience (indigo pro / violet client)
                au lieu d'ink noir → cohérent avec le pill Compte et le
                CTA principal de la home. */}
            <button type="submit" disabled={submitting}
              className="btn btn-lg"
              style={{
                width: "100%", marginTop: 6,
                opacity: submitting ? 0.7 : 1,
                background: role === "client" ? "var(--cli-accent)" : "var(--accent)",
                color: "#fff", border: "none",
                boxShadow: `0 12px 28px -12px ${role === "client" ? "var(--cli-accent)" : "var(--accent)"}`,
              }}>
              {submitting ? "…" : submitLabel}
            </button>
          </form>

          {switchLink && (
            <div style={{ marginTop: 24, fontSize: 13.5, textAlign: "center", color: "var(--ink-3)" }}>
              {switchLink.text}{" "}
              <a href="#" onClick={(e) => { e.preventDefault(); switchLink.action(); }}
                style={{ color: "var(--accent-ink)", fontWeight: 520 }}>
                {switchLink.label}
              </a>
            </div>
          )}

          {bottomSlot}
        </div>
      </div>

      {/* Panneau marketing, caché en mobile */}
      <div className="cb-auth-aside login-aside" style={{
        flex: 1, background: "var(--bg-section)",
        borderLeft: "1px solid var(--line)",
        display: "flex", alignItems: "center", justifyContent: "center", padding: 40,
        position: "relative", overflow: "hidden",
      }}>
        <div aria-hidden style={{
          position: "absolute", inset: 0,
          backgroundImage: "radial-gradient(circle at 1px 1px, var(--line) 1px, transparent 0)",
          backgroundSize: "28px 28px", opacity: 0.6,
        }}/>
        <div style={{ position: "relative", maxWidth: 420 }}>
          <div className="card" style={{ padding: 28, boxShadow: "var(--sh-3)" }}>
            <div style={{
              display: "inline-flex", alignItems: "center", gap: 8,
              padding: "4px 10px 4px 8px",
              background: "var(--accent-soft)", color: "var(--accent-ink)",
              borderRadius: 999, fontSize: 12, fontWeight: 520,
            }}>
              <Icon name="sparkle" size={12}/> {aside.eyebrow}
            </div>
            <h3 style={{ marginTop: 14, fontSize: 22 }}>{aside.title}</h3>
            <ul style={{ listStyle: "none", padding: 0, margin: "20px 0 0", display: "flex", flexDirection: "column", gap: 12 }}>
              {aside.bullets.map(t => (
                <li key={t} style={{ display: "flex", gap: 10, alignItems: "flex-start", fontSize: 14, color: "var(--ink-2)", lineHeight: 1.5 }}>
                  <span style={{
                    width: 20, height: 20, borderRadius: 50,
                    background: "var(--sage-soft)", color: "var(--sage)",
                    display: "inline-flex", alignItems: "center", justifyContent: "center",
                    flexShrink: 0, marginTop: 1,
                  }}>
                    <Icon name="check" size={12} stroke={2.6}/>
                  </span>
                  {t}
                </li>
              ))}
            </ul>
          </div>
          <div style={{
            marginTop: 20, padding: 18,
            background: "var(--surface)", border: "1px solid var(--line)",
            borderRadius: 12, fontSize: 13, color: "var(--ink-3)", lineHeight: 1.6,
          }}>
            <div style={{ fontWeight: 520, color: "var(--ink)", fontSize: 13.5 }}>💬 {aside.contactLine}</div>
            <div style={{ marginTop: 6 }}>
              Écrivez à <strong style={{ color: "var(--ink-2)" }}>{CB_CONTACT_EMAIL}</strong>, on répond toujours sous <span style={{ whiteSpace: "nowrap" }}>24 h</span>.
            </div>
          </div>
        </div>
      </div>
    </section>
  );
};

/* ============ AUTH EMAIL SENT, écran de confirmation après signup ============
   Affiché après la création de compte (Pro et Client). L'utilisateur peut :
   - cliquer sur le lien reçu par email pour activer son compte
   - renvoyer l'email s'il ne l'a pas reçu (avec cooldown anti-spam)
   - modifier l'adresse email (revient au formulaire signup avec l'email pré-rempli)
*/
const AuthEmailSent = ({ email, role = "pro", onEdit, onResend }) => {
  const [resentAt, setResentAt] = React.useState(0);
  const [resending, setResending] = React.useState(false);
  const cooldownSec = 30;
  const remaining = Math.max(0, cooldownSec - Math.floor((Date.now() - resentAt) / 1000));
  const [tick, setTick] = React.useState(0);
  React.useEffect(() => {
    if (remaining <= 0) return;
    const t = setInterval(() => setTick(x => x + 1), 1000);
    return () => clearInterval(t);
  }, [remaining]);

  const handleResend = async () => {
    if (remaining > 0 || resending) return;
    setResending(true);
    try {
      if (onResend) await onResend();
      setResentAt(Date.now());
    } finally {
      setResending(false);
    }
  };

  const aside = AUTH_ASIDE_CONTENT[role] || AUTH_ASIDE_CONTENT.pro;

  return (
    <section style={{ minHeight: "calc(100vh - 64px)", display: "flex", alignItems: "stretch", position: "relative", overflow: "hidden" }}>
      <style>{`
        @keyframes cbEmailPulse {
          0%, 100% { transform: scale(1); box-shadow: 0 0 0 0 color-mix(in oklab, var(--accent) 30%, transparent); }
          50%      { transform: scale(1.04); box-shadow: 0 0 0 14px color-mix(in oklab, var(--accent) 0%, transparent); }
        }
        @keyframes cbEmailFloat {
          0%, 100% { transform: translateY(0); }
          50%      { transform: translateY(-4px); }
        }
        @media (max-width: 900px) {
          .cb-auth-aside { display: none !important; }
        }
      `}</style>
      <div aria-hidden style={{
        position: "absolute", inset: 0, pointerEvents: "none",
        background: "radial-gradient(ellipse 50% 45% at 50% 20%, var(--accent-soft) 0%, transparent 70%)",
        opacity: 0.6,
      }}/>
      <div style={{ flex: 1, display: "flex", alignItems: "center", justifyContent: "center", padding: "40px 24px", position: "relative" }}>
        <div style={{ width: "100%", maxWidth: 440, textAlign: "center" }}>
          <div style={{
            width: 80, height: 80, borderRadius: 22, margin: "0 auto 22px",
            background: "linear-gradient(135deg, var(--accent) 0%, oklch(48% 0.20 300) 100%)",
            color: "#fff",
            display: "inline-flex", alignItems: "center", justifyContent: "center",
            boxShadow: "0 14px 32px -14px var(--accent)",
            animation: "cbEmailFloat 3.5s ease-in-out infinite, cbEmailPulse 2.5s ease-in-out infinite",
          }}>
            <Icon name="mail" size={36} stroke={1.6}/>
          </div>
          <h1 style={{
            fontSize: "clamp(26px, 3.6vw, 34px)", letterSpacing: "-0.025em",
            lineHeight: 1.15, margin: 0,
          }}>
            Vérifiez votre boîte mail
          </h1>
          <p style={{ marginTop: 12, fontSize: 15, color: "var(--ink-2)", lineHeight: 1.55 }}>
            On vient d'envoyer un email à
          </p>
          <div style={{
            marginTop: 6, padding: "10px 16px",
            background: "var(--surface)", border: "1px solid var(--line-strong)",
            borderRadius: 12, fontSize: 15, fontWeight: 580,
            color: "var(--ink)", display: "inline-block",
            fontFamily: "var(--ff-mono)",
            boxShadow: "var(--sh-1)",
          }}>
            {email}
          </div>
          <p style={{ marginTop: 16, fontSize: 13.5, color: "var(--ink-3)", lineHeight: 1.55 }}>
            Cliquez sur le lien dans cet email pour activer votre compte
            {role === "pro" ? " professionnel." : " client."}<br/>
            Le lien expire dans 24 heures.
          </p>

          <div style={{
            marginTop: 22, padding: "14px 16px",
            background: "var(--bg-alt)", border: "1px solid var(--line)",
            borderRadius: 12, fontSize: 12.5, color: "var(--ink-3)", lineHeight: 1.55,
            textAlign: "left",
          }}>
            <div style={{ fontWeight: 580, color: "var(--ink-2)", marginBottom: 6 }}>
              📬 Pas reçu d'email ?
            </div>
            <ul style={{ listStyle: "none", padding: 0, margin: 0, display: "flex", flexDirection: "column", gap: 4 }}>
              <li>• Vérifiez votre dossier spam / courriers indésirables</li>
              <li>• Patientez 1 à 2 minutes, l'envoi peut prendre du temps</li>
              <li>• Vérifiez que <strong>{email}</strong> est bien la bonne adresse</li>
            </ul>
          </div>

          <div style={{
            marginTop: 22, display: "flex", flexDirection: "column", gap: 9,
          }}>
            <button onClick={handleResend} disabled={remaining > 0 || resending}
              className="btn btn-ghost btn-lg"
              style={{
                width: "100%",
                opacity: (remaining > 0 || resending) ? 0.6 : 1,
                cursor: (remaining > 0 || resending) ? "not-allowed" : "pointer",
              }}>
              {resending ? "Envoi en cours…"
                : remaining > 0 ? `Renvoyer l'email (dans ${remaining}s)`
                : "Renvoyer l'email"}
            </button>
            <button onClick={onEdit}
              style={{
                background: "transparent", border: "none", cursor: "pointer",
                color: "var(--ink-3)", fontSize: 13, fontFamily: "inherit",
                textDecoration: "underline", padding: "6px 8px",
              }}>
              Modifier mon adresse email
            </button>
          </div>
        </div>
      </div>

      {/* Panneau marketing, caché en mobile */}
      <div className="cb-auth-aside login-aside" style={{
        flex: 1, background: "var(--bg-section)",
        borderLeft: "1px solid var(--line)",
        display: "flex", alignItems: "center", justifyContent: "center", padding: 40,
        position: "relative", overflow: "hidden",
      }}>
        <div aria-hidden style={{
          position: "absolute", inset: 0,
          backgroundImage: "radial-gradient(circle at 1px 1px, var(--line) 1px, transparent 0)",
          backgroundSize: "28px 28px", opacity: 0.6,
        }}/>
        <div style={{ position: "relative", maxWidth: 420 }}>
          <div className="card" style={{ padding: 28, boxShadow: "var(--sh-3)" }}>
            <div style={{
              display: "inline-flex", alignItems: "center", gap: 8,
              padding: "4px 10px 4px 8px",
              background: "var(--sage-soft)", color: "var(--sage)",
              borderRadius: 999, fontSize: 12, fontWeight: 520,
            }}>
              <Icon name="check" size={12}/> Compte créé
            </div>
            <h3 style={{ marginTop: 14, fontSize: 22 }}>Plus qu'une étape</h3>
            <p style={{ marginTop: 14, fontSize: 14, color: "var(--ink-2)", lineHeight: 1.6 }}>
              On vérifie votre adresse email pour sécuriser votre compte et vous éviter le spam.
              Cliquez sur le lien dans l'email qu'on vient de vous envoyer et c'est parti.
            </p>
            <ul style={{ listStyle: "none", padding: 0, margin: "20px 0 0", display: "flex", flexDirection: "column", gap: 12 }}>
              {aside.bullets.map(t => (
                <li key={t} style={{ display: "flex", gap: 10, alignItems: "flex-start", fontSize: 13.5, color: "var(--ink-3)", lineHeight: 1.5 }}>
                  <span style={{
                    width: 18, height: 18, borderRadius: 50,
                    background: "var(--accent-soft)", color: "var(--accent)",
                    display: "inline-flex", alignItems: "center", justifyContent: "center",
                    flexShrink: 0, marginTop: 1,
                  }}>
                    <Icon name="check" size={10} stroke={2.6}/>
                  </span>
                  {t}
                </li>
              ))}
            </ul>
          </div>
        </div>
      </div>
    </section>
  );
};

const labelStyle = { display: "block", fontSize: 13, fontWeight: 500, color: "var(--ink-2)", marginBottom: 6 };
// Sous-ligne explicative placée entre le label et l'input, pour préciser
// l'usage du champ (« visible sur votre page de RDV », « apparaît sur vos
// factures », etc.). Reste discrète en var(--ink-4) pour ne pas alourdir.
const fieldHintStyle = {
  fontSize: 11.5, color: "var(--ink-4)",
  marginTop: -3, marginBottom: 7, lineHeight: 1.4,
};
const inputStyle = {
  width: "100%", padding: "11px 14px", fontSize: 16, fontFamily: "inherit",
  background: "var(--bg)", border: "1px solid var(--line-strong)", borderRadius: 9,
  color: "var(--ink)", outline: "none",
  transition: "border-color .15s, box-shadow .15s",
};

const Field = ({ label, type = "text", value, onChange, placeholder }) => (
  <div>
    <label style={labelStyle}>{label}</label>
    <input type={type} value={value} onChange={e => onChange(e.target.value)} placeholder={placeholder} style={inputStyle}/>
  </div>
);

// Suggestion email : si l'utilisateur tape un local + un fragment de domaine
// connu (ex « marie@gmai »), on lui propose la complétion via Tab ou un clic
// sur la pill juste sous l'input. Couvre les 12 domaines les plus utilisés
// en France pour éviter les fautes de frappe gmail.con / hotmial / etc.
const COMMON_EMAIL_DOMAINS = [
  "gmail.com", "outlook.com", "outlook.fr", "hotmail.com", "hotmail.fr",
  "yahoo.com", "yahoo.fr", "free.fr", "orange.fr", "sfr.fr",
  "laposte.net", "wanadoo.fr", "icloud.com", "me.com", "live.fr", "bbox.fr",
];
const cbSuggestEmail = (raw) => {
  const v = (raw || "").trim();
  const at = v.indexOf("@");
  if (at < 1) return null;
  const local = v.slice(0, at);
  const frag  = v.slice(at + 1).toLowerCase();
  if (!frag) return null;
  // Si déjà un domaine complet, pas de suggestion.
  if (COMMON_EMAIL_DOMAINS.includes(frag)) return null;
  // Sinon, trouve le 1er domaine qui démarre par le fragment.
  const hit = COMMON_EMAIL_DOMAINS.find(d => d.startsWith(frag));
  if (!hit) return null;
  return `${local}@${hit}`;
};
if (typeof window !== "undefined") {
  window.cbSuggestEmail = cbSuggestEmail;
  window.COMMON_EMAIL_DOMAINS = COMMON_EMAIL_DOMAINS;
}

// Pill cliquable affichant la suggestion email. Accepte au clic OU à Tab.
// Composant minimal pour pouvoir l'insérer sous n'importe quel input email.
const EmailSuggestPill = ({ value, onAccept, tone = "var(--accent)" }) => {
  const suggestion = cbSuggestEmail(value);
  if (!suggestion) return null;
  return (
    <div style={{
      marginTop: 6,
      display: "flex", alignItems: "center", gap: 6,
      fontSize: 11.5, color: "var(--ink-4)",
      animation: "cbAuthFadeUp .25s cubic-bezier(.22,1,.36,1) both",
    }}>
      <span>Vouliez-vous dire</span>
      <button type="button" onClick={() => onAccept(suggestion)}
        title="Appuyez sur Tab ou cliquez pour utiliser"
        style={{
          padding: "2px 8px",
          background: "color-mix(in oklab, " + tone + " 8%, var(--surface))",
          border: "1px solid color-mix(in oklab, " + tone + " 32%, var(--line))",
          borderRadius: 999,
          fontSize: 11.5, fontWeight: 540, color: tone,
          cursor: "pointer", fontFamily: "inherit",
        }}>
        {suggestion}
      </button>
      <span style={{
        fontSize: 10, color: "var(--ink-4)",
        padding: "1px 5px", background: "var(--bg-alt)",
        border: "1px solid var(--line)", borderRadius: 4,
      }}>Tab</span>
    </div>
  );
};
if (typeof window !== "undefined") {
  window.EmailSuggestPill = EmailSuggestPill;
}

/* Password field — œil toggle + checklist anime­e des 5 critères de
   sécurité (à la « modern SaaS ») quand showMeter=true. Chaque critère
   qui devient OK scale+fade in et fait monter une jauge de force. */
const PASSWORD_CRITERIA = [
  { key: "len",    label: "10 caractères ou plus" },
  { key: "upper",  label: "Au moins 1 majuscule (A-Z)" },
  { key: "lower",  label: "Au moins 1 minuscule (a-z)" },
  { key: "digit",  label: "Au moins 1 chiffre (0-9)" },
  { key: "symbol", label: "Au moins 1 caractère spécial (! ? @ …)" },
];
const PasswordField = ({ value, onChange, placeholder = "••••••••", autoComplete = "current-password", showMeter = false }) => {
  const [shown, setShown] = React.useState(false);
  // Caps Lock detector : on capture l'état du modificateur sur le clavier,
  // utile surtout en login où un mot de passe en CAPS LOCK provoque un
  // « mot de passe incorrect » mystérieux. On affiche une pill discrète
  // sous l'input dès que l'utilisateur a focus + Caps Lock activé.
  const [capsOn, setCapsOn] = React.useState(false);
  const [focused, setFocused] = React.useState(false);
  const onKey = (e) => {
    try { setCapsOn(e.getModifierState && e.getModifierState("CapsLock")); } catch {}
  };
  const rules = (window.passwordRules || (() => ({})))(value || "");
  const score = Object.values(rules).filter(Boolean).length;
  const bands = [
    { label: "trop faible", color: "oklch(70% 0.18 25)"  },
    { label: "faible",      color: "oklch(70% 0.17 50)"  },
    { label: "moyen",       color: "oklch(75% 0.15 85)"  },
    { label: "bon",         color: "oklch(72% 0.14 160)" },
    { label: "très bon",    color: "oklch(62% 0.16 160)" },
    { label: "excellent",   color: "var(--accent)"       },
  ];
  const band = bands[score] || bands[0];
  // Emoji live de force du mot de passe (0→5), réactif comme la jauge.
  // Donne un repère émotionnel instantané, plus fun que le label texte seul.
  const emojis = ["😬", "😬", "🤔", "🙂", "😊", "💪"];
  const pwdEmoji = value ? emojis[score] : "";
  return (
    <div>
      <div style={{ position: "relative" }}>
        <input
          type={shown ? "text" : "password"}
          value={value}
          onChange={e => onChange(e.target.value)}
          onKeyDown={onKey}
          onKeyUp={onKey}
          onFocus={() => setFocused(true)}
          onBlur={() => setFocused(false)}
          placeholder={placeholder}
          autoComplete={autoComplete}
          style={{ ...inputStyle, paddingRight: 44 }}
        />
        <button type="button" onClick={() => setShown(!shown)}
          aria-label={shown ? "Masquer le mot de passe" : "Afficher le mot de passe"}
          style={{
            position: "absolute", right: 6, top: "50%", transform: "translateY(-50%)",
            width: 34, height: 34, background: "transparent", border: "none",
            display: "inline-flex", alignItems: "center", justifyContent: "center",
            cursor: "pointer", color: "var(--ink-4)", borderRadius: 6,
          }}>
          <Icon name={shown ? "eyeOff" : "eye"} size={16}/>
        </button>
      </div>
      {/* Avertissement Caps Lock : pop discret quand focus + caps lock activé */}
      {capsOn && focused && (
        <div style={{
          marginTop: 6, padding: "5px 10px",
          display: "inline-flex", alignItems: "center", gap: 6,
          background: "oklch(97% 0.04 60)", color: "oklch(40% 0.16 60)",
          border: "1px solid oklch(86% 0.10 60)", borderRadius: 8,
          fontSize: 11.5, fontWeight: 540,
          animation: "cbAuthFadeUp .22s cubic-bezier(.22,1,.36,1) both",
        }}>
          <span aria-hidden style={{ fontSize: 13 }}>⇪</span>
          Caps Lock est activé
        </div>
      )}
      {showMeter && (
        <div style={{ marginTop: 8 }}>
          {/* Jauge 5 segments qui se remplit dans la couleur du band */}
          <div style={{ display: "flex", alignItems: "center", gap: 10 }}>
            <div style={{ flex: 1, display: "flex", gap: 3 }}>
              {[0, 1, 2, 3, 4].map(i => (
                <div key={i} style={{
                  flex: 1, height: 5, borderRadius: 999,
                  background: i < score ? band.color : "var(--line)",
                  transition: "background .25s cubic-bezier(.22,1,.36,1)",
                }}/>
              ))}
            </div>
            <span style={{
              display: "inline-flex", alignItems: "center", gap: 4,
              fontSize: 11, color: band.color, fontWeight: 600,
              minWidth: 76, textAlign: "right", justifyContent: "flex-end",
              transition: "color .2s ease",
            }}>
              {pwdEmoji && (
                <span
                  key={pwdEmoji}
                  aria-hidden
                  style={{
                    fontSize: 14, lineHeight: 1,
                    animation: "cbPwdEmojiPop .3s cubic-bezier(.5,1.6,.4,1) both",
                  }}>{pwdEmoji}</span>
              )}
              {value ? band.label : ""}
            </span>
          </div>
          {/* Checklist : chaque critère, ✓ animé quand validé, ○ sinon */}
          <ul style={{
            listStyle: "none", padding: 0,
            margin: "10px 0 0",
            display: "grid", gridTemplateColumns: "1fr 1fr", gap: "5px 14px",
          }}>
            {PASSWORD_CRITERIA.map(c => {
              const ok = !!rules[c.key];
              return (
                <li key={c.key} style={{
                  display: "flex", alignItems: "center", gap: 7,
                  fontSize: 11.5, lineHeight: 1.35,
                  color: ok ? "var(--sage-ink)" : "var(--ink-4)",
                  transition: "color .25s ease",
                }}>
                  <span aria-hidden style={{
                    width: 16, height: 16, borderRadius: "50%",
                    background: ok ? "var(--sage)" : "transparent",
                    border: ok ? "1.5px solid var(--sage)" : "1.5px solid var(--line-strong)",
                    color: "#fff", flexShrink: 0,
                    display: "inline-flex", alignItems: "center", justifyContent: "center",
                    transform: ok ? "scale(1)" : "scale(0.85)",
                    transition: "background .25s ease, border-color .25s ease, transform .3s cubic-bezier(.5,1.6,.4,1)",
                  }}>
                    {ok && (
                      <svg width="9" height="9" viewBox="0 0 24 24" fill="none"
                        stroke="currentColor" strokeWidth="3.6" strokeLinecap="round" strokeLinejoin="round"
                        style={{ animation: "cbPwdCheck .35s cubic-bezier(.5,1.6,.4,1) both" }}>
                        <path d="M5 12l4 4 10-10"/>
                      </svg>
                    )}
                  </span>
                  <span>{c.label}</span>
                </li>
              );
            })}
          </ul>
          <style>{`
            @keyframes cbPwdCheck {
              from { opacity: 0; transform: scale(0.4); }
              to   { opacity: 1; transform: scale(1); }
            }
            @keyframes cbPwdEmojiPop {
              0%   { opacity: 0; transform: scale(0.5) translateY(2px); }
              60%  { transform: scale(1.15) translateY(0); }
              100% { opacity: 1; transform: scale(1) translateY(0); }
            }
          `}</style>
        </div>
      )}
    </div>
  );
};

// Expose PasswordField + critères au scope global pour que les autres
// fichiers (notamment pages-espace.jsx) puissent réutiliser exactement
// le même composant sans dupliquer la checklist animée + la jauge.
if (typeof window !== "undefined") {
  window.PasswordField = PasswordField;
  window.PASSWORD_CRITERIA = PASSWORD_CRITERIA;
}

/* ============ LOGIN / SIGNUP PAGE ============
   `forcedMode` est passé par le routeur (page="login" → "login",
   page="signup" → "signup"). Les modes `forgot` et `reset` sont atteints
   depuis la page login. */
const LoginPage = ({ go, forcedMode }) => {
  const existingUser = cbAuth.getCurrentUser();
  // Détecte un retour de lien "mot de passe oublié" (?reset=1 dans l'URL)
  const comingFromReset = typeof window !== "undefined"
    && new URLSearchParams(window.location.search).get("reset") === "1";

  const [mode, setMode] = React.useState(() => {
    if (comingFromReset) return "reset";
    if (forcedMode === "login" || forcedMode === "signup") return forcedMode;
    const intent = window.__cbLoginMode;
    window.__cbLoginMode = null;
    if (intent === "login" || intent === "signup") return intent;
    return existingUser ? "login" : "signup";
  });
  // Si la route change (navigation depuis la nav), on réaligne
  React.useEffect(() => {
    if (forcedMode === "login" || forcedMode === "signup") setMode(forcedMode);
    // eslint-disable-next-line
  }, [forcedMode]);
  // Pré-remplissage email si rejet précédent côté espace client (stash
  // dans sessionStorage par EspaceLogin). Consommé une seule fois.
  const initialEmail = (() => {
    if (existingUser && existingUser.email) return existingUser.email;
    try {
      const e = sessionStorage.getItem("cb_prefill_email");
      if (e) { sessionStorage.removeItem("cb_prefill_email"); return e; }
    } catch {}
    return "";
  })();
  const [form, setForm] = React.useState({
    email: initialEmail,
    password: "",
    passwordConfirm: "",
    businessName: "",
    ownerName: "",
    phone: "",
    rgpd: false,
  });
  const [error, setError] = React.useState(null);
  const [info, setInfo] = React.useState(null);
  const [busy, setBusy] = React.useState(false);
  // Email destinataire de l'écran "Vérifiez votre boîte mail", non-null = on
  // affiche l'écran de confirmation au lieu du formulaire.
  const [emailSentTo, setEmailSentTo] = React.useState(null);

  const switchMode = (m) => { setError(null); setInfo(null); setMode(m); };

  const onSubmit = async (e) => {
    e.preventDefault();
    setError(null);
    setInfo(null);
    setBusy(true);
    try {
      if (mode === "signup") {
        if (!cbAuth.isValidEmail(form.email)) { setError("Email invalide. Exemple : prenom@exemple.fr"); setBusy(false); return; }
        if (!form.rgpd) { setError("Vous devez accepter la politique de confidentialité."); setBusy(false); return; }
        if (!form.ownerName.trim()) { setError("Votre nom est requis."); setBusy(false); return; }
        if (!form.businessName.trim()) { setError("Le nom de votre activité est requis."); setBusy(false); return; }
        if (!form.phone.trim()) { setError("Votre téléphone est requis (visible sur vos factures et votre page de RDV)."); setBusy(false); return; }
        if (form.phone.replace(/\D/g, "").length < 9) { setError("Téléphone invalide (au moins 9 chiffres)."); setBusy(false); return; }
        const res = await cbAuth.signup(form);
        if (res.error) { setError(res.error); setBusy(false); return; }
        // Toujours afficher l'écran de confirmation email après un signup pro,
        // que Supabase exige la confirmation ou pas. Si la session est déjà
        // active (Confirm email OFF côté admin), l'utilisateur peut quand
        // même cliquer sur le lien (no-op) ou aller direct dans l'app, on
        // garde l'écran pour donner une UX uniforme avec le compte client.
        try { localStorage.setItem("cb_last_audience", "pro"); } catch {}
        setEmailSentTo(form.email);
        setBusy(false);
        return;
      } else if (mode === "login") {
        const res = await cbAuth.login(form);
        if (res.error) {
          // Si l'email correspond à un compte CLIENT, on stash l'email
          // dans sessionStorage pour le pré-remplir côté espace client
          // après redirect, puis on offre un CTA "Aller à l'espace
          // client" via une variante d'erreur "wrongAudience".
          if (res.wrongAudience === "client") {
            try { sessionStorage.setItem("cb_prefill_email", res.email || form.email || ""); } catch {}
            setError({
              kind: "wrongAudience",
              text: "Cet email correspond à un compte CLIENT, pas pro.",
              ctaLabel: "Continuer vers l'espace client →",
              ctaHref: "/?espace=login",
            });
          } else {
            setError(res.error);
          }
          setBusy(false); return;
        }
        // Mémorise le rôle pour que la nav vitrine après logout propose
        // « Mon espace pro » plutôt qu'un compte vide ambigu.
        try { localStorage.setItem("cb_last_audience", "pro"); } catch {}
        go("app");
      } else if (mode === "forgot") {
        const res = await cbAuth.resetPassword(form.email);
        if (res.error) { setError(res.error); setBusy(false); return; }
        setInfo(`Un email vient d'être envoyé à ${form.email}. Cliquez sur le lien qu'il contient pour choisir un nouveau mot de passe.`);
      } else if (mode === "reset") {
        if (form.password !== form.passwordConfirm) { setError("Les deux mots de passe ne correspondent pas."); setBusy(false); return; }
        const res = await cbAuth.updatePassword(form.password);
        if (res.error) { setError(res.error); setBusy(false); return; }
        // Nettoie l'URL pour éviter de réappliquer au reload
        try { window.history.replaceState({}, "", window.location.pathname); } catch {}
        setInfo("Mot de passe modifié. Vous êtes maintenant connecté·e.");
        setTimeout(() => go("app"), 700);
      }
    } finally {
      setBusy(false);
    }
  };

  const title = mode === "login"   ? "Bon retour."
             : mode === "signup"   ? "Rejoindre la bêta."
             : mode === "forgot"   ? "Mot de passe oublié"
             : /* reset */           "Nouveau mot de passe";
  const subtitle = mode === "login"   ? "Connectez-vous pour retrouver votre agenda et vos clients."
                : mode === "signup"   ? "Gratuit pendant toute la bêta. Sans carte bancaire."
                : mode === "forgot"   ? "Entrez votre email, on vous envoie un lien pour réinitialiser."
                : /* reset */           "Choisissez un nouveau mot de passe sécurisé.";
  const submitLabel = mode === "login"   ? "Se connecter"
                   : mode === "signup"   ? "Créer mon compte"
                   : mode === "forgot"   ? "Envoyer le lien"
                   : /* reset */           "Enregistrer";

  // ===== Avatar live + progress + encouragement (signup uniquement) =====
  const initials = (form.ownerName || "").trim()
    .split(/\s+/).map(s => s[0]).slice(0, 2).join("").toUpperCase();
  const avatarHue = (() => {
    let h = 0;
    for (const c of (form.ownerName || "")) h = (h * 31 + c.charCodeAt(0)) >>> 0;
    return h % 360;
  })();

  const isEmailValid = cbAuth.isValidEmail(form.email);
  const isPwdValid = !cbAuth.validatePassword(form.password);
  const isPhoneValid = form.phone.replace(/\D/g, "").length >= 9;
  const TOTAL_FIELDS = 6;
  const filledCount = (
    (form.ownerName.trim() ? 1 : 0) +
    (form.businessName.trim() ? 1 : 0) +
    (isPhoneValid ? 1 : 0) +
    (isEmailValid ? 1 : 0) +
    (isPwdValid ? 1 : 0) +
    (form.rgpd ? 1 : 0)
  );
  const progressPct = (filledCount / TOTAL_FIELDS) * 100;
  const encouragement =
    filledCount === 0 ? "Allez, c'est parti, ça prend 30 secondes."
    : filledCount === TOTAL_FIELDS ? "Tout est prêt 🎉 Cliquez pour finaliser."
    : filledCount >= 4 ? `Plus que ${TOTAL_FIELDS - filledCount} champ${TOTAL_FIELDS - filledCount > 1 ? "s" : ""} !`
    : "On continue…";

  // Écran "Vérifiez votre boîte mail", affiché après un signup réussi
  if (emailSentTo) {
    return (
      <AuthEmailSent
        email={emailSentTo}
        role="pro"
        onEdit={() => { setEmailSentTo(null); setMode("signup"); }}
        onResend={async () => {
          try { await cbAuth.signup(form); } catch {}
        }}
      />
    );
  }

  // Badge identifie le rôle (Pro), pas un message marketing. Cohérent
  // avec le badge "Compte client" côté EspaceLogin (même structure, juste
  // l'icône et le label changent).
  const eyebrow = mode === "forgot" || mode === "reset"
    ? "Récupération de compte"
    : "Votre compte pro";

  const switchLink = mode === "login"  ? { text: "Pas encore de compte ?", label: "Créer un compte", action: () => go("signup") }
                  : mode === "signup" ? { text: "Déjà inscrit·e ?",       label: "Se connecter",   action: () => go("login") }
                  : mode === "forgot" ? { text: "Retour à la",              label: "connexion",       action: () => { go("login"); switchMode("login"); } }
                  : { text: "Retour à la", label: "connexion", action: () => go("login") };

  const topSlot = mode === "signup" ? (
    <div style={{
      marginTop: 22, padding: "16px 18px",
      background: "var(--surface)", border: "1px solid var(--line)",
      borderRadius: 14, display: "flex", alignItems: "center", gap: 14,
      animation: "cbAuthFadeUp .5s cubic-bezier(.22,1,.36,1) both",
    }}>
      <div style={{
        width: 52, height: 52, borderRadius: 50, flexShrink: 0,
        background: initials
          ? `linear-gradient(135deg, oklch(78% 0.14 ${avatarHue}), oklch(65% 0.18 ${(avatarHue + 40) % 360}))`
          : "var(--bg-alt)",
        color: initials ? "white" : "var(--ink-4)",
        display: "flex", alignItems: "center", justifyContent: "center",
        fontFamily: "var(--ff-display)", fontWeight: 600, fontSize: 20,
        boxShadow: initials ? "0 6px 16px -6px var(--accent)" : "none",
        transition: "background .35s ease, box-shadow .35s ease",
      }}>
        {initials || "?"}
      </div>
      <div style={{ flex: 1, minWidth: 0 }}>
        <div style={{ fontSize: 13, color: "var(--ink-3)", fontWeight: 500, marginBottom: 6 }}>
          {encouragement}
        </div>
        <div style={{
          height: 5, background: "var(--bg-alt)",
          borderRadius: 999, overflow: "hidden",
        }}>
          <div style={{
            width: `${progressPct}%`, height: "100%",
            background: "linear-gradient(90deg, var(--accent), oklch(60% 0.22 300))",
            borderRadius: 999,
            transition: "width .35s cubic-bezier(.22,1,.36,1)",
          }}/>
        </div>
        {/* Chips de champs : les remplis montrent un ✓ sage, les manquants
            pulsent doucement (cbAuthFieldPulse) pour guider l'œil sans
            jamais crier. Signpost UX qui remplace la simple ligne
            « X/5 informations remplies ». */}
        <div style={{
          marginTop: 6,
          display: "flex", flexWrap: "wrap", gap: 5,
        }}>
          {[
            { ok: !!form.ownerName.trim(),     label: "Nom" },
            { ok: !!form.businessName.trim(),  label: "Activité" },
            { ok: isPhoneValid,                label: "Téléphone" },
            { ok: isEmailValid,                label: "Email" },
            { ok: isPwdValid,                  label: "Mot de passe" },
            { ok: !!form.rgpd,                 label: "CGU" },
          ].map((f, i) => (
            <span key={f.label} style={{
              display: "inline-flex", alignItems: "center", gap: 4,
              padding: "2px 7px 2px 5px",
              background: f.ok ? "var(--sage-soft)" : "var(--bg-alt)",
              border: `1px solid ${f.ok ? "color-mix(in oklab, var(--sage) 30%, transparent)" : "var(--line)"}`,
              borderRadius: 999,
              fontSize: 10.5, fontWeight: 540,
              color: f.ok ? "var(--sage-ink, oklch(38% 0.10 160))" : "var(--ink-4)",
              animation: f.ok
                ? "none"
                : `cbAuthFieldPulse 2s ease-in-out ${i * 0.18}s infinite`,
              transition: "background .25s ease, color .25s ease, border-color .25s ease",
            }}>
              <span aria-hidden style={{
                width: 11, height: 11, borderRadius: "50%", flexShrink: 0,
                background: f.ok ? "var(--sage)" : "transparent",
                border: f.ok ? "none" : "1.4px solid var(--line-strong)",
                color: "#fff",
                display: "inline-flex", alignItems: "center", justifyContent: "center",
              }}>
                {f.ok && (
                  <svg width="7" height="7" viewBox="0 0 24 24" fill="none" stroke="currentColor"
                    strokeWidth="4" strokeLinecap="round" strokeLinejoin="round">
                    <path d="M5 12l4 4 10-10"/>
                  </svg>
                )}
              </span>
              {f.label}
            </span>
          ))}
        </div>
      </div>
    </div>
  ) : null;

  // Bottom slot harmonisé pro/client : bouton « Voir le compte démo »
  // full-width avec point pulsant + 3 promises ✓ centrées. Pour pro on
  // câble window.cbStartDemo qui sign-out Supabase + reload vers /v2/app
  // en mode local (SEED_DATA s'affiche). Côté client c'est un lien
  // direct vers /v2/?espace=demo.
  const SharedBottomSlot = window.CbSignupBottomSlot || null;
  const bottomSlot = SharedBottomSlot
    ? <SharedBottomSlot
        tone="accent"
        demoLabel="Voir le compte démo"
        demoOnClick={() => { try { window.cbStartDemo && window.cbStartDemo("accueil"); } catch {} }}
      />
    : null;

  return (
    <AuthShell
      role="pro"
      eyebrow={eyebrow}
      title={title}
      subtitle={subtitle}
      error={error}
      info={info}
      topSlot={topSlot}
      bottomSlot={bottomSlot}
      onSubmit={onSubmit}
      submitting={busy}
      submitLabel={submitLabel}
      switchLink={switchLink}
    >
      {/* ───────── Connexions rapides : Google / Apple / Passkey ───────── */}
      {(mode === "login" || mode === "signup") && (
        <div>
          <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 8 }}>
            <button type="button" disabled={busy}
              onClick={async () => {
                setError(null);
                const r = await cbAuth.loginWithGoogle();
                if (r && r.error) setError(r.error);
              }}
              style={{
                display: "inline-flex", alignItems: "center", justifyContent: "center", gap: 9,
                padding: "11px", background: "#fff", color: "#111",
                border: "1px solid var(--line-strong)", borderRadius: 10,
                fontSize: 13.5, fontWeight: 560, cursor: "pointer", fontFamily: "inherit",
              }}>
              <svg width="17" height="17" viewBox="0 0 48 48" aria-hidden>
                <path fill="#FFC107" d="M43.6 20.5H42V20H24v8h11.3c-1.6 4.7-6 8-11.3 8a12 12 0 1 1 0-24c3 0 5.7 1.1 7.8 3l5.7-5.7A20 20 0 1 0 24 44a20 20 0 0 0 19.6-23.5z"/>
                <path fill="#FF3D00" d="M6.3 14.7l6.6 4.8C14.7 16 19 13 24 13c3 0 5.7 1.1 7.8 3l5.7-5.7A20 20 0 0 0 6.3 14.7z"/>
                <path fill="#4CAF50" d="M24 44a20 20 0 0 0 13.4-5.2l-6.2-5.2A12 12 0 0 1 12.7 28.5l-6.5 5A20 20 0 0 0 24 44z"/>
                <path fill="#1976D2" d="M43.6 20.5H42V20H24v8h11.3a12 12 0 0 1-4.1 5.6l6.2 5.2C39.5 35.6 44 30.3 44 24c0-1.2-.1-2.4-.4-3.5z"/>
              </svg>
              Google
            </button>
            <button type="button" disabled={busy}
              onClick={async () => {
                setError(null);
                const r = await cbAuth.loginWithApple();
                if (r && r.error) setError(r.error);
              }}
              style={{
                display: "inline-flex", alignItems: "center", justifyContent: "center", gap: 9,
                padding: "11px", background: "#000", color: "#fff",
                border: "1px solid #000", borderRadius: 10,
                fontSize: 13.5, fontWeight: 560, cursor: "pointer", fontFamily: "inherit",
              }}>
              <svg width="15" height="17" viewBox="0 0 384 512" fill="#fff" aria-hidden>
                <path d="M318.7 268.7c-.2-36.7 16.4-64.4 50-84.8-18.8-26.9-47.2-41.7-84.7-44.6-35.5-2.8-74.3 20.7-88.5 20.7-15 0-49.4-19.7-76.4-19.7C63.3 141.2 4 184.8 4 273.5q0 39.3 14.4 81.2c12.8 36.7 59 126.7 107.2 125.2 25.2-.6 43-17.9 75.8-17.9 31.8 0 48.3 17.9 76.4 17.9 48.6-.7 90.4-82.5 102.6-119.3-65.2-30.7-61.7-90-61.7-91.9zm-56.6-164.2c27.3-32.4 24.8-61.9 24-72.5-24.1 1.4-52 16.4-67.9 34.9-17.5 19.8-27.8 44.3-25.6 71.9 26.1 2 49.9-11.4 69.5-34.3z"/>
              </svg>
              Apple
            </button>
          </div>
          <button type="button" disabled={busy}
            onClick={() => window.cbComingSoon && window.cbComingSoon({
              title: "Touch ID / Face ID (Passkeys)",
              message: "La connexion par empreinte / visage arrive avec l'infra de juillet (besoin d'un serveur dédié pour générer les challenges WebAuthn). Vous pourrez alors vous reconnecter sans mot de passe d'un seul geste.",
              eta: "été 2026",
            })}
            style={{
              width: "100%", marginTop: 8, padding: "10px",
              background: "var(--bg-alt)", color: "var(--ink-2)",
              border: "1px dashed var(--line-strong)", borderRadius: 10,
              fontSize: 12.5, fontWeight: 540, cursor: "pointer", fontFamily: "inherit",
              display: "inline-flex", alignItems: "center", justifyContent: "center", gap: 7,
            }}>
            🔐 Touch ID / Face ID (bientôt)
          </button>
          <div style={{
            display: "flex", alignItems: "center", gap: 10,
            margin: "16px 0 6px", fontSize: 11.5, color: "var(--ink-4)",
            textTransform: "uppercase", letterSpacing: "0.08em", fontWeight: 600,
          }}>
            <span style={{ flex: 1, height: 1, background: "var(--line)" }}/>
            ou par email
            <span style={{ flex: 1, height: 1, background: "var(--line)" }}/>
          </div>
        </div>
      )}
      {mode === "signup" && (
        <>
          {/* Petites sous-lignes explicatives sous chaque label : on dit à
              l'utilisateur OÙ et POURQUOI l'info sera utilisée. Réduit le
              friction « pourquoi vous me demandez ça ». */}
          <div className="cb-auth-field">
            <label style={labelStyle}>Votre nom</label>
            <div style={fieldHintStyle}>Le nom qui apparaîtra sur vos factures et signera vos messages.</div>
            <input type="text" value={form.ownerName}
              onChange={e => setForm({ ...form, ownerName: e.target.value })}
              placeholder="Léa Bernard"
              style={inputStyle}/>
          </div>
          <div className="cb-auth-field">
            <label style={labelStyle}>Nom de votre activité</label>
            <div style={fieldHintStyle}>Le nom que vos clients verront sur votre page de RDV publique.</div>
            <input type="text" value={form.businessName}
              onChange={e => setForm({ ...form, businessName: e.target.value })}
              placeholder="Ongles by Léa"
              style={inputStyle}/>
          </div>
          <div className="cb-auth-field">
            <label style={labelStyle}>Téléphone</label>
            <div style={fieldHintStyle}>Visible sur votre page de RDV publique et vos factures.</div>
            <input type="tel" value={form.phone}
              onChange={e => setForm({ ...form, phone: e.target.value })}
              placeholder="06 12 34 56 78"
              autoComplete="tel"
              style={inputStyle}/>
          </div>
        </>
      )}
      {mode !== "reset" && (
        <div className="cb-auth-field" style={{ position: "relative" }}>
          <label style={labelStyle}>Email</label>
          <input
            type="email"
            value={form.email}
            onChange={e => setForm({ ...form, email: e.target.value })}
            onKeyDown={e => {
              // Tab accepte la suggestion d'auto-complétion email si présente
              // (ex « marie@gmai » → Tab → « marie@gmail.com »).
              if (e.key === "Tab" && !e.shiftKey) {
                const s = cbSuggestEmail(form.email);
                if (s && s !== form.email) {
                  e.preventDefault();
                  setForm({ ...form, email: s });
                }
              }
            }}
            placeholder="vous@exemple.fr"
            style={inputStyle}
            autoComplete="email"
          />
          {form.email.length > 3 && (
            <span style={{
              position: "absolute", right: 14, top: 36,
              fontSize: 14,
              color: isEmailValid ? "var(--sage)" : "var(--ink-4)",
              transition: "color .2s ease",
            }}>
              {isEmailValid ? "✓" : "…"}
            </span>
          )}
          <EmailSuggestPill
            value={form.email}
            onAccept={s => setForm({ ...form, email: s })}
            tone="var(--accent)"
          />
        </div>
      )}
      {(mode === "login" || mode === "signup" || mode === "reset") && (
        <div className="cb-auth-field">
          <div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline" }}>
            <label style={labelStyle}>
              {mode === "reset" ? "Nouveau mot de passe" : "Mot de passe"}
            </label>
            {(mode === "signup" || mode === "reset") && (
              <span style={{ fontSize: 12, color: "var(--ink-4)" }}>8 car., 1 lettre, 1 chiffre</span>
            )}
          </div>
          <PasswordField
            value={form.password}
            onChange={v => setForm({ ...form, password: v })}
            autoComplete={mode === "login" ? "current-password" : "new-password"}
            showMeter={mode === "signup" || mode === "reset"}
          />
          {/* « Mot de passe oublié ? » sous l'input (au lieu d'au-dessus). */}
          {mode === "login" && (
            <div style={{ marginTop: 6, textAlign: "right" }}>
              <a href="#" onClick={(e) => { e.preventDefault(); switchMode("forgot"); }}
                style={{ fontSize: 12.5, color: "var(--accent-ink)", fontWeight: 520 }}>
                Mot de passe oublié ?
              </a>
            </div>
          )}
        </div>
      )}
      {/* Lien magique — zéro mot de passe, parfait sur mobile.
          Envoie un email avec un lien à 1 clic qui connecte directement. */}
      {mode === "login" && (
        <div style={{ marginTop: 8, paddingTop: 12, borderTop: "1px solid var(--line)" }}>
          <button type="button"
            onClick={async () => {
              setError(null); setInfo(null);
              if (!cbAuth.isValidEmail(form.email)) { setError("Entrez votre email pour recevoir le lien."); return; }
              setBusy(true);
              const r = await cbAuth.requestMagicLink(form.email);
              setBusy(false);
              if (r.error) setError(r.error);
              else setInfo("✉️ Lien magique envoyé ! Ouvrez votre boîte mail et cliquez sur le lien pour vous connecter.");
            }}
            disabled={busy}
            style={{
              width: "100%", padding: "11px",
              background: "var(--bg-alt)", color: "var(--ink)",
              border: "1px solid var(--line)", borderRadius: 10,
              fontSize: 13.5, fontWeight: 560, cursor: "pointer", fontFamily: "inherit",
              display: "inline-flex", alignItems: "center", justifyContent: "center", gap: 8,
            }}>
            ✨ Recevoir un lien magique par email
          </button>
          <div style={{ fontSize: 11.5, color: "var(--ink-4)", textAlign: "center", marginTop: 6 }}>
            Pas de mot de passe à retenir — idéal sur mobile.
          </div>
        </div>
      )}
      {mode === "reset" && (
        <div>
          <label style={labelStyle}>Confirmer le mot de passe</label>
          <PasswordField
            value={form.passwordConfirm}
            onChange={v => setForm({ ...form, passwordConfirm: v })}
            autoComplete="new-password"
          />
        </div>
      )}
      {mode === "signup" && (
        <label className="cb-auth-field" style={{ display: "flex", gap: 10, alignItems: "flex-start", fontSize: 12.5, color: "var(--ink-3)", lineHeight: 1.5, cursor: "pointer" }}>
          <input type="checkbox" checked={form.rgpd} onChange={e => setForm({ ...form, rgpd: e.target.checked })} style={{ accentColor: "var(--accent)", width: 16, height: 16, flexShrink: 0, marginTop: 2 }}/>
          <span>
            J'accepte la <a onClick={(e) => { e.preventDefault(); go("legal"); }} href="#" style={{ color: "var(--accent-ink)", fontWeight: 520 }}>politique de confidentialité</a> et les <a onClick={(e) => { e.preventDefault(); go("legal"); }} href="#" style={{ color: "var(--accent-ink)", fontWeight: 520 }}>conditions d'utilisation</a>.
          </span>
        </label>
      )}
    </AuthShell>
  );
};

/* Page d'atterrissage après clic sur le lien de confirmation email.
   Le client Supabase a déjà avalé le token dans l'URL et créé une session
   automatiquement, on attend juste qu'il signale SIGNED_IN puis on
   propose de continuer vers l'espace pro. */
const EmailConfirmedPage = ({ go }) => {
  const user = cbAuth.getCurrentUser();
  const [loading, setLoading] = React.useState(!user);

  React.useEffect(() => {
    if (user) { setLoading(false); return; }
    // Petite attente : Supabase finit de valider le token et fire SIGNED_IN
    const t = setInterval(() => {
      const u = cbAuth.getCurrentUser();
      if (u) { setLoading(false); clearInterval(t); }
    }, 200);
    // Si rien après 5s, on arrête le spinner et on propose la connexion manuelle
    const timeout = setTimeout(() => { setLoading(false); clearInterval(t); }, 5000);
    return () => { clearInterval(t); clearTimeout(timeout); };
  }, [user]);

  // Nettoie l'URL (vire #access_token=… ou ?type=signup) une fois chargé
  React.useEffect(() => {
    try { window.history.replaceState({}, "", window.location.pathname); } catch {}
  }, []);

  return (
    <section style={{ padding: "80px 20px", minHeight: "60vh", display: "flex", alignItems: "center", justifyContent: "center" }}>
      <div className="container" style={{ maxWidth: 520 }}>
        <div style={{
          background: "var(--surface)", border: "1px solid var(--line)",
          borderRadius: 20, padding: "48px 32px", textAlign: "center",
          boxShadow: "var(--sh-2)",
        }}>
          {loading ? (
            <>
              <div style={{
                width: 64, height: 64, borderRadius: 50, margin: "0 auto 18px",
                background: "var(--accent-soft)", color: "var(--accent-ink)",
                display: "flex", alignItems: "center", justifyContent: "center",
                fontSize: 32,
              }}>⏳</div>
              <h1 style={{ fontSize: "clamp(24px, 3vw, 32px)", letterSpacing: "-0.025em", marginBottom: 10 }}>
                Vérification en cours…
              </h1>
              <p style={{ fontSize: 14.5, color: "var(--ink-3)", lineHeight: 1.55 }}>
                On termine de confirmer votre adresse, ce ne sera qu'une seconde.
              </p>
            </>
          ) : (
            <>
              <div style={{
                width: 72, height: 72, borderRadius: 50, margin: "0 auto 20px",
                background: "var(--sage-soft)", color: "var(--sage)",
                display: "flex", alignItems: "center", justifyContent: "center",
                fontSize: 38, fontWeight: 700,
                boxShadow: "0 0 0 8px color-mix(in oklab, var(--sage-soft) 60%, transparent)",
              }}>✓</div>
              <h1 style={{ fontSize: "clamp(26px, 3.4vw, 36px)", letterSpacing: "-0.025em", marginBottom: 12 }}>
                Compte confirmé !
              </h1>
              <p style={{ fontSize: 15, color: "var(--ink-2)", lineHeight: 1.55, marginBottom: 8 }}>
                {user
                  ? <>Bienvenue <strong>{user.ownerName || user.email}</strong>. Votre adresse <strong>{user.email}</strong> est désormais vérifiée.</>
                  : <>Votre adresse email a été confirmée. Vous pouvez maintenant vous connecter.</>
                }
              </p>
              <p style={{ fontSize: 13, color: "var(--ink-4)", lineHeight: 1.5, marginBottom: 28 }}>
                Le badge <strong style={{ color: "var(--accent-ink)" }}>✓ Vérifié</strong> apparaît maintenant
                sur votre page de réservation publique, un signal de confiance pour vos clients.
              </p>
              <button onClick={() => go(user ? "app" : "login")} className="btn btn-accent btn-lg">
                {user ? "Aller à mon espace pro" : "Me connecter"} →
              </button>
            </>
          )}
        </div>
      </div>
    </section>
  );
};

/* ============ AUTH CHOICE, sélecteur Pro / Client ============
   Cliquer sur "Connexion" ou "Créer un compte" depuis la home ouvre cette
   page intermédiaire pour choisir le type de compte. Le choix dirige vers :
   - Pro    → LoginPage (page "login" ou "signup"), flow Supabase existant
   - Client → EspaceLogin (?espace=login), flow client centralisé existant
   `intent` = "login" | "signup", préserve l'intention de l'utilisateur. */
const AuthChoicePage = ({ go, intent = "signup" }) => {
  // Intent en state local : permet de switcher signup ↔ login sans re-naviguer
  // (sinon setPage("authChoice") avec la même valeur ne re-render pas et le
  // composant garde l'intent initial).
  const [localIntent, setLocalIntent] = React.useState(intent);
  const isSignup = localIntent === "signup";
  const title = isSignup ? "Créer un compte" : "Se connecter";
  const sub = isSignup
    ? "Choisissez le type de compte qui vous correspond, gratuit, sans engagement."
    : "Sélectionnez votre type de compte pour vous connecter.";

  // Tous les flows passent par le routeur React (pas de window.location.href)
  // → pas de reload, pas d'écran de chargement, navigation instantanée.
  const goClient = () => go(isSignup ? "clientSignup" : "clientLogin");
  const goPro    = () => go(isSignup ? "signup"       : "login");

  return (
    <section style={{
      minHeight: "calc(100vh - 64px)",
      display: "flex", alignItems: "center", justifyContent: "center",
      padding: "48px 22px 80px",
      position: "relative", overflow: "hidden",
    }}>
      <style>{`
        @keyframes cbChoiceFadeUp {
          from { opacity: 0; transform: translateY(14px); }
          to   { opacity: 1; transform: translateY(0); }
        }
        .cb-auth-choice-card { animation: cbChoiceFadeUp .55s cubic-bezier(.22,1,.36,1) both; }
        .cb-auth-choice-card:nth-of-type(1) { animation-delay: 0.08s; }
        .cb-auth-choice-card:nth-of-type(2) { animation-delay: 0.16s; }
        .cb-auth-choice-card:hover {
          transform: translateY(-3px);
          box-shadow: 0 24px 48px -22px var(--accent), 0 0 0 2px var(--accent) inset !important;
        }
        .cb-auth-choice-card:hover .cb-auth-choice-arrow {
          transform: translateX(4px);
        }
      `}</style>

      {/* Aurora indigo, cohérent avec la home et LoginPage */}
      <div aria-hidden style={{
        position: "absolute", inset: 0, pointerEvents: "none",
        background: "radial-gradient(ellipse 55% 50% at 50% 18%, var(--accent-soft) 0%, transparent 70%)",
        opacity: 0.55,
      }}/>

      {/* Le `key={localIntent}` force le re-mount du contenu quand on switche
          signup ↔ login → l'animation cbChoiceFadeUp se re-déclenche et l'user
          voit clairement que la page a changé d'état. */}
      <div key={localIntent} style={{ width: "100%", maxWidth: 760, position: "relative" }}>
        <div style={{ textAlign: "center", marginBottom: 36 }}>
          <div style={{
            display: "inline-flex", alignItems: "center", gap: 8,
            padding: "5px 14px 5px 6px",
            background: "var(--surface)", border: "1px solid var(--line-strong)",
            borderRadius: 999, fontSize: 12.5, fontWeight: 520,
            color: "var(--ink-2)", marginBottom: 18,
            boxShadow: "var(--sh-1)",
            animation: "cbChoiceFadeUp .4s cubic-bezier(.22,1,.36,1) both",
          }}>
            <span style={{
              width: 18, height: 18, borderRadius: 50,
              background: "var(--accent)", color: "white",
              display: "inline-flex", alignItems: "center", justifyContent: "center",
              fontSize: 10, fontWeight: 700,
            }}>✦</span>
            {isSignup ? "Nouveau compte" : "Bon à vous revoir"}
          </div>
          <h1 style={{
            fontSize: "clamp(28px, 4vw, 38px)",
            letterSpacing: "-0.028em", lineHeight: 1.1, margin: 0,
            fontFamily: "var(--ff-display)", fontWeight: 580,
            animation: "cbChoiceFadeUp .45s cubic-bezier(.22,1,.36,1) both",
            animationDelay: "0.05s",
          }}>{title}</h1>
          <p style={{
            marginTop: 12, fontSize: 15, color: "var(--ink-3)", lineHeight: 1.55,
            animation: "cbChoiceFadeUp .45s cubic-bezier(.22,1,.36,1) both",
            animationDelay: "0.08s",
          }}>{sub}</p>
        </div>

        {/* Layout conditionnel :
            - SIGNUP : cartes riches verticales avec liste de bénéfices (le user
              est en train de décider, on lui vend le produit).
            - LOGIN  : 2 boutons compacts horizontaux, look totalement différent
              (rapide, on sait ce qu'on vient faire). Évite la confusion "tiens,
              j'ai cliqué Connectez-vous mais la page n'a pas changé". */}
        {isSignup ? (
          <div style={{
            display: "grid", gap: 18,
            gridTemplateColumns: "repeat(auto-fit, minmax(280px, 1fr))",
          }}>
            {/* === Compte PRO === */}
            <button
              onClick={goPro}
              className="cb-auth-choice-card cb-press-feedback"
              style={{
                textAlign: "left", cursor: "pointer", fontFamily: "inherit",
                padding: 26, background: "var(--surface)",
                border: "1px solid var(--line)", borderRadius: 18,
                boxShadow: "var(--sh-2)",
                display: "flex", flexDirection: "column", gap: 14,
                transition: "transform .18s ease, box-shadow .18s ease",
              }}>
              <div style={{
                width: 48, height: 48, borderRadius: 12,
                background: "linear-gradient(135deg, var(--accent) 0%, oklch(48% 0.20 300) 100%)",
                color: "#fff",
                display: "inline-flex", alignItems: "center", justifyContent: "center",
                boxShadow: "0 10px 24px -10px var(--accent)",
              }}>
                <Icon name="briefcase" size={24} stroke={1.7}/>
              </div>
              <div>
                <div style={{
                  fontFamily: "var(--ff-display)", fontSize: 19, fontWeight: 600,
                  letterSpacing: "-0.018em", color: "var(--ink)",
                }}>
                  Compte professionnel
                </div>
                <div style={{
                  marginTop: 6, fontSize: 13.5, color: "var(--ink-3)", lineHeight: 1.55,
                }}>
                  Pour gérer votre activité, agenda, clients, RDV en ligne, factures, fidélité.
                </div>
              </div>
              <ul style={{
                listStyle: "none", padding: 0, margin: 0,
                display: "flex", flexDirection: "column", gap: 6,
                fontSize: 12.5, color: "var(--ink-2)",
              }}>
                {[
                  "Agenda + prise de RDV en ligne",
                  "Fiches clientes & historique",
                  "Factures conformes 2026",
                  "Programme de fidélité",
                ].map(t => (
                  <li key={t} style={{ display: "flex", gap: 8, alignItems: "center" }}>
                    <span style={{
                      width: 16, height: 16, borderRadius: 50,
                      background: "var(--sage-soft)", color: "var(--sage)",
                      display: "inline-flex", alignItems: "center", justifyContent: "center",
                      flexShrink: 0,
                    }}>
                      <Icon name="check" size={10} stroke={2.6}/>
                    </span>
                    {t}
                  </li>
                ))}
              </ul>
              <div style={{
                marginTop: 6, paddingTop: 14,
                borderTop: "1px dashed var(--line)",
                display: "flex", alignItems: "center", justifyContent: "space-between",
              }}>
                <span style={{
                  fontSize: 13, fontWeight: 580, color: "var(--accent-ink)",
                }}>
                  Créer mon compte pro
                </span>
                <span className="cb-auth-choice-arrow" style={{
                  transition: "transform .18s ease", color: "var(--accent-ink)",
                }}>
                  <Icon name="arrow" size={16} stroke={2}/>
                </span>
              </div>
            </button>

            {/* === Compte CLIENT === */}
            <button
              onClick={goClient}
              className="cb-auth-choice-card cb-press-feedback"
              style={{
                textAlign: "left", cursor: "pointer", fontFamily: "inherit",
                padding: 26, background: "var(--surface)",
                border: "1px solid var(--line)", borderRadius: 18,
                boxShadow: "var(--sh-2)",
                display: "flex", flexDirection: "column", gap: 14,
                transition: "transform .18s ease, box-shadow .18s ease",
              }}>
              <div style={{
                width: 48, height: 48, borderRadius: 12,
                background: "linear-gradient(135deg, oklch(70% 0.16 25) 0%, oklch(60% 0.20 350) 100%)",
                color: "#fff",
                display: "inline-flex", alignItems: "center", justifyContent: "center",
                boxShadow: "0 10px 24px -10px oklch(60% 0.20 350)",
              }}>
                <Icon name="user" size={24} stroke={1.7}/>
              </div>
              <div>
                <div style={{
                  fontFamily: "var(--ff-display)", fontSize: 19, fontWeight: 600,
                  letterSpacing: "-0.018em", color: "var(--ink)",
                }}>
                  Compte client
                </div>
                <div style={{
                  marginTop: 6, fontSize: 13.5, color: "var(--ink-3)", lineHeight: 1.55,
                }}>
                  Un seul compte pour tous vos pros ClientBase, un espace pour gérer vos rendez-vous.
                </div>
              </div>
              <ul style={{
                listStyle: "none", padding: 0, margin: 0,
                display: "flex", flexDirection: "column", gap: 6,
                fontSize: 12.5, color: "var(--ink-2)",
              }}>
                {[
                  "Vos rendez-vous à venir et passés",
                  "Annulation & report en un clic",
                  "Cartes de fidélité chez vos pros",
                  "Préférences de rappel (SMS, email)",
                ].map(t => (
                  <li key={t} style={{ display: "flex", gap: 8, alignItems: "center" }}>
                    <span style={{
                      width: 16, height: 16, borderRadius: 50,
                      background: "var(--sage-soft)", color: "var(--sage)",
                      display: "inline-flex", alignItems: "center", justifyContent: "center",
                      flexShrink: 0,
                    }}>
                      <Icon name="check" size={10} stroke={2.6}/>
                    </span>
                    {t}
                  </li>
                ))}
              </ul>
              <div style={{
                marginTop: 6, paddingTop: 14,
                borderTop: "1px dashed var(--line)",
                display: "flex", alignItems: "center", justifyContent: "space-between",
              }}>
                <span style={{
                  fontSize: 13, fontWeight: 580, color: "var(--accent-ink)",
                }}>
                  Créer mon compte client
                </span>
                <span className="cb-auth-choice-arrow" style={{
                  transition: "transform .18s ease", color: "var(--accent-ink)",
                }}>
                  <Icon name="arrow" size={16} stroke={2}/>
                </span>
              </div>
            </button>
          </div>
        ) : (
          /* ============ Mode LOGIN, layout compact, 2 lignes ============
             Look totalement différent du signup pour qu'il n'y ait aucun doute
             sur le fait qu'on a bien switché. Plus de listes de features, juste
             une icône + un titre + un sous-titre court. */
          <div style={{
            display: "flex", flexDirection: "column", gap: 12,
            maxWidth: 480, margin: "0 auto",
          }}>
            {/* === Bouton login PRO === */}
            <button
              onClick={goPro}
              className="cb-auth-choice-card cb-press-feedback"
              style={{
                textAlign: "left", cursor: "pointer", fontFamily: "inherit",
                padding: "18px 22px", background: "var(--surface)",
                border: "1px solid var(--line)", borderRadius: 14,
                boxShadow: "var(--sh-1)",
                display: "flex", alignItems: "center", gap: 16,
                transition: "transform .18s ease, box-shadow .18s ease, border-color .18s ease",
              }}>
              <div style={{
                width: 44, height: 44, borderRadius: 11, flexShrink: 0,
                background: "linear-gradient(135deg, var(--accent) 0%, oklch(48% 0.20 300) 100%)",
                color: "#fff",
                display: "inline-flex", alignItems: "center", justifyContent: "center",
                boxShadow: "0 8px 20px -10px var(--accent)",
              }}>
                <Icon name="briefcase" size={22} stroke={1.7}/>
              </div>
              <div style={{ flex: 1, minWidth: 0 }}>
                <div style={{
                  fontFamily: "var(--ff-display)", fontSize: 16.5, fontWeight: 580,
                  letterSpacing: "-0.012em", color: "var(--ink)",
                }}>
                  Se connecter en tant que pro
                </div>
                <div style={{
                  marginTop: 2, fontSize: 12.5, color: "var(--ink-3)",
                }}>
                  Accédez à votre espace de gestion
                </div>
              </div>
              <span className="cb-auth-choice-arrow" style={{
                transition: "transform .18s ease", color: "var(--accent-ink)", flexShrink: 0,
              }}>
                <Icon name="arrow" size={18} stroke={2}/>
              </span>
            </button>

            {/* === Bouton login CLIENT === */}
            <button
              onClick={goClient}
              className="cb-auth-choice-card cb-press-feedback"
              style={{
                textAlign: "left", cursor: "pointer", fontFamily: "inherit",
                padding: "18px 22px", background: "var(--surface)",
                border: "1px solid var(--line)", borderRadius: 14,
                boxShadow: "var(--sh-1)",
                display: "flex", alignItems: "center", gap: 16,
                transition: "transform .18s ease, box-shadow .18s ease, border-color .18s ease",
              }}>
              <div style={{
                width: 44, height: 44, borderRadius: 11, flexShrink: 0,
                background: "linear-gradient(135deg, oklch(70% 0.16 25) 0%, oklch(60% 0.20 350) 100%)",
                color: "#fff",
                display: "inline-flex", alignItems: "center", justifyContent: "center",
                boxShadow: "0 8px 20px -10px oklch(60% 0.20 350)",
              }}>
                <Icon name="user" size={22} stroke={1.7}/>
              </div>
              <div style={{ flex: 1, minWidth: 0 }}>
                <div style={{
                  fontFamily: "var(--ff-display)", fontSize: 16.5, fontWeight: 580,
                  letterSpacing: "-0.012em", color: "var(--ink)",
                }}>
                  Se connecter en tant que client
                </div>
                <div style={{
                  marginTop: 2, fontSize: 12.5, color: "var(--ink-3)",
                }}>
                  Retrouvez vos RDV et votre fidélité
                </div>
              </div>
              <span className="cb-auth-choice-arrow" style={{
                transition: "transform .18s ease", color: "var(--accent-ink)", flexShrink: 0,
              }}>
                <Icon name="arrow" size={18} stroke={2}/>
              </span>
            </button>
          </div>
        )}

        {/* Lien pour switcher l'intention sans repasser par la home.
            Utilise <button> plutôt que <a href="#"> pour un click handling
            plus fiable (pas de scroll-to-top parasite, focus management OK). */}
        <div style={{
          marginTop: 30, textAlign: "center",
          fontSize: 13.5, color: "var(--ink-3)",
        }}>
          {isSignup ? (
            <>Vous avez déjà un compte ?{" "}
              <button type="button"
                onClick={() => setLocalIntent("login")}
                style={{
                  background: "transparent", border: "none", padding: 0,
                  color: "var(--accent-ink)", fontWeight: 580,
                  fontFamily: "inherit", fontSize: "inherit",
                  cursor: "pointer", textDecoration: "underline",
                  textUnderlineOffset: 3,
                }}>
                Connectez-vous
              </button>
            </>
          ) : (
            <>Pas encore inscrit·e ?{" "}
              <button type="button"
                onClick={() => setLocalIntent("signup")}
                style={{
                  background: "transparent", border: "none", padding: 0,
                  color: "var(--accent-ink)", fontWeight: 580,
                  fontFamily: "inherit", fontSize: "inherit",
                  cursor: "pointer", textDecoration: "underline",
                  textUnderlineOffset: 3,
                }}>
                Créer un compte
              </button>
            </>
          )}
        </div>
      </div>
    </section>
  );
};

Object.assign(window, {
  AboutPage, ContactPage, LoginPage, AuthChoicePage, EmailConfirmedPage,
  AuthShell, AuthEmailSent,
  CB_CONTACT_EMAIL, sendContactMail,
});
