const { useState: useStateP } = React;

/* helpers (core.js) */
const PR = window;

/* Sens symbolique du nombre réduit (1-9) — sobre, jamais prédictif. */
const NOMBRE_SENS = {
  1: "l'initiative, l'unité, ce qui ose commencer",
  2: "la relation, l'écho, le lien à l'autre",
  3: "l'expression, l'élan qui crée et se montre",
  4: "l'assise, le cadre, ce qui se bâtit pour durer",
  5: "le mouvement, la liberté, le goût du changement",
  6: "le soin, l'harmonie, la responsabilité envers les siens",
  7: "l'intériorité, la quête, le retrait qui cherche du sens",
  8: "la puissance d'agir, la matière, l'ambition concrète",
  9: "l'ouverture, le don, ce qui s'achève pour transmettre" };

/* Développement TRADITIONNEL — corps de phrase (le label gras est ajouté dans le
   rendu). Sobre, jamais prédictif. Sert la lecture alchimique. */
const ELEM_TRADITION = {
  Feu: "l'ardeur et l'élan. Chaud et sec dans la tradition des humeurs, c'est une nature qui s'allume vite, qui éclaire et entraîne — le goût d'oser, d'agir, parfois de brûler les étapes.",
  Air: "l'esprit et le lien. Chaud et humide, c'est une nature qui pense, parle et relie : curieuse, mobile, sociable — faite pour échanger et mettre les idées en mouvement, au risque de se disperser.",
  Eau: "la sensibilité et la profondeur. Froide et humide, c'est une nature qui ressent, écoute et reflète : intuitive, patiente, accordée aux émotions — elle épouse le courant plutôt que de le forcer.",
  Terre: "l'ancrage et la durée. Froide et sèche, c'est une nature concrète, patiente et fiable : on construit, on garde, on fait tenir — une solidité qui rassure, parfois lente à changer." };
const NOMBRE_TRADITION = {
  1: "celui du commencement et de l'individualité : l'initiative, l'autonomie, la volonté qui ouvre la voie. Il aime être à la source, décider, avancer le premier.",
  2: "celui de la relation et de l'accord : l'écoute, la diplomatie, le lien à l'autre. Il se réalise dans le duo, la coopération, la juste mesure entre soi et autrui.",
  3: "celui de l'expression et de la création : la parole, le geste qui montre, la joie de relier. Il cherche à dire, à créer, à faire passer ce qu'il porte — et s'épanouit dès qu'il a un canal pour s'exprimer.",
  4: "celui de l'assise et de la construction : le cadre, la méthode, la fidélité. Il bâtit pour durer, aime ce qui est solide et sur quoi l'on peut compter.",
  5: "celui du mouvement et de la liberté : le voyage, le changement, la curiosité. Il a besoin d'air et d'expériences, supporte mal l'enfermement, apprend en bougeant.",
  6: "celui du soin et de l'harmonie : la famille, la beauté, la responsabilité envers les siens. Il relie, protège et cherche l'équilibre — quitte à beaucoup porter.",
  7: "celui de l'intériorité et de la quête : la réflexion, le retrait, le besoin de sens. Il cherche à comprendre en profondeur, aime le silence et la vie intérieure.",
  8: "celui de la puissance d'agir et de la matière : l'ambition, l'organisation, la maîtrise du concret. Il vise grand, gère, transforme l'effort en résultat.",
  9: "celui de l'ouverture et du don : l'altruisme, l'achèvement, la transmission. Il embrasse large, donne, et clôt un cycle pour passer le relais." };
const MATIERE_TRADITION = {
  Feu: "sous Mars : ce qui se forge à chaud, l'outil et l'arme — une matière de volonté, d'action et de tranchant.",
  Air: "sous Jupiter : ce qui s'allège et s'étend — une matière d'expansion, de largeur de vue et d'optimisme.",
  Eau: "sous la Lune : ce qui reflète et suit la marée — une matière de réceptivité, de rêve et de cycles.",
  Terre: "sous Saturne : ce qui pèse, garde et dure — une matière de patience, de structure et de temps long." };
const TEMPER_TRADITION = {
  Feu: "Le tempérament ardent (bilieux/colérique dans la médecine des humeurs) est celui de l'élan : une énergie qui s'allume vite, décide et entraîne. On agit d'instinct, on mène, on n'aime guère attendre. Sa force est l'initiative et le courage ; son revers, l'impatience — apprendre à laisser le feu chauffer sans tout consumer.",
  Air: "Le tempérament vif (sanguin) est celui du mouvement et de l'échange : l'esprit circule, relie, met les idées en l'air. On est sociable, curieux, prompt à saisir et à transmettre. Sa force est l'aisance et l'adaptabilité ; son revers, la dispersion — apprendre à poser ce qui vole pour qu'il prenne corps.",
  Eau: "Le tempérament sensible (flegmatique) est celui de la profondeur et de la patience : on ressent avant de dire, on écoute, on épouse le courant plutôt que de le forcer. Sa force est l'intuition et la constance du cœur ; son revers, la lenteur à trancher — apprendre à nommer ce que l'on perçoit sans se laisser submerger.",
  Terre: "Le tempérament constant (mélancolique au sens ancien : la terre, le solide) est celui de l'ancrage et de la durée : on bâtit, on garde, on fait tenir. Sa force est la fiabilité et le sens du concret ; son revers, la difficulté à changer — apprendre à laisser bouger ce qui s'était fixé." };


/* La lecture alchimique — la couche calculée DÉPLOYÉE (gématrie · nombre · élément ·
   qualités · matière, puis tempérament, les trois principes Soufre·Mercure·Sel, l'œuvre).
   Tout dérive de Onomancie.alchimie() — déterministe, depuis les lettres, jamais un destin.
   Habillage sobre, au goût de l'app (pas le carton dégradé du gabarit SEO). */
const ALC_PRIN_COL = { soufre: "#b8502f", mercure: "#4f7a86", sel: "#7a5a39" };
const ALC_PRIN_ORDER = ["soufre", "mercure", "sel"];

/* ---------- Radar / diagramme en toile (réutilisable) ----------
   axes = [{ label, value (0..1, déjà normalisé), color, sub? }]. Dessine la grille
   concentrique, les rayons, le polygone des données et les étiquettes.
   Exposé sur window pour prenom.jsx ET nommage.jsx. */
function RadarChart({ axes, size, accent, fill }) {
  const N = axes.length;
  if (!N) return null;
  const S = size || 224;
  // marge horizontale plus large pour les étiquettes latérales (Eau / Terre sur 4 axes)
  const padX = S * 0.16;
  const VBW = S + padX * 2;
  const cx = VBW / 2, cy = S / 2;
  const R = S * 0.34;
  const A = accent || "#b15b36";
  const ring = "rgba(122,90,57,.22)";
  const pt = (ang, r) => [cx + r * Math.cos(ang), cy + r * Math.sin(ang)];
  const ang = (i) => -Math.PI / 2 + (i * 2 * Math.PI) / N;
  const grids = [0.34, 0.67, 1];
  const poly = (r, fn) => axes.map((ax, i) => { const a = ang(i); const rr = fn ? fn(ax, i) : r; const [x, y] = pt(a, rr * R); return x.toFixed(1) + "," + y.toFixed(1); }).join(" ");
  const dataPts = axes.map((ax, i) => { const a = ang(i); const [x, y] = pt(a, Math.max(0.04, ax.value) * R); return { x, y, ax, a }; });
  return (
    <svg className="radar" viewBox={"0 0 " + VBW + " " + S} width="100%" style={{ maxWidth: VBW + "px", display: "block", margin: "0 auto" }} role="img" aria-label="diagramme en toile">
      {/* grille concentrique */}
      {grids.map((g, gi) => <polygon key={"g" + gi} points={poly(g)} fill={gi === grids.length - 1 ? "rgba(122,90,57,.03)" : "none"} stroke={ring} strokeWidth="1" />)}
      {/* rayons */}
      {axes.map((ax, i) => { const a = ang(i); const [x, y] = pt(a, R); return <line key={"r" + i} x1={cx} y1={cy} x2={x} y2={y} stroke={ring} strokeWidth="1" />; })}
      {/* polygone des données */}
      <polygon points={dataPts.map((p) => p.x.toFixed(1) + "," + p.y.toFixed(1)).join(" ")} fill={fill || "rgba(177,91,54,.13)"} stroke={A} strokeWidth="2" strokeLinejoin="round" />
      {/* sommets */}
      {dataPts.map((p, i) => <circle key={"d" + i} cx={p.x} cy={p.y} r="3.5" fill={p.ax.color || A} stroke="#fff" strokeWidth="1.5" />)}
      {/* étiquettes */}
      {axes.map((ax, i) => {
        const a = ang(i); const [lx, ly] = pt(a, R + S * 0.085);
        const anchor = Math.abs(Math.cos(a)) < 0.3 ? "middle" : Math.cos(a) > 0 ? "start" : "end";
        return (
          <g key={"l" + i}>
            <text x={lx} y={ly - (ax.sub ? 4 : 0)} textAnchor={anchor} dominantBaseline="middle" className="radar-lbl" fill={ax.color || "#5a4a36"}>{ax.label}</text>
            {ax.sub && <text x={lx} y={ly + 9} textAnchor={anchor} dominantBaseline="middle" className="radar-sub" fill="#9a8a72">{ax.sub}</text>}
          </g>);
      })}
    </svg>);
}
window.RadarChart = RadarChart;

