/* ============================================================
   Auth chrome — identity control (top bar), login popover with
   role-scoped accounts, and the compact review/guest feedback dock.
   Mirrors the backend tables: users · user_sessions ·
   user_access_grants (SHARED | EDITORIAL) · content_feedback.
   ============================================================ */
const { useState: uSau, useEffect: uEau, useRef: uRau } = React;

/* bilingual chrome labels for the identity control + login popover */
const SIGN = {
  en: { signin: "Sign in", who: "Sign in", chooseSub: "Enter your email and password to access your space.",
    emailLabel: "Email", pwLabel: "Password", enter: "Sign in", stay: "Stay connected on this device",
    badCreds: "Incorrect email or password.", signingIn: "Signing in…",
    adminMode: "Admin Board", editMode: "Enter edit mode", reviewMode: "Enter review mode", publishMode: "Enter publish mode", testerMode: "Enter tester mode", editHere: "Edit this page",
    closeAdmin: "Close edit mode", closeEdit: "Close edit mode", closeReview: "Close review mode", closePublish: "Close publish mode", closeTester: "Close tester mode",
    board: "Admin Board", settings: "Open settings", manage: "Manage roles & shared content", logout: "Log out", account: "Account settings",
    shared: "Shared with you", seeAll: "See all my shared content", noShared: "No content shared with you yet.", priv: "private",
    editNote: "You edit drafts & untranslated content. Publishing, settings and users stay locked.",
    reviewNote: "You can validate pieces in review and leave feedback. Read-only otherwise.",
    publishNote: "You publish validated pieces and schedule go-live dates. Private pages can't be published.",
    testerNote: "You preview pre-released (in-review & validated) public pages before they go live." },
  fr: { signin: "Connexion", who: "Connexion", chooseSub: "Entrez votre email et votre mot de passe pour acc\u00e9der \u00e0 votre espace.",
    emailLabel: "Email", pwLabel: "Mot de passe", enter: "Se connecter", stay: "Rester connect\u00e9 sur cet appareil",
    badCreds: "Email ou mot de passe incorrect.", signingIn: "Connexion\u2026",
    adminMode: "Tableau d'admin", editMode: "Entrer en mode \u00e9dition", reviewMode: "Entrer en mode relecture", publishMode: "Entrer en mode publication", testerMode: "Entrer en mode testeur", editHere: "\u00c9diter cette page",
    closeAdmin: "Fermer le mode \u00e9dition", closeEdit: "Fermer le mode \u00e9dition", closeReview: "Fermer le mode relecture", closePublish: "Fermer le mode publication", closeTester: "Fermer le mode testeur",
    board: "Tableau d'admin", settings: "Ouvrir les r\u00e9glages", manage: "G\u00e9rer les r\u00f4les & contenus partag\u00e9s", logout: "Se d\u00e9connecter", account: "Mon compte",
    shared: "Partag\u00e9 avec vous", seeAll: "Voir tous mes contenus partag\u00e9s", noShared: "Aucun contenu partag\u00e9 pour l'instant.", priv: "priv\u00e9e",
    editNote: "Vous \u00e9ditez les brouillons & contenus non traduits. Publication, r\u00e9glages et utilisateurs restent verrouill\u00e9s.",
    reviewNote: "Vous pouvez valider les contenus en relecture et laisser un feedback. Lecture seule sinon.",
    publishNote: "Vous publiez les contenus valid\u00e9s et programmez leur mise en ligne. Les pages priv\u00e9es ne peuvent pas \u00eatre publi\u00e9es.",
    testerNote: "Vous pr\u00e9visualisez les pages en pr\u00e9-sortie (en relecture & valid\u00e9es) avant leur mise en ligne." }
};
function useSign() {const { lang } = useNav();return SIGN[lang] || SIGN.en;}