/* Petite croix dépliable ❖ — pour développer une notion sans alourdir la lecture. */
function AlcCross({ label, children }) {
  return (
    <details className="alc-cross">
      <summary><span className="alc-cross-mark">❖</span><span className="alc-cross-lbl">{label}</span></summary>
      <div className="alc-cross-body">{children}</div>
    </details>);

}
function LectureAlchimique({ res }) {
  const O = window.Onomancie;
  const prenom = res && res.prenom;
  if (!O || !O.alchimie || !prenom) return null;
  const base = window.nommageBaseline ? window.nommageBaseline() : null;
  // Lecture TRADITIONNELLE : la signature principale porte sur l'identité complète
  // (« nombre d'expression » = tous les prénoms + le nom). On garde aussi le
  // « nombre actif » (1er prénom seul) et l'« héréditaire » (le nom) pour la croix ❖.
  const full = ((res.prenomsFull || prenom) + (res.nom ? " " + res.nom : "")).trim();
  const a = O.alchimie(full, base);
  if (!a) return null;
  const aActif = O.alchimie(prenom, base);
  const aHered = res.nom ? O.alchimie(res.nom, base) : null;
  const multi = full.replace(/\s+/g, "").length > prenom.replace(/\s+/g, "").length; // y a-t-il + que le 1er prénom ?
  const ELM = window.ELEM_META || {};
  const e0 = ELM[a.element] || {};
  const nb = NOMBRE_SENS[a.nombre] || "";
  const manque = a.principes[a.manque];
  return (
    <div className="block prenom-block prenom-alc">
      <div className="pos-label"><span>La lecture alchimique</span><span className="pos-help">— ce que les lettres calculent</span></div>
      <p className="palc-base">Calculé sur {multi ? "ton nom complet" : "ton prénom"}&nbsp;: <b>{full}</b></p>
      <p className="piste">L'ancienne manière de lire toute matière&nbsp;: la gématrie et le nombre, l'élément et ses qualités, et les trois principes — Soufre, Mercure, Sel. Rien n'est posé à la main&nbsp;: tout se déduit des lettres.</p>
      {multi &&
      <AlcCross label="Pourquoi sur le nom complet&nbsp;? (et non le prénom seul)">
        <p>La tradition onomantique distingue trois nombres, selon les lettres qu'on additionne&nbsp;:</p>
        <p><b>Le nombre d'expression</b> — sur <b>l'identité entière</b> (tous les prénoms + le nom). C'est la lecture la plus complète, celle qu'on retient ici&nbsp;: gématrie <b>{a.gematrie}</b>, nombre <b>{a.nombre}</b>, élément <b>{a.element}</b>.</p>
        <p><b>Le nombre actif</b> — sur ton <b>premier prénom seul</b> ({prenom})&nbsp;: gématrie <b>{aActif.gematrie}</b>, nombre <b>{aActif.nombre}</b>, élément <b>{aActif.element}</b>. C'est le soi du quotidien, ce que tu mets en avant.</p>
        {aHered &&
        <p><b>Le nombre héréditaire</b> — sur ton <b>nom de famille</b> ({res.nom})&nbsp;: gématrie <b>{aHered.gematrie}</b>, nombre <b>{aHered.nombre}</b>, élément <b>{aHered.element}</b>. C'est la part de la lignée.</p>}
        <p>On affiche le nombre d'expression parce qu'il embrasse tout ce que tu portes&nbsp;; les deux autres en sont les composantes.</p>
      </AlcCross>}
      <div className="palc-grid">
        <div className="palc-cell"><div className="palc-k">Gématrie</div><div className="palc-v">{a.gematrie}</div><div className="palc-c">somme des lettres · A=1…Z=26</div></div>
        <div className="palc-cell"><div className="palc-k">Nombre</div><div className="palc-v">{a.nombre}</div><div className="palc-c">{nb}</div></div>
        <div className="palc-cell"><div className="palc-k">Élément</div><div className="palc-v">{a.element}</div><div className="palc-c">{a.qualites}{e0.court ? " · " + e0.court : ""}</div></div>
        <div className="palc-cell"><div className="palc-k">Matière</div><div className="palc-v">{a.metal.metal}</div><div className="palc-c">{a.metal.astre} · {a.metal.note}</div></div>
      </div>
      <p className="palc-sub">Ce que disent l'élément, le nombre et la matière</p>
      <div className="palc-tradi">
        <p className="palc-tradi-p"><b>L'élément {a.element}</b> — c'est {ELEM_TRADITION[a.element]}</p>
        <p className="palc-tradi-p"><b>Le nombre {a.nombre}</b> — {NOMBRE_TRADITION[a.nombre]}</p>
        <p className="palc-tradi-p"><b>La matière, {a.metal.metal}</b> — {MATIERE_TRADITION[a.element]}</p>
      </div>
      <AlcCross label="Comment lire ces quatre mesures">
        <p><b>Gématrie</b> — chaque lettre vaut un nombre (A=1, B=2… Z=26). La gématrie en est la somme : une vieille façon de lire un mot par son poids chiffré, partagée par l'hébreu, le grec et le latin.</p>
        <p><b>Nombre</b> — on réduit cette somme à un seul chiffre (1 à 9). Il donne une tonalité d'ensemble, jamais un destin.</p>
        <p><b>Élément</b> — les lettres se répartissent en quatre familles, Feu · Air · Eau · Terre. Le dominant dit la matière première du prénom, son tempérament de fond.</p>
        <p><b>Matière</b> — à chaque profil l'alchimie associe un métal et un astre (l'or et le Soleil, l'argent et la Lune…) : une image pour nommer la densité et l'éclat.</p>
      </AlcCross>

      <p className="palc-sub">Le tempérament</p>
      <div className="palc-temper">
        <span className="palc-pill">{a.humeur.nom}</span>
        <span className="palc-pill">{a.humeur.humeur}</span>
      </div>
      <p className="palc-trait">{TEMPER_TRADITION[a.element]}</p>

      <p className="palc-sub">Les trois principes</p>
      <p className="palc-intro">L'alchimie lit toute matière selon trois forces&nbsp;: le <b>Soufre</b> (l'âme, le désir, ce qui brûle), le <b>Mercure</b> (l'esprit, le lien, ce qui circule) et le <b>Sel</b> (le corps, l'ancrage, ce qui demeure). Leur équilibre dessine une manière d'être.</p>
      {(() => {
        const maxP = Math.max(1, ...ALC_PRIN_ORDER.map((k) => a.prima[k]));
        const radarAxes = ALC_PRIN_ORDER.map((k) => ({ label: a.principes[k].nom, sub: a.prima[k] + "%", value: a.prima[k] / maxP, color: ALC_PRIN_COL[k] }));
        return (
          <div className="palc-radar-wrap">
            <RadarChart axes={radarAxes} size={236} accent="#b15b36" />
            <div className="palc-legend">
              {ALC_PRIN_ORDER.map((k) => {
                const p = a.principes[k];
                return (
                  <div className="palc-leg-row" key={k}>
                    <div className="palc-leg-top">
                      <span className="palc-leg-sym" style={{ color: ALC_PRIN_COL[k] }}>{p.sym}</span>
                      <span className="palc-leg-name">{p.nom}</span>
                      <span className="palc-leg-pct">{a.prima[k]}<small>%</small></span>
                    </div>
                    <div className="palc-leg-bar"><span style={{ width: a.prima[k] + "%", background: ALC_PRIN_COL[k] }}></span></div>
                    <p className="palc-leg-glose">{p.glose}</p>
                  </div>);
              })}
            </div>
          </div>);
      })()}

      <p className="palc-sub">L'œuvre</p>
      <p className="palc-intro">Le «&nbsp;Grand Œuvre&nbsp;» est, en alchimie, le travail de transformation de la matière — du plomb vers l'or. Ici, aucune magie&nbsp;: c'est une image. Le principe le plus discret de ton prénom montre ce qui demande à grandir — non ce qui te manque, mais ce vers quoi le mouvement t'invite.</p>
      <div className="palc-oeuvre">
        <p><b>{manque.nom}, le principe le plus discret</b> — {a.oeuvre}</p>
        <p className="palc-q">Là où un principe se fait rare, c'est souvent là que se joue le mouvement. Où, dans ta vie, demande-t-il un peu plus de place&nbsp;?</p>
      </div>
      <AlcCross label="Pourquoi le principe le plus discret&nbsp;?">
        <p>En alchimie, on ne cherche pas à supprimer ce qui domine, mais à <b>réveiller ce qui dort</b>. Le principe le moins présent est le point de transformation : l'endroit où la matière (ici, toi) a le plus à apprendre. C'est une invitation, pas un manque à combler.</p>
      </AlcCross>
    </div>);

}