/* ============================================================
   AUTH MODE — secure email + password sign-in.
   Sign-in is by EMAIL + PASSWORD. There is no account list and no password is
   ever shown: the visitor types their own credentials, exactly as they would on
   the live site.
     · LIVE  (window.__VITRINE_API__ set): POST /api/auth/login verifies the
       password against the PBKDF2 hash in D1 and sets an HttpOnly session cookie.
       Nothing sensitive touches the browser.
     · LOCAL (prototype, no API): credentials are checked against the in-memory
       store so the demo still works offline — but the UI never reveals which
       emails exist or what any password is (one generic error for any failure).
   ============================================================ */

/* verify email + password locally without leaking which part was wrong */
function verifyLocalCredentials(users, email, password) {
  const e = String(email || "").trim().toLowerCase();
  const p = String(password || "");
  const u = (users || []).find((x) => String(x.email || "").trim().toLowerCase() === e);
  if (u && p && String(u.pass) === p) return u; // constant response shape whether email exists or not
  return null;
}

/* compact name diminutive — first + last initial → "CR". Single source of truth for
   BOTH the avatar glyph and the chip label, so they always agree. */
function initialsOf(u) {
  if (!u) return "?";
  const first = String(u.first || "").trim();
  const last = String(u.last || "").trim();
  if (first || last) {
    const a = first[0] || "";
    const b = last[0] || first.split(/\s+/)[1]?.[0] || "";
    return (a + b || first[0] || "?").toUpperCase();
  }
  const parts = String(u.name || "?").trim().split(/\s+/);
  const a = (parts[0] || "?")[0] || "?";
  const b = parts.length > 1 ? parts[parts.length - 1][0] || "" : "";
  return (a + b).toUpperCase();
}
/* the full display name, derived from first + last (falls back to stored name) */
function fullNameOf(u) {
  if (!u) return "";
  const fl = [u.first, u.last].map((x) => String(x || "").trim()).filter(Boolean).join(" ");
  return fl || u.name || "";
}

/* ---------- account settings (available to every signed-in user) ---------- */
function AccountSettingsModal({ user, onClose }) {
  const { update } = useStore();
  const s = useSign();
  // seed last name from the stored value, or split it off the legacy full name
  const seedLast = user.last || (user.name && user.first ? String(user.name).replace(user.first, "").trim() : "") || "";
  const [u, setU] = uSau({ first: user.first || "", last: seedLast, email: user.email || "", company: user.company || "", title: user.title || "" });
  const set = (k, v) => setU((p) => ({ ...p, [k]: v }));
  // live preview object so the avatar/initials update as you type
  const preview = { ...user, first: u.first, last: u.last };
  const save = () => {
    update((d) => {const x = (d.users || []).find((z) => z.id === user.id);if (x) {
        x.first = u.first.trim();
        x.last = u.last.trim();
        x.name = fullNameOf({ first: u.first, last: u.last }) || x.name;
        x.email = u.email;x.company = u.company;x.title = u.title;
      }});
    onClose();
  };
  return (
    <Modal title={s.account} onClose={onClose}
    footer={<><button className="btn ghost" onClick={onClose}>Cancel</button><button className="btn accent" onClick={save}><Icon name="save" size={16} /> Save</button></>}>
      <div className="row gap-8" style={{ alignItems: "center", marginBottom: 12 }}>
        <Avatar user={preview} size={42} />
        <div><div className="mono dim" style={{ fontSize: 11, letterSpacing: ".1em" }}>{fullNameOf(preview) || "\u2014"}</div><div className="mono" style={{ fontSize: 13 }}>{initialsOf(preview)}</div></div>
        <span className="grow" /><RoleBadge role={user.role} />
      </div>
      <div className="field-row">
        <div><label>First name</label><input value={u.first} onChange={(e) => set("first", e.target.value)} placeholder="Cannelle" /></div>
        <div><label>Last name</label><input value={u.last} onChange={(e) => set("last", e.target.value)} placeholder="Richter" /></div>
      </div>
      <div><label>Email</label><input value={u.email} onChange={(e) => set("email", e.target.value)} placeholder="you@domain.com" /></div>
      <div className="field-row">
        <div><label>Company</label><input value={u.company} onChange={(e) => set("company", e.target.value)} placeholder="Studio / org" /></div>
        <div><label>Function</label><input value={u.title} onChange={(e) => set("title", e.target.value)} placeholder="Role / title" /></div>
      </div>
    </Modal>);

}

/* ---------- small role badge ---------- */
function RoleBadge({ role, size = "sm" }) {
  const m = roleMeta(role);
  return (
    <span className={"rolebadge " + size} style={{ "--rc": m.color }}>
      <span className="rb-dot" />{m.label}
    </span>);

}

/* ---------- avatar: coloured initials (first + last, e.g. CR) ----------
   The circle is tinted by the person's ROLE (so colours map to roles everywhere);
   falls back to a stored colour for role-less subjects (e.g. anonymous feedback). */
function Avatar({ user, size = 30 }) {
  if (!user) return null;
  const init = initialsOf(user);
  const bg = user.role && roleMeta(user.role).color || user.color || "#211e1a";
  return (
    <span className="avatar" style={{ width: size, height: size, background: bg, fontSize: size * (init.length > 1 ? 0.38 : 0.44) }}>{init}</span>);

}

/* the ROLE's initial, e.g. Admin → “A” — shown inside the role-coloured circle */
function roleInitialOf(role) {const m = roleMeta(role);return (m.label || "?").trim()[0].toUpperCase();}

/* ---------- role avatar: the role initial (A/E/R/P/T/G) in the role colour ---------- */
function RoleAvatar({ role, size = 26 }) {
  const m = roleMeta(role);
  return <span className="avatar role-av" title={m.label} style={{ width: size, height: size, background: m.color, fontSize: size * 0.46 }}>{roleInitialOf(role)}</span>;
}

/* ---------- identity tag: role circle + the person's initials, tinted by role.
   ONE consistent identity form — used in the top-bar chip and the board pill. ---------- */
function IdentityTag({ user, size = 26 }) {
  if (!user) return null;
  const m = roleMeta(user.role);
  return (
    <span className="id-tag" style={{ "--rc": m.color }} title={`${m.label} · ${fullNameOf(user) || user.name || ""}`}>
      <RoleAvatar role={user.role} size={size} />
      <span className="id-tag-init">{initialsOf(user)}</span>
    </span>);

}