/* L'empreinte chiffrée — la couche CALCULÉE, désormais INTÉGRÉE à la lecture :
   on l'écrit comme une phrase d'explication (gématrie → nombre → matière),
   avec un rappel compact en dessous. C'est elle qui rend la lecture vérifiable. */
function EmpreinteChiffree({ prenom }) {
  const O = window.Onomancie;
  if (!O) return null;
  const base = window.nommageBaseline ? window.nommageBaseline() : null;
  const sig = O.signature(prenom, base);
  const ELM = window.ELEM_META || {};
  const elems = sig.elements || [];
  const nb = NOMBRE_SENS[sig.nombre] || "";
  const e0 = elems[0] ? ELM[elems[0]] : null;
  const e1 = elems[1] ? ELM[elems[1]] : null;
  return (
    <div className="name-cat prenom-empreinte">
      <div className="name-cat-label">L'empreinte des lettres <span className="name-cat-help">— ce que le calcul dit, pas la main</span></div>
      <p className="piste">
        Additionné lettre à lettre (A=1…Z=26), « {prenom} » pèse <b>{sig.gematrie}</b>, qui se ramène au nombre <b>{sig.nombre}</b> — {nb}.
        {e0 &&
        <React.Fragment> Et sa matière penche vers <b>{e0.nom}</b> ({e0.court}){e1 ? <React.Fragment> et <b>{e1.nom}</b> ({e1.court})</React.Fragment> : null} : {e0.trait}{e1 ? ", tempéré par " + e1.trait : ""}.</React.Fragment>}
      </p>
      <div className="prenom-empreinte-chips">
        <span className="prenom-sig-cell"><span className="prenom-sig-k">gématrie</span><span className="prenom-sig-v">{sig.gematrie}</span></span>
        <span className="prenom-sig-cell"><span className="prenom-sig-k">nombre</span><span className="prenom-sig-v">{sig.nombre}</span></span>
        <span className="prenom-sig-cell prenom-sig-elem">
          <span className="prenom-sig-k">élément</span>
          <span className="prenom-sig-v">{elems.map((e) =>
            <span className={"elem-tag elem-" + e.toLowerCase()} key={e}><span className={"elem-dot elem-" + e.toLowerCase()}></span>{ELM[e] ? ELM[e].nom : e}</span>
            )}</span>
        </span>
      </div>
    </div>);

}

/* Bandeau d'accès (aperçu gratuit → analyse complète PRO) */
function PrenomLock({ onUnlock, hasNom, hasOmbres }) {
  const quoi = hasNom && hasOmbres ? "de chaque prénom et du nom" : hasNom ? "du prénom et du nom" : hasOmbres ? "de chaque prénom" : "du prénom";
  return (
    <div className="prenom-lock">
      <div className="prenom-lock-card">
        <div className="eyebrow">L'analyse complète</div>
        <p className="prenom-lock-text">
          Voici un aperçu — l'<b>origine et les premières lettres</b> {quoi}. L'<b>analyse complète</b> déroule
          toutes les lettres une à une, la sonorité, <b>le projet et l'ombre</b> de tes prénoms{hasNom ? <React.Fragment>, la <b>lecture entière de l'héritage du nom</b></React.Fragment> : null},
          la <b>lecture alchimique</b> (gématrie, élément, les trois principes) et la synthèse.
        </p>

        <div className="prenom-lock-ways">
          <button className="prenom-lock-pay" onClick={onUnlock}>
            <span className="prenom-lock-pay-k">Avec l'offre augmentée</span>
            <span className="prenom-lock-pay-t">Débloquer l'analyse complète →</span>
          </button>
          <div className="prenom-lock-or"><span>ou, gratuitement</span></div>
          <button className="prenom-lock-share" onClick={onUnlock}>
            <svg viewBox="0 0 24 24" width="18" height="18" aria-hidden="true"><path fill="currentColor" d="M.057 24l1.687-6.163a11.867 11.867 0 0 1-1.587-5.946C.16 5.335 5.495 0 12.05 0a11.82 11.82 0 0 1 8.413 3.488 11.824 11.824 0 0 1 3.48 8.414c-.003 6.557-5.338 11.892-11.893 11.892a11.9 11.9 0 0 1-5.688-1.448L.057 24zm6.597-3.807c1.676.995 3.276 1.591 5.392 1.592 5.448 0 9.886-4.434 9.889-9.885.002-5.462-4.415-9.89-9.881-9.892-5.452 0-9.887 4.434-9.889 9.884a9.86 9.86 0 0 0 1.51 5.26l-.999 3.648 3.728-.978z"/></svg>
            Partager à un proche &amp; débloquer 48 h
          </button>
          <p className="prenom-lock-share-fine">Un clin d'œil « regarde ce que ça lit dans notre prénom » — et la lecture complète s'ouvre.</p>
        </div>
      </div>
    </div>);

}

/* La liste des lettres : séquence COMPLÈTE, dans l'ordre, ouverture/clôture marquées en ligne.
   `maxClear` (gratuit) : premières lettres nettes, le reste flouté. */
function LettreListe({ seq, maxClear }) {
  if (!seq || !seq.length) return null;
  const last = seq.length - 1;
  const teasing = typeof maxClear === "number" && maxClear < seq.length;
  return (
    <ol className={"lettre-liste" + (teasing ? " lettre-liste--teaser" : "")}>
      {seq.map((l, i) => {
        const tag = i === 0 ? "ouverture" : i === last ? "clôture" : null;
        const locked = teasing && i >= maxClear;
        return (
          <li className={"lettre-row" + (tag ? " lettre-row--" + (i === 0 ? "open" : "close") : "") + (locked ? " lettre-row--locked" : "")} key={i} aria-hidden={locked ? "true" : undefined}>
            <div className="lettre-row-glyph">
              <span className="lettre-row-letter">{l.lettre}</span>
              {tag && <span className="lettre-row-tag">{tag}</span>}
            </div>
            <div className="lettre-row-body">
              <p className="lettre-row-sens">{l.sens}</p>
              <p className="lettre-row-piste">{l.piste}</p>
            </div>
          </li>);

      })}
    </ol>);

}

/* Le mot sous le mot — LANGAGE DES OISEAUX (esprit Burensteinas), lecture
   vibratoire UNIQUE générée par l'IA : clef vibratoire + décodage phonétique +
   sens caché + cheminement continu des lettres. Cohérent avec la fiche SEO.
   Repli gracieux sur la liste de lettres (LangageOiseaux) si l'IA est absente. */
function LangageOiseauxAI({ prenom, seq, teaser, known }) {
  const freshCache = () => {
    const c = window.oiseauxCacheGet && window.oiseauxCacheGet(prenom);
    return c && Array.isArray(c.lettres_lecture) && c.lettres_lecture.length ? c : null;
  };
  const [data, setData] = useStateP(freshCache);
  const [state, setState] = useStateP(data ? "ok" : "idle");
  React.useEffect(() => {
    if (data || teaser || !prenom) return;
    if (!window.genLangageOiseaux) { setState("fail"); return; }
    let alive = true;
    setState("loading");
    window.genLangageOiseaux(prenom, known)
      .then((d) => { if (!alive) return; window.oiseauxCacheSet && window.oiseauxCacheSet(prenom, d); setData(d); setState("ok"); })
      .catch(() => { if (alive) setState("fail"); });
    return () => { alive = false; };
  }, [prenom]);

  // Teaser (gratuit) ou IA indisponible → on garde la liste de lettres existante.
  if (teaser || state === "fail") return <LangageOiseaux prenom={prenom} seq={seq} teaser={teaser} />;
  if (!data) {
    return (
      <div className="name-cat">
        <div className="name-cat-label">Le mot sous le mot <span className="name-cat-help">— le langage des oiseaux</span></div>
        <p className="piste lo-loading">{state === "loading" ? "L'oracle écoute ce que " + prenom + " dit sous le mot…" : ""}</p>
      </div>);
  }
  return (
    <div className="name-cat lo-ai">
      <div className="name-cat-label">Le mot sous le mot <span className="name-cat-help">— le langage des oiseaux</span></div>
      {data.clef_vibratoire && <p className="lo-clef">« {data.clef_vibratoire} »</p>}
      {(data.decoupage_phonetique || data.sens_cache) &&
      <div className="lo-sous">
        {data.decoupage_phonetique && <p>{data.decoupage_phonetique}</p>}
        {data.sens_cache && <p className="lo-cache">{data.sens_cache}</p>}
      </div>}
      {Array.isArray(data.lettres_lecture) && data.lettres_lecture.length
        ? <LettresLecture rows={data.lettres_lecture} seq={seq} />
        : <LangageOiseaux prenom={prenom} seq={seq} headless />}
    </div>);
}

/* Tableau des lettres — lecture UNIQUE par lettre (IA), ancrée sur le sens
   canonique mais tissée dans le prénom. Une lettre répétée a deux lectures
   différentes (position-aware). Tags ouverture / laboratoire / délivrance. */
function LettresLecture({ rows, seq }) {
  const TAG = { porte: "ouverture", "cœur": "laboratoire", coeur: "laboratoire", "délivrance": "délivrance", delivrance: "délivrance" };
  // RÉCONCILIATION : l'IA omet parfois une lettre (ex. le 2e N de Benjamin).
  // On réaligne sur la VRAIE séquence du nom — chaque lettre, dans l'ordre —
  // en piochant la lecture IA correspondante, sinon le sens canonique (Fortuner).
  const safe = (() => {
    if (!seq || !seq.length) return rows || [];
    const LO = window.LANGAGE_OISEAUX || {};
    const byL = {};
    (rows || []).forEach((r) => { const L = (r.lettre || "").toUpperCase().slice(0, 1); if (L) (byL[L] = byL[L] || []).push(r); });
    return seq.map((s, i) => {
      const L = (s.lettre || "").toUpperCase().slice(0, 1);
      const q = byL[L];
      if (q && q.length) { const r = q.shift(); return { lettre: L, role: r.role, lecture: r.lecture }; }
      return { lettre: L, role: i === 0 ? "porte" : i === seq.length - 1 ? "délivrance" : "cœur", lecture: (LO[L] && LO[L].sens) || s.sens || "" };
    });
  })();
  return (
    <React.Fragment>
      <div className="lo-chemin-h">Le cheminement des lettres</div>
      <div className="lo-list">
        {safe.map((r, i) => {
          const tag = TAG[(r.role || "").toLowerCase()] || (i === 0 ? "ouverture" : i === safe.length - 1 ? "délivrance" : "laboratoire");
          return (
            <div className="lo-row" key={i}>
              <div className="lo-glyph"><span className="lo-letter">{(r.lettre || "").toUpperCase().slice(0, 1)}</span><span className="lo-tag">{tag}</span></div>
              <p className="lo-sens">{r.lecture}</p>
            </div>);
        })}
      </div>
    </React.Fragment>);
}

/* Les lettres : LE LANGAGE DES OISEAUX — lecture des lettres du prénom DANS L'ORDRE,
   par leur sens symbolique (forme + son, le chemin A→Z). Format épuré (cf. fiche Kenza).
   `teaser` (gratuit) : 2 lettres nettes, le reste verrouillé sous un voile. */