/* ===================== LOGIN POPOVER ===================== */
function LoginPopover({ onClose, dark }) {
  const { db, update } = useStore();
  const { login, lang } = useNav();
  const fr = lang === "fr";
  const s = useSign();
  const [email, setEmail] = uSau("");
  const [pw, setPw] = uSau("");
  const [stay, setStay] = uSau(true);
  const [err, setErr] = uSau("");
  const [busy, setBusy] = uSau(false);
  const emailRef = uRau(null);

  uEau(() => {const k = (e) => e.key === "Escape" && onClose();window.addEventListener("keydown", k);return () => window.removeEventListener("keydown", k);}, []);
  uEau(() => {if (emailRef.current) emailRef.current.focus();}, []);

  const enter = async () => {
    if (busy) return;
    setErr("");
    if (!email.trim() || !pw) {setErr(s.badCreds);return;}
    const api = window.VitrineAPI;
    // LIVE: verify against D1 through the API (PBKDF2 + HttpOnly cookie).
    if (api && api.isRemote()) {
      setBusy(true);
      try {
        const res = await api.login(email.trim(), pw, stay);
        const user = res && res.user;
        if (!user) throw new Error("no user");
        // merge the returned identity into the store so the app resolves the session
        update((d) => {
          d.users = d.users || [];
          const i = d.users.findIndex((u) => u.id === user.id);
          const shaped = { grants: [], editGrants: [], ...user };
          if (i >= 0) d.users[i] = { ...d.users[i], ...shaped };else d.users.push(shaped);
        });
        login(user, stay);
        onClose();
      } catch (e) {
        setErr(s.badCreds);
      } finally {setBusy(false);}
      return;
    }
    // LOCAL prototype: check the in-memory store without revealing accounts or passwords.
    const u = verifyLocalCredentials(db.users, email, pw);
    if (!u) {setErr(s.badCreds);return;}
    login(u, stay);
    onClose();
  };

  return (
    <>
      <div className="id-scrim" onClick={onClose} />
      <div className="login-pop" onClick={(e) => e.stopPropagation()}>
        <div className="lp-head">
          <div>
            <div className="lp-kicker">{s.signin.toUpperCase()}</div>
            <h3 className="lp-title">{s.who}</h3>
          </div>
          <button className="iconbtn" onClick={onClose}><Icon name="close" size={16} /></button>
        </div>
        <p className="lp-sub">{s.chooseSub}</p>
        <div className="lp-auth" style={{ marginTop: 4 }}>
          <label className="lp-lbl">{s.emailLabel}</label>
          <input ref={emailRef} type="email" autoComplete="username" value={email} placeholder="you@domain.com"
          onChange={(e) => {setEmail(e.target.value);setErr("");}}
          onKeyDown={(e) => e.key === "Enter" && enter()} />
          <label className="lp-lbl" style={{ marginTop: 12 }}>{s.pwLabel}</label>
          <input type="password" autoComplete="current-password" value={pw} placeholder={s.pwLabel.toLowerCase()}
          onChange={(e) => {setPw(e.target.value);setErr("");}}
          onKeyDown={(e) => e.key === "Enter" && enter()} />
          {err && <div className="lp-err">{err}</div>}
          <button className="btn accent" disabled={busy} onClick={enter}
          style={{ width: "100%", justifyContent: "center", marginTop: 14 }}>
            <Icon name={busy ? "globe" : "arrow"} size={16} /> {busy ? s.signingIn : s.enter}
          </button>
          <label className="lp-stay"><input type="checkbox" checked={stay} onChange={(e) => setStay(e.target.checked)} /> {s.stay}</label>
          {!(window.VitrineAPI && window.VitrineAPI.isRemote()) &&
          <button type="button" className="lp-demo-hint" onClick={() => {setEmail("hello@cannellerichter.fr");setPw("hello");setErr("");}}>
              {fr ? "Démo — cliquez pour remplir : " : "Demo — click to fill: "}<span className="mono">hello@cannellerichter.fr · hello</span>
            </button>
          }
        </div>
      </div>
    </>);

}