function LangageOiseaux({ prenom, seq, teaser, headless }) {
  const LO = window.LANGAGE_OISEAUX || {};
  if (!seq || !seq.length) return null;
  const rows = seq.map((l) => ({ letter: l.lettre, sens: (LO[l.lettre] && LO[l.lettre].sens) || l.sens || "" }));
  const last = rows.length - 1;
  const maxClear = teaser ? 2 : rows.length;
  const free = rows.slice(0, maxClear);
  const rest = rows.slice(maxClear);
  // i = index global dans la séquence → marque ouverture (1re) / clôture (dernière)
  const Row = (r, i) => {
    const tag = i === 0 ? "ouverture" : i === last ? "clôture" : null;
    return (
      <div className={"lo-row" + (tag ? " lo-row--" + (i === 0 ? "open" : "close") : "")} key={i}>
        <div className="lo-glyph"><span className="lo-letter">{r.letter}</span>{tag && <span className="lo-tag">{tag}</span>}</div>
        <p className="lo-sens">{r.sens}</p>
      </div>);
  };
  const inner = (
    <React.Fragment>
      <div className="lo-list">{free.map((r, i) => Row(r, i))}</div>
      {rest.length > 0 && !teaser &&
      <div className="lo-list lo-rest is-locked">
        {rest.map((r, i) => Row(r, maxClear + i))}
        <div className="lo-lock"><span className="lo-lock-pill">✦ Les lettres suivantes — réservées à l'Oracle complet</span></div>
      </div>}
      {rest.length > 0 && teaser &&
      <p className="lo-teaser-note">…et {rest.length} autres lettres — dans l'analyse complète, plus bas.</p>}
    </React.Fragment>);
  if (headless) {
    return (
      <React.Fragment>
        <div className="lo-chemin-h">Le cheminement des lettres</div>
        {inner}
      </React.Fragment>);
  }
  return (
    <div className="name-cat">
      <div className="name-cat-label">Les lettres <span className="name-cat-help">— le langage des oiseaux</span></div>
      <p className="piste lo-intro">Le langage des oiseaux écoute les mots autrement&nbsp;: par la forme et le sens de chaque lettre, comme un petit chemin de A à Z. Lues ainsi, les {rows.length} lettres de {prenom} dessinent un mouvement&nbsp;:</p>
      {inner}
    </div>);

}

/* La racine — gère le cas du prénom composé (plusieurs racines tissées) */
function RacineBlock({ etym }) {
  if (etym.compose) {
    return (
      <React.Fragment>
        {etym.compose.map((part, i) =>
        <div className="compose-part" key={i}>
            <div className="compose-part-name">{part.prenom}</div>
            {part.data ?
          <React.Fragment>
                <p className="prenom-etym"><span className="prenom-orig">{part.data.o}</span>{part.data.s ? " · " + part.data.s : ""}</p>
                <p className="piste">{part.data.piste}</p>
              </React.Fragment> :

          <p className="piste">Racine non répertoriée — la lecture s'appuie sur ses lettres et ses sons.</p>
          }
          </div>
        )}
      </React.Fragment>);

  }
  return (
    <React.Fragment>
      {etym.origine &&
      <p className="prenom-etym"><span className="prenom-orig">{etym.origine}</span>{etym.sens ? " · " + etym.sens : ""}</p>
      }
      <p className="piste">{etym.piste}</p>
    </React.Fragment>);

}

/* ----- Lecture unifiée d'UN nom (1er prénom, ombre, ou nom de famille) -----
   Mêmes catégories pour les trois : Racine · Lettres · Sonorité · Rôle.
   `racineOnly` = aperçu gratuit (on ne montre que la racine).            */
function NameReading({ r, size, racineOnly, teaser, headless, showEmpreinte, oiseaux, noRacine, ficheKind }) {
  const Questions = window.Questions;
  const Lettrine = window.Lettrine;
  const roleClass = r.role === "ombre" ? " name-reading--ombre" : r.role === "heritage" ? " name-reading--nom" : " name-reading--projet";
  // Fiche « dico » propre à cette lecture (ombre ou nom) — même gabarit que le prénom.
  const ficheRes = ficheKind ? { prenom: r.label, etym: r.etym, found: !!(r.etym && r.etym.found) } : null;
  const subFiche = useFiche(ficheKind ? r.label : null, ficheRes, ficheKind || "prenom");
  const hideRacine = noRacine || !!ficheKind;

  return (
    <div className={"name-reading" + roleClass}>
      {!headless &&
      <div className="name-reading-head" style={{ margin: "0px 0px 22px" }}>
        <Lettrine mot={r.label} size={size || 72} />
        <div className="name-reading-id">
          <div className="name-reading-label">{r.label}</div>
        </div>
      </div>}

      {/* Bloc « dico classique » adapté (ombre = bref, nom = répartition + variantes) */}
      {ficheKind && <FicheClassique res={ficheRes} fiche={subFiche} kind={ficheKind} />}

      {/* 1 · La racine (masquée si une fiche « origine » la couvre déjà) */}
      {!hideRacine &&
      <div className="name-cat">
        <div className="name-cat-label">La racine <span className="name-cat-help">— d'où ça vient</span></div>
        <RacineBlock etym={r.etym} />
      </div>}

      {/* L'empreinte chiffrée — intégrée à la lecture (gématrie · nombre · matière) */}
      {showEmpreinte && <EmpreinteChiffree prenom={r.label} />}

      {/* Aperçu gratuit : les 2 premières lettres, le reste verrouillé */}
      {teaser && (oiseaux ?
      <LangageOiseaux prenom={r.label} seq={r.graphie.lettresSeq} teaser /> :
      <div className="name-cat">
          <div className="name-cat-label">Les lettres <span className="name-cat-help">— {r.label.toLowerCase()}, lettre à lettre</span></div>
          <LettreListe seq={r.graphie.lettresSeq} maxClear={2} />
        </div>)
      }

      {!racineOnly && !teaser &&
      <React.Fragment>
          {/* 2 · Les lettres */}
          {oiseaux ?
          <LangageOiseauxAI prenom={r.label} seq={r.graphie.lettresSeq} known={r.etym ? { origine: r.etym.origine, sens: r.etym.sens } : null} /> :
          <div className="name-cat">
            <div className="name-cat-label">Les lettres <span className="name-cat-help">— {r.label.toLowerCase()}, lettre à lettre</span></div>
            <LettreListe seq={r.graphie.lettresSeq} />
          </div>}

          {/* 3 · La sonorité */}
          {r.sonTexte &&
        <div className="name-cat">
              <div className="name-cat-label">La sonorité <span className="name-cat-help">— comment ça résonne</span></div>
              <p className="piste">{r.sonTexte.replace(/\.+$/, "")}.</p>
            </div>
        }

          {/* 4 · Le rôle (projet / ombre / héritage) */}
          <div className="name-cat name-cat--role">
            <div className="name-cat-label">{r.framing.titre} <span className="name-cat-help">— {r.framing.sous}</span></div>
            <p className="piste">{r.framing.texte}</p>
            {Questions && <Questions q={r.framing.q} label="Questions à se poser" />}
          </div>
        </React.Fragment>
      }
    </div>);

}

/* Section complète d'un nom (2ᵉ prénom / nom de famille) — MÊME GABARIT que le
   prénom principal : en-tête carte+enluminure à gauche, nom + essence/badges à
   droite, puis le corps « dico » (origine, répartition, variantes), puis
   l'anatomie (lettres, sonorité, rôle). Évite l'asymétrie avec le prénom. */
function NameSection({ r, kind, size }) {
  const O = window.Onomancie;
  const sig = O ? O.signature(r.label, window.nommageBaseline ? window.nommageBaseline() : null) : null;
  const mat = sig ? (sig.poids <= 0.4 ? "légère" : sig.poids >= 0.6 ? "dense" : "posée") : null;
  const ficheRes = { prenom: r.label, etym: r.etym, found: !!(r.etym && r.etym.found) };
  const subFiche = useFiche(r.label, ficheRes, kind);
  const isNom = kind === "nom";
  const gi = r.graphie ? r.graphie.initiale : null;
  const sub = (r.etym && r.etym.found && r.etym.sens)
    ? ((r.etym.origine ? r.etym.origine + " · " : "") + r.etym.sens)
    : (gi ? gi.sens : null);
  return (
    <div className={"name-section name-section--" + kind}>
      <div className="prenom-head prenom-head-card">
        {window.FicheCard && <window.FicheCard
          inline
          word={r.label}
          kindLabel={isNom ? "Nom" : "Prénom"}
          elemParts={sig ? sig.elements : []}
          gematrie={sig ? sig.gematrie : null}
          nombre={sig ? sig.nombre : null}
          matiere={mat}
          sub={sub}
          line={gi ? gi.sens : (r.etym && r.etym.piste) || ""} />}
        <div className="prenom-head-main">
          <div className="prenom-head-txt">
            <div className="eyebrow">{isNom ? "Le nom" : "Un autre prénom"}</div>
            <div className="prenom-name">{r.label}</div>
            <FicheClassique res={ficheRes} fiche={subFiche} kind={kind} part="head" />
          </div>
        </div>
      </div>
      <FicheClassique res={ficheRes} fiche={subFiche} kind={kind} part="body" />
      <NameReading r={r} size={size} headless oiseaux noRacine />
    </div>);

}

/* Les données globales CLASSIQUES — en tête de lecture, comme une fiche prénom
   (genre, origine, sens, nombre de lettres). C'est le « début » : de l'info de
   prénom, PAS la couche chiffrée (qui vit, elle, dans la lecture alchimique). */
function PrenomGlobalData({ res }) {
  const key = res.prenom.normalize("NFD").replace(/[\u0300-\u036f]/g, "").trim().split(/[\s-]+/)[0].toLowerCase();
  const g = window.PRENOM_GENRE ? window.PRENOM_GENRE[key] : null;
  const genreLabel = g === "f" ? "Prénom féminin" : g === "m" ? "Prénom masculin" : g === "x" ? "Prénom mixte" : null;
  const nLett = res.prenom.normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/[^A-Za-z]/g, "").length;
  const origine = res.found && res.etym.origine ? res.etym.origine.split("/")[0].trim() : null;
  const sens = res.found && res.etym.sens ? res.etym.sens.replace(/^[«»"\s]+|[«»"\s]+$/g, "") : null;

  const badges = [];
  if (genreLabel) badges.push(genreLabel);
  if (origine) badges.push("Origine " + origine.toLowerCase());
  if (sens) badges.push("« " + sens + " »");
  badges.push(nLett + " lettres");

  let lead = null;
  if (genreLabel || origine || sens) {
    lead = res.prenom + " est un " + (genreLabel ? genreLabel.toLowerCase() : "prénom");
    if (origine) lead += " d'origine " + origine.toLowerCase();
    if (sens) lead += " qui signifie « " + sens + " »";
    lead += ".";
  }

  return (
    <div className="prenom-global">
      <div className="prenom-badges">
        {badges.map((b, i) => <span className="prenom-badge" key={i}>{b}</span>)}
      </div>
      {lead && <p className="prenom-global-lead">{lead}</p>}
    </div>);

}

/* La synthèse GLOBALE — écrite par l'IA, tout à la fin, mêlée à l'œuvre.
   Tisse le classique et l'alchimique en un seul portrait. Repli déterministe. */
function SyntheseGlobale({ res, onText }) {
  const [st, setSt] = useStateP({ loading: true, body: [], q: null });
  React.useEffect(() => {
    let alive = true;
    setSt({ loading: true, body: [], q: null });
    (async () => {
      let raw;
      try { raw = await window.genSyntheseGlobale(res); }
      catch (e) { raw = window.syntheseGlobaleFallback ? window.syntheseGlobaleFallback(res) : (res.synthese || ""); }
      if (!alive) return;
      const lines = (raw || "").split("\n").map((s) => s.trim()).filter(Boolean);
      const qi = lines.findIndex((l) => /^✦/.test(l));
      let body, q = null;
      if (qi >= 0) { q = lines[qi].replace(/^✦\s*/, ""); body = lines.slice(0, qi); }
      else body = lines;
      if (!body.length) body = [res.synthese || ""];
      setSt({ loading: false, body: body, q: q });
      onText && onText(raw);
    })();
    return () => { alive = false; };
  }, [res.prenom, res.nom]);

  return (
    <div className="prenom-synthese">
      <div className="eyebrow">La synthèse · ce que l'ensemble dessine</div>
      {st.loading ?
      <p className="prenom-synthese-load"><span className="pdot"></span><span className="pdot"></span><span className="pdot"></span> la synthèse se tisse…</p> :

      <React.Fragment>
          {st.body.map((p, i) => <p className="prenom-synthese-p" key={i}>{p}</p>)}
          {st.q && <p className="prenom-synthese-q">{st.q}</p>}
        </React.Fragment>
      }
    </div>);

}

/* ---------------- Fiche classique « dico » (IA + repli) ---------------- */
/* Nettoie un « » » orphelin de fin (l'IA en ajoute parfois un de trop). */
function cleanEssence(s) {
  if (!s) return s;
  let t = String(s).trim();
  const open = (t.match(/«/g) || []).length, close = (t.match(/»/g) || []).length;
  if (close > open && /»\s*$/.test(t)) t = t.replace(/\s*»\s*$/, "");
  return t;
}
/* Fusionne la fiche IA PAR-DESSUS le repli déterministe : on ne garde une valeur
   de l'IA que si elle est substantielle (chaîne >1 car., tableau non vide), sinon
   on conserve celle du dico. Évite qu'une réponse IA vide/corrompue (ex. essence
   « x », origine_paragraphes []) n'efface le « début » déjà calculé. */
function mergeFiche(seed, ai) {
  if (!seed) return ai; if (!ai) return seed;
  const out = Object.assign({}, seed);
  Object.keys(ai).forEach(function (k) {
    const v = ai[k];
    if (Array.isArray(v)) { if (v.length) out[k] = v; }
    else if (typeof v === "string") { if (v.trim().length > 1) out[k] = v; }
    else if (v != null) out[k] = v;
  });
  return out;
}
/* Hook : récupère (et met en cache) la fiche éditoriale IA. kind = prenom|ombre|nom. */
function useFiche(prenom, res, kind) {
  kind = kind || "prenom";
  const [state, setState] = useStateP({ loading: false, data: null });
  React.useEffect(() => {
    if (!res || !prenom) { setState({ loading: false, data: null }); return; }
    let alive = true;
    const seed = window.ficheClassiqueFallback ? window.ficheClassiqueFallback(res, kind) : null;
    const cached = window.ficheCacheGet ? window.ficheCacheGet(prenom, kind) : null;
    if (cached) { setState({ loading: false, data: mergeFiche(seed, cached) }); return; }
    setState({ loading: true, data: seed });
    (async () => {
      // 1) backend PARTAGÉ si configuré (générée une fois, servie à tous) ;
      // 2) sinon génération locale via window.claude (prévisualisation).
      const known = res.etym ? { origine: res.etym.origine, sens: res.etym.sens } : null;
      try {
        let data;
        if (window.ficheApiBase && window.ficheApiBase()) {
          try { data = await window.remoteFiche(res.prenom, kind, known); }
          catch (e) { data = await window.genFicheClassique(res, kind); }
        } else {
          data = await window.genFicheClassique(res, kind);
        }
        if (alive) { const merged = mergeFiche(seed, data); setState({ loading: false, data: merged }); window.ficheCacheSet && window.ficheCacheSet(prenom, merged, kind); }
      } catch (e) {
        if (alive) setState({ loading: false, data: seed });
      }
    })();
    return () => { alive = false; };
  }, [prenom, kind, !!res]);
  return state;
}

/* Le bloc « dico classique » — adaptatif selon kind (prenom | ombre | nom).
   prenom : badges + signification + popularité + similaires.
   ombre  : version brève (essence + origine + similaires par le sens).
   nom    : origine + répartition géographique + variantes (besoins propres au patronyme). */