/* ===================== IDENTITY CONTROL (top bar) ===================== */
function IdentityControl({ dark }) {
  const { db } = useStore();
  const nav = useNav();
  const { go, session, role, isAdmin, logout, setEdit, setReview, setPublish, setTmode, edit, reviewMode, publishMode, testerMode, route, lang } = nav;
  const ed = window.useEdit ? window.useEdit() : {};
  const s = useSign();
  const [menu, setMenu] = uSau(false);
  const [loginOpen, setLoginOpen] = uSau(false);
  const [manage, setManage] = uSau(false);
  const [acct, setAcct] = uSau(false);
  const home = db.profile.defaultRoute;
  const grants = userGrantsRanked(db, session).filter((g) => g.kind !== "section");

  if (!session) {
    return (
      <div className="id-wrap">
        <button className={"id-signin" + (dark ? " on-dark" : "")} onClick={() => setLoginOpen(true)} title={s.signin}>
          <Icon name="user" size={16} /> <span className="id-signin-lbl">{s.signin}</span>
        </button>
        {loginOpen && <LoginPopover onClose={() => setLoginOpen(false)} dark={dark} />}
      </div>);

  }

  const editActive = (isAdmin || role === "editor") && edit;
  const inMode = editActive || reviewMode || publishMode || testerMode; // any focused collaborator mode is active
  const close = (fn) => {setMenu(false);fn && fn();};
  const enterAdmin = () => close(() => go("/board"));
  // jump straight into editing the CURRENT page (blog → its editor, domain → its panel)
  const editHere = () => close(() => {setEdit(true);if (route.path === "/board" || route.path === "/admin") go(home);});
  const enterEdit = () => close(() => {setEdit(true);go(home);});
  const closeEdit = () => close(() => {setEdit(false);go(home);});
  const enterReview = () => close(() => {setReview(true);go(home);});
  const closeReview = () => close(() => {setReview(false);go(home);});
  const enterPublish = () => close(() => {setPublish(true);go(home);});
  const closePublish = () => close(() => {setPublish(false);go(home);});
  const enterTester = () => close(() => {setTmode(true);go(home);});
  const closeTester = () => close(() => {setTmode(false);go(home);});
  const toBoard = () => close(() => go("/board"));
  const openSettings = () => close(() => {setEdit(true);if (ed.setPanelMode) ed.setPanelMode("global");if (ed.setPanelOpen) ed.setPanelOpen(true);go(home);});
  const openManage = () => {setMenu(false);setManage(true);};
  const doLogout = () => close(() => {logout();go(home);});
  const openGrant = (g) => close(() => go(g.route));

  const grantIcon = (k) => k === "video" ? "play" : k === "secret" ? "lock" : k === "section" ? "compass" : "edit";
  const fr = lang === "fr";
  // shared content shown as the SECTIONS it lives in (like the public section tabs)
  const sharedGroups = (() => {
    const groups = [];
    grants.forEach((g) => {
      const key = g.sectionId || "other";
      let grp = groups.find((x) => x.key === key);
      if (!grp) {
        const sec = (db.sections || []).find((x) => x.id === g.sectionId);
        grp = { key, label: sec ? secLabel(sec, lang) : g.sectionLabel || "Other", logo: sec ? sec.logo : g.logo || null, kind: sec ? sec.kind : g.sectionKind, items: [] };
        groups.push(grp);
      }
      grp.items.push(g);
    });
    return groups;
  })();
  const SharedBlock = () =>
  <div className="idm-group">
      <div className="idm-cap">{s.shared}</div>
      {sharedGroups.length ? <>
        {sharedGroups.map((grp) =>
      <button key={grp.key} className="idm-item grant" onClick={() => close(() => go("/shared/" + grp.key))}>
            <Icon name={window.iconForKind ? window.iconForKind(grp.kind || "blog") : "edit"} size={15} />
            <span className="idm-grant-l">{grp.label}</span>
            <span className="grow" />
            <span className="dim mono" style={{ fontSize: 11 }}>{grp.items.length}</span>
          </button>
      )}
        <button className="idm-item seeall" onClick={() => close(() => go("/shared"))}>
          <Icon name="compass" size={15} /><span className="idm-grant-l">{s.seeAll}</span><span className="grow" /><Icon name="right" size={14} />
        </button>
      </> : <div className="idm-note">{s.noShared}</div>}
    </div>;


  return (
    <div className="id-wrap">
      <button className={"id-chip" + (dark ? " on-dark" : "") + (inMode ? " in-mode" : "")} onClick={() => setMenu((v) => !v)} title={session.name}>
        <IdentityTag user={session} size={26} />
        <Icon name="down" size={15} />
      </button>
      {menu &&
      <>
          <div className="id-scrim" onClick={() => setMenu(false)} />
          <div className="id-menu">
            <div className="idm-head">
              <RoleAvatar role={role} size={40} />
              <div className="idm-id">
                <div className="idm-name">{session.name}</div>
                <RoleBadge role={role} />
              </div>
            </div>
            <p className="idm-blurb">{roleMeta(role).blurb}</p>

            {isAdmin &&
          <>
                {!editActive ?
            <>
                      <div className="idm-group">
                        <button className="idm-item" onClick={editHere}><Icon name="edit" size={16} /> {s.editMode}</button>
                      </div>
                      <div className="idm-group">
                        <button className="idm-item" onClick={enterAdmin}><Icon name="chart" size={16} /> {s.adminMode}</button>
                      </div>
                    </> :
            <div className="idm-group">
                      <button className="idm-item" onClick={openSettings}><Icon name="edit" size={16} /> {s.settings}</button>
                      <button className="idm-item" onClick={openManage}><Icon name="user" size={16} /> {s.manage}</button>
                      <button className="idm-item" onClick={toBoard}><Icon name="chart" size={16} /> {s.board}</button>
                      <button className="idm-item danger-item" onClick={closeEdit}><Icon name="close" size={16} /> {s.closeAdmin}</button>
                    </div>}
              </>
          }
            {role === "editor" &&
          <div className="idm-group">
                {!edit ?
            <button className="idm-item" onClick={enterEdit}><Icon name="edit" size={16} /> {s.editMode}</button> :
            <button className="idm-item danger-item" onClick={closeEdit}><Icon name="close" size={16} /> {s.closeEdit}</button>}
                <div className="idm-note">{s.editNote}</div>
              </div>
          }
            {role === "reviewer" &&
          <div className="idm-group">
                {!reviewMode ?
            <button className="idm-item" onClick={enterReview}><Icon name="check" size={16} /> {s.reviewMode}</button> :
            <button className="idm-item danger-item" onClick={closeReview}><Icon name="close" size={16} /> {s.closeReview}</button>}
                <div className="idm-note">{s.reviewNote}</div>
              </div>
          }
            {role === "publisher" &&
          <div className="idm-group">
                {!publishMode ?
            <button className="idm-item" onClick={enterPublish}><Icon name="check" size={16} /> {s.publishMode}</button> :
            <button className="idm-item danger-item" onClick={closePublish}><Icon name="close" size={16} /> {s.closePublish}</button>}
                <div className="idm-note">{s.publishNote}</div>
              </div>
          }
            {role === "tester" &&
          <div className="idm-group">
                {!testerMode ?
            <button className="idm-item" onClick={enterTester}><Icon name="play" size={16} /> {s.testerMode}</button> :
            <button className="idm-item danger-item" onClick={closeTester}><Icon name="close" size={16} /> {s.closeTester}</button>}
                <div className="idm-note">{s.testerNote}</div>
              </div>
          }
            {(role === "reviewer" || role === "guest" || role === "editor" || role === "tester" || role === "publisher") && !inMode && <SharedBlock />}

            <button className="idm-item" onClick={() => {setMenu(false);setAcct(true);}}><Icon name="user" size={16} /> {s.account}</button>
            <button className="idm-item logout" onClick={doLogout}><Icon name="lock" size={16} /> {s.logout}</button>
          </div>
        </>
      }
      {manage && window.ManageAccessModal && <window.ManageAccessModal onClose={() => setManage(false)} />}
      {acct && <AccountSettingsModal user={session} onClose={() => setAcct(false)} />}
    </div>);

}