function FicheClassique({ res, fiche, kind, onPick, part }) {
  kind = kind || "prenom";
  const showHead = part !== "body";
  const showBody = part !== "head";
  const ELM = window.ELEM_META || {};
  const ELEM_COLOR = { Feu: "#b8502f", Eau: "#4f7a86", Air: "#bd9a40", Terre: "#7a5a39" };
  const O = window.Onomancie;
  const sig = O ? O.signature(res.prenom, window.nommageBaseline ? window.nommageBaseline() : null) : null;
  const elem = sig && sig.elements && sig.elements[0];
  const d = fiche.data || {};
  const isNom = kind === "nom";

  return (
    <div className={"fiche-classique fiche-classique--" + kind + (part ? " fiche-classique--" + part : "")}>
      {showHead && <React.Fragment>
      {d.essence && <p className="kfiche-essence">{cleanEssence(d.essence)}</p>}

      <div className="fiche-badges">
        {isNom ?
          (d.type && <span className="fiche-badge">{d.type.charAt(0).toUpperCase() + d.type.slice(1)}</span>) :
          (d.genre && <span className="fiche-badge">Prénom {d.genre}</span>)}
        {!isNom && d.fete && <span className="fiche-badge">Fête&nbsp;: {d.fete}</span>}
        {d.origine && <span className="fiche-badge">Origine {String(d.origine).replace(/^(adjectif|nom|mot|forme)\s+/i, "").split(/[,;(]/)[0].trim().toLowerCase()}</span>}
        {kind === "prenom" && elem && <span className="fiche-badge is-elem">Élément&nbsp;: {ELM[elem] ? ELM[elem].nom : elem}</span>}
      </div>
      </React.Fragment>}

      {showBody && <React.Fragment>
      {d.lead && <p className="fiche-lead">{d.lead}</p>}

      {(d.origine_paragraphes && d.origine_paragraphes.length > 0) &&
      <div className="name-cat">
        <div className="name-cat-label">{isNom ? "Origine du nom" : "Signification et origine"} <span className="name-cat-help">— d'où ça vient</span></div>
        {d.origine_paragraphes.map((p, i) => <p className="fiche-p" key={i}>{p}</p>)}
      </div>}

      {/* prénom : popularité — VRAIES données INSEE (jamais inventées) */}
      {kind === "prenom" && window.inseeStats && window.inseeStats(d.p || d.prenom || (res && res.prenom)) &&
      (() => {
        const st = window.inseeStats(d.p || d.prenom || res.prenom);
        return (
        <div className="name-cat">
          <div className="name-cat-label">Popularité <span className="name-cat-help">— données INSEE</span></div>
          <div className="fiche-table-wrap">
            <table className="fiche-table">
              <tbody>
                <tr><td><b>Pic de popularité</b></td><td>{st.pic}</td></tr>
                <tr><td><b>Tendance récente</b></td><td>{st.tendance}</td></tr>
                {st.note && <tr><td><b>À noter</b></td><td>{st.note}</td></tr>}
              </tbody>
            </table>
          </div>
          <p className="fiche-source-note">Source&nbsp;: {st.source}.</p>
        </div>);
      })()}

      {/* nom : répartition géographique */}
      {(d.repartition && d.repartition.length > 0) &&
      <div className="name-cat">
        <div className="name-cat-label">Répartition <span className="name-cat-help">— où le nom est porté</span></div>
        <div className="fiche-table-wrap">
          <table className="fiche-table">
            <thead><tr><th>Région / Pays</th><th>Présence</th></tr></thead>
            <tbody>
              {d.repartition.map((row, i) => <tr key={i}><td><b>{row.region}</b></td><td>{row.presence}</td></tr>)}
            </tbody>
          </table>
        </div>
        <p className="fiche-table-note">Tendances générales de répartition du nom ; les relevés précis dépendent des archives d'état civil.</p>
      </div>}

      {/* prénom : prénoms similaires (son + sens) */}
      {(((d.similaires_son && d.similaires_son.length > 0) || (kind !== "nom" && d.similaires_sens && d.similaires_sens.length > 0)) ? true : false) &&
      <div className="name-cat">
        <div className="name-cat-label">Prénoms similaires <span className="name-cat-help">— par la sonorité et le sens</span></div>
        {d.similaires_son && d.similaires_son.length > 0 &&
        <div className="simil-block">
          <p className="simil-h">Par l'origine et la sonorité</p>
          <div className="flame-row">
            {d.similaires_son.map((n, i) =>
            onPick
              ? <button className="flame-chip flame-chip--btn" key={i} onClick={() => onPick(n)}><span className="flame-dot" style={{ background: ELEM_COLOR[elem] || "#bd9a40" }}></span>{n}</button>
              : <span className="flame-chip" key={i}><span className="flame-dot" style={{ background: ELEM_COLOR[elem] || "#bd9a40" }}></span>{n}</span>)}
          </div>
        </div>}
        {d.similaires_sens && d.similaires_sens.length > 0 &&
        <div className="simil-block">
          <p className="simil-h">Par le sens</p>
          <div className="simil-sens-row">
            {d.similaires_sens.map((s, i) =>
            onPick
              ? <button className="simil-sens simil-sens--btn" key={i} onClick={() => onPick(s.nom)}><span className="flame-dot" style={{ background: ELEM_COLOR[elem] || "#bd9a40" }}></span><b>{s.nom}</b> — {s.sens}</button>
              : <span className="simil-sens" key={i}><span className="flame-dot" style={{ background: ELEM_COLOR[elem] || "#bd9a40" }}></span><b>{s.nom}</b> — {s.sens}</span>)}
          </div>
        </div>}
      </div>}

      {/* nom : variantes et formes proches */}
      {(d.variantes && d.variantes.length > 0) &&
      <div className="name-cat">
        <div className="name-cat-label">Variantes et formes proches <span className="name-cat-help">— la même racine, d'autres graphies</span></div>
        <div className="flame-row">
          {d.variantes.map((n, i) => <span className="flame-chip" key={i}><span className="flame-dot" style={{ background: "#7a5a39" }}></span>{n}</span>)}
        </div>
      </div>}
      </React.Fragment>}
    </div>);

}

/* La FAQ — tout en bas, comme jean.html. */
function FicheFAQ({ fiche }) {
  const d = fiche.data || {};
  if (!d.faq || !d.faq.length) return null;
  return (
    <div className="name-cat fiche-faq">
      <div className="name-cat-label">Questions fréquentes</div>
      {d.faq.map((item, i) =>
      <details className="faq-item" key={i}>
        <summary>{item.q}</summary>
        <div className="faq-a"><p>{item.a}</p></div>
      </details>)}
    </div>);

}

/* ---------------- Espace Essence du prénom ---------------- */
function PrenomSpace({ onSave, pending, onConsumePending }) {
  const [phase, setPhase] = useStateP("accueil"); // accueil | lecture
  const [prenom, setPrenom] = useStateP("");
  const [autres, setAutres] = useStateP("");
  const [nom, setNom] = useStateP("");
  const [res, setRes] = useStateP(null);
  const [note, setNote] = useStateP("");
  const [relation, setRelation] = useStateP("moi"); // moi | proche
  const [relLabel, setRelLabel] = useStateP("");
  const [saved, setSaved] = useStateP(false);
  const [share, setShare] = useStateP(false);
  const [synthText, setSynthText] = useStateP("");

  const { pro, openPaywall } = React.useContext(PR.OracleCtx);
  const fiche = useFiche(res && res.prenom, res);
  const Lettrine = window.Lettrine;
  const ShareCard = window.ShareCard;

  function reveler() {
    if (!prenom.trim()) return;
    setRes(PR.analysePrenom(prenom, autres, nom));
    setNote("");setSaved(false);setRelation("moi");setRelLabel("");
    setPhase("lecture");
  }
  function reset() {setPhase("accueil");setRes(null);}

  // Fiche complète demandée depuis « Trouver un prénom » : préremplir + lire directement.
  React.useEffect(() => {
    if (pending && pending.prenom) {
      setPrenom(pending.prenom);
      setAutres("");
      setNom(pending.nom || "");
      setRes(PR.analysePrenom(pending.prenom, "", pending.nom || ""));
      setNote(""); setSaved(false); setRelation("proche"); setRelLabel("l'enfant qui vient");
      setPhase("lecture");
      onConsumePending && onConsumePending();
    }
  }, [pending && pending.prenom, pending && pending.nom]);

  // Clic sur un prénom similaire → relire ce prénom dans l'app (SPA).
  function readPrenom(name) {
    const nm = (name || "").trim();
    if (!nm) return;
    setPrenom(nm); setAutres(""); setNom("");
    setRes(PR.analysePrenom(nm, "", ""));
    setNote(""); setSaved(false); setRelation("proche"); setRelLabel("");
    setSynthText(""); setShare(false);
    setPhase("lecture");
    try { window.scrollTo({ top: 0, behavior: "smooth" }); } catch (e) { window.scrollTo(0, 0); }
  }

  function garder() {
    if (saved || !res) return;
    onSave({
      id: Date.now(), space: "prenom",
      prenom: res.prenom, nom: res.nom,
      relation: relation, relLabel: relation === "proche" ? relLabel.trim() : "",
      found: res.found,
      prenomsFull: res.prenomsFull,
      ombres: res.ombres.map((o) => ({ prenom: o.label, sens: o.etym ? o.etym.sens : "" })),
      etym: res.found ? { origine: res.etym.origine, sens: res.etym.sens, piste: res.etym.piste } : null,
      initiale: res.initiale ? res.initiale.lettre : "",
      finale: res.finale ? res.finale.lettre : "",
      synthese: synthText || res.synthese, questions: (res.questions || []).slice(),
      intention: note.trim()
    });
    setSaved(true);
  }

  return (
    <React.Fragment>
      {phase === "accueil" &&
      <div className="fade-screen">
          <div className="eyebrow">L'essence de ton prénom</div>
          <h1 className="lede">Ton prénom n'est pas neutre.<br />Il te <em>raconte</em> déjà.</h1>
          <p className="sub">Pas de numérologie ni de destin. On lit chaque nom de la même façon — sa racine, ses lettres, sa sonorité — puis ce que chacun dit de ta lignée : le projet, l'ombre, l'héritage. Un miroir : garde ce qui résonne, laisse le reste.</p>

          <div className="field">
            <div className="prenom-fields">
              <div className="prenom-input-wrap">
                <label className="field-label" htmlFor="pr">Ton premier prénom</label>
                <input id="pr" className="prenom-input" type="text" autoComplete="off"
              placeholder="Sébastien…" value={prenom}
              onChange={(e) => setPrenom(e.target.value)}
              onKeyDown={(e) => {if (e.key === "Enter") reveler();}} />
              </div>
              <div className="prenom-input-wrap">
                <label className="field-label" htmlFor="autres">Tes autres prénoms <span className="opt">— optionnel</span></label>
                <input id="autres" className="prenom-input" type="text" autoComplete="off"
              placeholder="Jean…" value={autres}
              onChange={(e) => setAutres(e.target.value)}
              onKeyDown={(e) => {if (e.key === "Enter") reveler();}} />
              </div>
            </div>
            <div className="prenom-input-wrap prenom-nom-wrap">
              <label className="field-label" htmlFor="nm">Ton nom <span className="opt">— optionnel</span></label>
              <input id="nm" className="prenom-input" type="text" autoComplete="off"
            placeholder="…" value={nom}
            onChange={(e) => setNom(e.target.value)}
            onKeyDown={(e) => {if (e.key === "Enter") reveler();}} />
            </div>
            <p className="prenom-hint">Dans l'ordre de l'état civil. Le <b>premier</b> dit ce que ta lignée espérait que tu sois ou que tu apportes ; les <b>suivants</b> gardent souvent un désir mis dans l'ombre.</p>

            <div className="actions">
              <button className="btn-primary" onClick={reveler} disabled={!prenom.trim()}>Révéler l'essence</button>
              <span className="hint-inline">le tien, ou celui d'un proche</span>
            </div>
          </div>
        </div>
      }

      {phase === "lecture" && res &&
      <div className="fade-screen">
          {/* En-tête : enluminure/carte à GAUCHE, nom à DROITE — comme les fiches statiques */}
          <div className="prenom-head prenom-head-card">
            {window.FicheCard && (() => {
              const O = window.Onomancie;
              const sig = O ? O.signature(res.prenom, window.nommageBaseline ? window.nommageBaseline() : null) : null;
              const mat = sig ? (sig.poids <= 0.4 ? "légère" : sig.poids >= 0.6 ? "dense" : "posée") : null;
              return <window.FicheCard
                inline
                word={res.prenom}
                kindLabel="Prénom"
                elemParts={sig ? sig.elements : []}
                gematrie={sig ? sig.gematrie : null}
                nombre={sig ? sig.nombre : null}
                matiere={mat}
                sub={res.found ? res.etym.origine + " · " + res.etym.sens : res.initiale ? res.initiale.sens : null}
                line={res.initiale ? res.initiale.sens : res.found ? res.etym.piste : ""} />;
            })()}
            <div className="prenom-head-main">
              <div className="prenom-head-txt">
                <div className="eyebrow">{res.ombres.length ? "Tes prénoms" : res.nom ? "Ton prénom et ton nom" : "Ton prénom"}</div>
                <div className="prenom-name">{res.prenom}{res.ombres.map((o, i) => <span className="prenom-ombre-name" key={i}> {o.label}</span>)}{res.nom ? <span className="prenom-surname"> {res.nom}</span> : null}</div>
                {pro && res.archetype && <div className="prenom-archetype">{res.archetype}</div>}
                {fiche && fiche.data && <FicheClassique res={res} fiche={fiche} kind="prenom" part="head" />}
              </div>
            </div>
          </div>

          {/* Bloc « dico classique » — essence, accroche, signification & origine, popularité, similaires */}
          <FicheClassique res={res} fiche={fiche} kind="prenom" part="body" onPick={readPrenom} />

          {/* APERÇU GRATUIT : pour CHAQUE nom (prénom, autres prénoms, nom de
             famille) on montre NET l'étymologie + les 2 premières lettres ;
             la lecture profonde (lettres complètes, sonorité, projet/ombre,
             alchimie) reste derrière le verrou unique. */}
          {!pro &&
        <React.Fragment>
              <NameReading r={res.primary} size={84} teaser headless oiseaux noRacine />
              {res.ombres.map((o, i) => <NameReading r={o} size={72} key={i} teaser oiseaux />)}
              {res.nomReading && <NameReading r={res.nomReading} size={72} teaser oiseaux />}
              <PrenomLock onUnlock={openPaywall} hasNom={!!res.nomReading} hasOmbres={res.ombres.length > 0} />
            </React.Fragment>
        }

          {/* ANALYSE COMPLÈTE : chaque nom, même anatomie */}
          {pro &&
        <React.Fragment>
              <NameReading r={res.primary} size={84} headless oiseaux noRacine />
              {res.ombres.map((o, i) => <NameSection r={o} kind="ombre" size={72} key={i} />)}
              {res.ombres.length > 0 &&
          <p className="ombre-source">L'ombre s'inspire de la psychogénéalogie (P. del Castillo, M. Fréchet, A. Jodorowsky) — une lentille de réflexion, pas une vérité sur ta famille.</p>
          }
              {res.nomReading && <NameSection r={res.nomReading} kind="nom" size={72} />}

              {/* Le corps, peut-être (question, jamais un diagnostic) */}
              {res.corps &&
          <div className="block prenom-block prenom-corps">
                  <div className="pos-label"><span>Le corps, peut-être</span><span className="pos-help">— une question, pas un diagnostic</span></div>
                  <p className="piste">Le corps garde parfois la trace de ce que le prénom porte. Rien d'écrit, rien de médical — seulement une question à écouter, si elle te parle.</p>
                  {window.Questions && <window.Questions q={[res.corps]} label="À écouter" />}
                </div>
          }

              {/* La lecture alchimique — la couche calculée déployée (partie 2) */}
              <LectureAlchimique res={res} />

              {/* La synthèse globale — écrite par l'IA, tout à la fin, mêlée à l'œuvre */}
              <SyntheseGlobale res={res} onText={setSynthText} />
            </React.Fragment>
        }

          {/* La FAQ — tout en bas, comme jean.html */}
          <FicheFAQ fiche={fiche} />

          <div className="mirror-note">
            <span>↳</span>
            <span><b>Un miroir, pas un verdict.</b> Ton prénom ne te détermine pas — il te tend une image. Ce qui résonne t'appartient déjà ; ce qui sonne faux n'a pas à être gardé.</span>
          </div>

          <div className="prenom-end-actions">
            {pro && <button className="prenom-pdf-btn" onClick={() => window.print()}>Télécharger la fiche (PDF)</button>}
          </div>

          {/* Enregistrement + à qui */}
          <div className="integration">
            <div className="prenom-whose">
              <span className="field-label">À qui est ce prénom ?</span>
              <div className="whose-opts">
                <button className={"whose-opt" + (relation === "moi" ? " whose-on" : "")} onClick={() => setRelation("moi")}>Le mien</button>
                <button className={"whose-opt" + (relation === "proche" ? " whose-on" : "")} onClick={() => setRelation("proche")}>Un proche</button>
              </div>
              {relation === "proche" &&
            <input className="prenom-input whose-label" type="text" placeholder="Qui ? (ma sœur, un ami, mon fils…)"
            value={relLabel} onChange={(e) => {setRelLabel(e.target.value);setSaved(false);}} />
            }
            </div>

            <label className="field-label" htmlFor="prnote">Une note, si tu veux</label>
            <textarea id="prnote" className="intention-area"
          placeholder="Ce qui résonne, ce que ce prénom éclaire…"
          value={note} onChange={(e) => {setNote(e.target.value);setSaved(false);}}></textarea>

            <div className="reading-actions">
              <button className="btn-secondary" onClick={garder} disabled={saved}>
                {saved ? "Gardé dans le journal" : "Garder dans le journal"}
              </button>
              {saved && <span className="saved-flag"><span className="dot"></span>enregistré</span>}
              <button className="ghost-btn" onClick={reset}>Un autre prénom →</button>
            </div>
          </div>

          {share && window.FicheCard && (() => {
          const O = window.Onomancie;
          const sig = O ? O.signature(res.prenom, window.nommageBaseline ? window.nommageBaseline() : null) : null;
          const mat = sig ? sig.poids <= 0.4 ? "légère" : sig.poids >= 0.6 ? "dense" : "posée" : null;
          return <window.FicheCard
            word={res.prenom}
            kindLabel="Prénom"
            elemParts={sig ? sig.elements : []}
            gematrie={sig ? sig.gematrie : null}
            nombre={sig ? sig.nombre : null}
            matiere={mat}
            sub={res.found ? res.etym.origine + " · " + res.etym.sens : res.initiale ? res.initiale.sens : null}
            line={res.initiale ? res.initiale.sens : res.found ? res.etym.piste : ""}
            onClose={() => setShare(false)} />;
        })()}
        </div>
      }
    </React.Fragment>);

}

window.PrenomSpace = PrenomSpace;