/* ===================== REVIEW / GUEST FEEDBACK DOCK ===================== */
function pageSubject(db, path) {
  const segs = path.split("/").filter(Boolean);
  const secByKind = (kind) => (db.sections || []).find((s) => s.kind === kind);
  if (segs.length === 2) {
    const c = (db.content || []).find((x) => x.ref === segs[1]);
    if (c) {const sec = secByKind(c.type);const secL = sec ? sec.label : c.type === "video" ? "Videos" : "Blog";const w = wholeLang(c, "en");const t = w.title || c.ref;return { ref: c.id, label: t, crumb: `${secL}/${t}` };}
    const sec = (db.sections || []).find((s) => s.route === "/" + segs[0]);
    if (sec) return { ref: sec.id, label: sec.label, crumb: sec.label };
  }
  if (segs[0] === "other" && segs[1]) {
    const p = (db.otherPages || []).find((x) => x.route === path);
    if (p) {const w = pageWholeLang(p, "en");const t = w.label || p.id;return { ref: p.id, label: t, crumb: `Other/${t}` };}
  }
  const sec = (db.sections || []).find((s) => s.route === path);
  if (sec) return { ref: sec.id, label: sec.label, crumb: sec.label };
  const dom = (db.domains || []).find((d) => d.route === path);
  if (dom) return { ref: dom.id, label: dom.label, crumb: dom.label };
  if (path === "/about") return { ref: "about", label: "About me", crumb: "About me" };
  if (path === "/shared") return { ref: "shared", label: "Shared content", crumb: "Shared content" };
  if (path === "/" || path === "") {const h = (db.domains || [])[0];return { ref: h ? h.id : "home", label: h ? h.label : "Home", crumb: h ? h.label : "Home" };}
  return { ref: "page", label: "This page", crumb: "This page" };
}

function ReviewFeedbackDock() {
  const { db, update } = useStore();
  const { route, session, role, lang } = useNav();
  const [open, setOpen] = uSau(false);
  const [text, setText] = uSau("");
  const [sent, setSent] = uSau(false);
  const subj = pageSubject(db, route.path);
  const m = roleMeta(role);
  const fr = lang === "fr";

  const send = () => {
    if (!text.trim()) return;
    update((d) => {
      d.contentFeedback = d.contentFeedback || [];
      d.contentFeedback.unshift({
        id: uid("cf"), target: subj.ref, targetLabel: subj.label, lang,
        by: session.name, byColor: session.color, role, date: new Date().toISOString().slice(0, 10), text: text.trim()
      });
      d.notifications.unshift({ id: uid("n"), tile: "t3", time: new Date().toISOString().slice(0, 16).replace("T", " "), text: `${m.label} feedback from ${session.first} on “${subj.label}”.` });
    });
    setSent(true);setText("");
    setTimeout(() => {setSent(false);setOpen(false);}, 1500);
  };

  return (
    <div className={"rf-dock" + (open ? " open" : "")} style={{ "--rc": m.color }}>
      {open ?
      <div className="rf-card">
          <div className="rf-head">
            <span className="rf-title"><Icon name="msg" size={15} /> Feedback</span>
            {session && <Avatar user={session} size={22} />}
            <RoleBadge role={role} />
            <span className="grow" />
            <button className="iconbtn sm" onClick={() => setOpen(false)}><Icon name="close" size={15} /></button>
          </div>
          <div className="rf-subj">{fr ? "Sur" : "On"} <b className="mono">{subj.crumb}</b></div>
          {sent ?
        <div className="rf-sent"><Icon name="check" size={18} /> {fr ? "Envoyé — merci !" : "Sent — thank you!"}</div> :

        <>
              <textarea className="rf-text" rows={3} autoFocus value={text} onChange={(e) => setText(e.target.value)}
          placeholder={role === "reviewer" ? fr ? "Une correction, une question, quelque chose à régler avant publication…" : "Note a change, a question, anything to fix before publishing…" : fr ? "Dites à Cannelle ce que vous en pensez…" : "Tell Cannelle what you think…"} />
              <button className="rf-send" disabled={!text.trim()} onClick={send}><Icon name="arrow" size={16} /> {fr ? "Envoyer le feedback" : "Send feedback"}</button>
            </>
        }
        </div> :

      <button className="rf-fab" onClick={() => setOpen(true)} title={fr ? "Laisser un feedback" : "Leave feedback"}>
          <Icon name="msg" size={18} /> <span>Feedback</span>
        </button>
      }
    </div>);

}

Object.assign(window, { RoleBadge, Avatar, RoleAvatar, IdentityTag, roleInitialOf, LoginPopover, IdentityControl, ReviewFeedbackDock, pageSubject, AccountSettingsModal, initialsOf, fullNameOf, verifyLocalCredentials });