// ============================================================
// NOMERUS · LE BRIEF (écran app /news, connecté)
// ============================================================
// Journal des marchés rédigé par IA (pipeline Make → news-collect →
// news-publish, 2-3 éditions/jour). Lecture seule via window.nomerusNews —
// la RLS n'expose que les posts publiés.
//
// Direction visuelle : « la salle de lecture du terminal » — un
// broadsheet financier (serif Newsreader, manchette, filets, lettrine,
// éditions Matin/Mi-séance/Clôture, marque de fin ∎) qui contraste
// volontairement avec le mono/Inter du reste du Quant Terminal, tout en
// suivant les tokens window.QT (thèmes DARK/TAMISÉ/TERMINAL mutables).

// ── Constantes & helpers ──────────────────────────────────────

const BRIEF_SERIF = "'Newsreader', 'Iowan Old Style', Georgia, serif";

const NEWS_CATEGORIES = {
  forex:   { label: "FOREX",   color: "#7C9EFF" },
  indices: { label: "INDICES", color: "#FFB454" },
  crypto:  { label: "CRYPTO",  color: "#A78BFA" },
  macro:   { label: "MACRO",   color: "#5BD99A" },
};

const newsCat = (c) => NEWS_CATEGORIES[c] || NEWS_CATEGORIES.macro;

// Encre : T.text (hex) décliné en alpha, pour une hiérarchie de gris
// typographique qui suit le thème actif.
const briefInk = (alpha) => {
  let h = String(window.QT.text || "#E5EAFF").replace("#", "");
  if (h.length === 3) h = h.split("").map((c) => c + c).join("");
  const n = parseInt(h, 16);
  return `rgba(${(n >> 16) & 255}, ${(n >> 8) & 255}, ${n & 255}, ${alpha})`;
};

const newsDate = (iso, withTime) => {
  try {
    const d = new Date(iso);
    const opts = withTime
      ? { day: "numeric", month: "long", year: "numeric", hour: "2-digit", minute: "2-digit" }
      : { day: "numeric", month: "long", year: "numeric" };
    return new Intl.DateTimeFormat("fr-CH", opts).format(d);
  } catch (e) { return ""; }
};

const newsDay = (iso) => {
  try {
    return new Intl.DateTimeFormat("fr-CH", { weekday: "long", day: "numeric", month: "long", year: "numeric" })
      .format(new Date(iso));
  } catch (e) { return ""; }
};

const newsTime = (iso) => {
  try {
    return new Intl.DateTimeFormat("fr-CH", { hour: "2-digit", minute: "2-digit" }).format(new Date(iso));
  } catch (e) { return ""; }
};

// Trois parutions par jour de séance → nom d'édition façon journal.
const newsEdition = (iso) => {
  try {
    const h = new Date(iso).getHours();
    if (h < 12) return "ÉDITION MATIN";
    if (h < 19) return "ÉDITION MI-SÉANCE";
    return "ÉDITION CLÔTURE";
  } catch (e) { return "ÉDITION"; }
};

const newsReadMins = (md) => {
  const words = String(md || "").replace(/[#>*`_-]/g, " ").split(/\s+/).filter(Boolean).length;
  return Math.max(1, Math.round(words / 190));
};

// ── Markdown léger → blocs ────────────────────────────────────
// Même philosophie que le chat du Coach : aucun HTML injecté. Supporte
// **gras**, *italique*, listes à puces, titres `## `, citations `> `.

const newsInline = (text, keyBase) => {
  const T = window.QT;
  const out = [];
  String(text).split(/\*\*(.+?)\*\*/g).forEach((seg, i) => {
    if (i % 2 === 1) {
      out.push(<strong key={`${keyBase}-b${i}`} style={{ color: T.text, fontWeight: 700 }}>{seg}</strong>);
      return;
    }
    seg.split(/\*([^*]+)\*/g).forEach((s2, j) => {
      if (j % 2 === 1) out.push(<em key={`${keyBase}-i${i}-${j}`} style={{ fontStyle: "italic" }}>{s2}</em>);
      else if (s2) out.push(<React.Fragment key={`${keyBase}-t${i}-${j}`}>{s2}</React.Fragment>);
    });
  });
  return out;
};

const newsParseMd = (md) => {
  const blocks = [];
  let list = null;
  String(md || "").split("\n").forEach((raw) => {
    const t = raw.trim();
    if (/^[-•*]\s+/.test(t)) {
      if (!list) { list = []; blocks.push({ type: "list", items: list }); }
      list.push(t.replace(/^[-•*]\s+/, ""));
      return;
    }
    list = null;
    if (!t) return;
    const h = t.match(/^#{2,4}\s+(.*)$/);
    if (h) { blocks.push({ type: "h", text: h[1].replace(/#+\s*$/, "").trim() }); return; }
    const q = t.match(/^>\s?(.*)$/);
    if (q) {
      const prev = blocks[blocks.length - 1];
      if (prev && prev.type === "q") prev.text += " " + q[1];
      else blocks.push({ type: "q", text: q[1] });
      return;
    }
    blocks.push({ type: "p", text: t });
  });
  // « ## L'essentiel » + sa liste → encadré dédié en tête d'article.
  const idx = blocks.findIndex((b) => b.type === "h" && /essentiel/i.test(b.text));
  if (idx !== -1 && blocks[idx + 1] && blocks[idx + 1].type === "list") {
    const items = blocks[idx + 1].items;
    blocks.splice(idx, 2, { type: "essential", items });
  }
  return blocks;
};

// ── Atomes typographiques ─────────────────────────────────────

const NewsChip = ({ category }) => {
  const T = window.QT;
  const c = newsCat(category);
  return (
    <span style={{
      fontFamily: T.mono, fontSize: 9, letterSpacing: 1.5, fontWeight: 600,
      padding: "3px 8px", borderRadius: 3,
      color: c.color, background: `${c.color}1E`, border: `1px solid ${c.color}3D`,
    }}>{c.label}</span>
  );
};

// Filet typographique — l'ossature du journal.
const NewsRule = ({ weight = 1, gap = 0 }) => {
  const T = window.QT;
  return <div style={{
    borderTop: `${weight}px solid ${weight > 1 ? T.borderStrong : T.border}`,
    margin: `${gap}px 0`,
  }}/>;
};

const NewsKicker = ({ children, color }) => {
  const T = window.QT;
  return (
    <span style={{ fontFamily: T.mono, fontSize: 9, letterSpacing: 2, color: color || T.textMute, whiteSpace: "nowrap" }}>
      {children}
    </span>
  );
};

const NewsEndMark = () => {
  const T = window.QT;
  return (
    <div style={{ display: "flex", alignItems: "center", gap: 14, margin: "6px 0 30px" }}>
      <div style={{ flex: 1, borderTop: `1px solid ${T.border}` }}/>
      <span style={{ fontFamily: T.mono, fontSize: 11, color: T.indigo }}>∎</span>
      <div style={{ flex: 1, borderTop: `1px solid ${T.border}` }}/>
    </div>
  );
};

const NewsDisclaimer = () => {
  const T = window.QT;
  return (
    <div style={{
      marginTop: 8, padding: "14px 16px", borderRadius: 4,
      border: `1px solid ${T.border}`, borderLeft: `2px solid ${T.amber}`, background: T.panel,
    }}>
      <div style={{ fontFamily: T.mono, fontSize: 8.5, letterSpacing: 2, color: T.textMute, marginBottom: 8 }}>
        // MENTION
      </div>
      <div style={{ fontFamily: T.sans, fontSize: 12, color: T.textMute, lineHeight: 1.6 }}>
        Le Brief est rédigé automatiquement par une IA à partir de sources publiques citées,
        puis publié sans relecture humaine systématique. Il peut contenir des imprécisions.
        Ce contenu est purement informatif : ce n'est <strong style={{ color: T.textDim }}>ni un conseil en
        investissement, ni une recommandation</strong> d'achat ou de vente. Fais toujours tes propres recherches.
      </div>
    </div>
  );
};

// ── Corps d'article ───────────────────────────────────────────

const NewsEssential = ({ items }) => {
  const T = window.QT;
  return (
    <div style={{
      margin: "0 0 26px", padding: "16px 18px 14px", borderRadius: 4,
      background: T.panel, border: `1px solid ${T.border}`, borderLeft: `2px solid ${T.indigo}`,
    }}>
      <div style={{ fontFamily: T.mono, fontSize: 9, letterSpacing: 2.5, color: T.indigo, marginBottom: 12 }}>
        L'ESSENTIEL
      </div>
      <div style={{ display: "flex", flexDirection: "column", gap: 9 }}>
        {items.map((li, i) => (
          <div key={i} style={{ display: "flex", gap: 10 }}>
            <span style={{ fontFamily: T.mono, fontSize: 11, color: T.indigo, lineHeight: 1.5, flexShrink: 0 }}>—</span>
            <span style={{ fontFamily: BRIEF_SERIF, fontSize: 15.5, color: briefInk(0.88), lineHeight: 1.55 }}>
              {newsInline(li, `ess${i}`)}
            </span>
          </div>
        ))}
      </div>
    </div>
  );
};

const NewsBody = ({ md }) => {
  const T = window.QT;
  const blocks = newsParseMd(md);
  let sectionNo = 0;
  let firstP = true;
  // Justification broadsheet sur desktop uniquement : sur colonne étroite
  // elle crée des « rivières » de blancs illisibles.
  const justify = typeof window !== "undefined" && window.innerWidth > 640;
  return (
    <div lang="fr">
      {blocks.map((b, i) => {
        if (b.type === "essential") return <NewsEssential key={i} items={b.items}/>;

        if (b.type === "h") {
          sectionNo += 1;
          return (
            <div key={i} style={{ margin: "30px 0 14px", display: "flex", alignItems: "baseline", gap: 12 }}>
              <span style={{ fontFamily: T.mono, fontSize: 10, color: T.indigo, letterSpacing: 1 }}>
                {String(sectionNo).padStart(2, "0")}
              </span>
              <h2 style={{
                margin: 0, fontFamily: BRIEF_SERIF, fontSize: 21, fontWeight: 600,
                color: T.text, letterSpacing: -0.3, lineHeight: 1.25,
              }}>{newsInline(b.text, `h${i}`)}</h2>
            </div>
          );
        }

        if (b.type === "q") {
          return (
            <div key={i} style={{
              margin: "28px 6px", padding: "18px 12px", textAlign: "center",
              borderTop: `1px solid ${T.borderStrong}`, borderBottom: `1px solid ${T.borderStrong}`,
            }}>
              <div style={{ fontFamily: T.mono, fontSize: 10, color: T.indigo, marginBottom: 8 }}>◆</div>
              <div style={{
                fontFamily: BRIEF_SERIF, fontStyle: "italic", fontSize: 19.5,
                color: briefInk(0.92), lineHeight: 1.5, maxWidth: 520, margin: "0 auto",
              }}>{newsInline(b.text, `q${i}`)}</div>
            </div>
          );
        }

        if (b.type === "list") {
          return (
            <div key={i} style={{ margin: "0 0 20px 6px", display: "flex", flexDirection: "column", gap: 8 }}>
              {b.items.map((li, j) => (
                <div key={j} style={{ display: "flex", gap: 10 }}>
                  <span style={{ fontFamily: T.mono, fontSize: 11, color: T.indigo, lineHeight: 1.7, flexShrink: 0 }}>—</span>
                  <span style={{ fontFamily: BRIEF_SERIF, fontSize: 16.5, color: briefInk(0.84), lineHeight: 1.7 }}>
                    {newsInline(li, `li${i}-${j}`)}
                  </span>
                </div>
              ))}
            </div>
          );
        }

        const drop = firstP;
        firstP = false;
        return (
          <p key={i} className={drop ? "brief-dropcap" : undefined} style={{
            fontFamily: BRIEF_SERIF, fontSize: 16.5, color: briefInk(0.84),
            lineHeight: 1.8, margin: "0 0 18px", textAlign: justify ? "justify" : "left",
            hyphens: "auto", WebkitHyphens: "auto",
          }}>
            {newsInline(b.text, `p${i}`)}
          </p>
        );
      })}
    </div>
  );
};

// Défense en profondeur : le serveur (news-publish) ne stocke que des URLs
// http(s), mais on revalide le protocole ici pour qu'un href javascript:/data:
// ne puisse jamais devenir cliquable, quelle que soit l'origine des données.
const newsSafeHref = (url) => {
  try {
    const u = new URL(String(url));
    return (u.protocol === "http:" || u.protocol === "https:") ? u.href : null;
  } catch (_) { return null; }
};

const NewsSources = ({ sources }) => {
  const T = window.QT;
  if (!Array.isArray(sources) || sources.length === 0) return null;
  return (
    <div style={{ margin: "0 0 26px" }}>
      <div style={{ fontFamily: T.mono, fontSize: 9, color: T.textMute, letterSpacing: 2, marginBottom: 12 }}>
        // SOURCES & RÉFÉRENCES
      </div>
      <div style={{ display: "flex", flexDirection: "column", gap: 9 }}>
        {sources.map((s, i) => {
          const href = newsSafeHref(s.url);
          return (
          <a key={i} href={href || undefined} target={href ? "_blank" : undefined} rel="noopener noreferrer" className="brief-src" style={{
            display: "flex", gap: 10, alignItems: "baseline",
            color: T.textDim, textDecoration: "none",
          }}>
            <span style={{ fontFamily: T.mono, fontSize: 9.5, color: T.indigo, flexShrink: 0 }}>
              [{String(i + 1).padStart(2, "0")}]
            </span>
            <span style={{ fontFamily: BRIEF_SERIF, fontSize: 14.5, lineHeight: 1.5 }}>
              {s.title}{" "}
              <span style={{ fontFamily: T.mono, fontSize: 9, color: T.textMute, letterSpacing: 1 }}>
                · {String(s.source || "").toUpperCase()} ↗
              </span>
            </span>
          </a>
          );
        })}
      </div>
    </div>
  );
};

// ── Vue article ───────────────────────────────────────────────

const NewsArticle = ({ go, slug }) => {
  const T = window.QT;
  const [state, setState] = React.useState({ loading: true, post: null, error: "" });

  React.useEffect(() => {
    let alive = true;
    setState({ loading: true, post: null, error: "" });
    window.nomerusNews.get(slug).then((res) => {
      if (!alive) return;
      if (res.ok) setState({ loading: false, post: res.post, error: "" });
      else setState({ loading: false, post: null, error: res.error });
    });
    return () => { alive = false; };
  }, [slug]);

  const p = state.post;
  return (
    <div style={{ maxWidth: 720, margin: "0 auto", padding: "26px 24px 60px", "--brief-accent": T.indigo }}>
      <button onClick={() => go && go("news")} className="qt-nav-btn" style={{
        background: "transparent", border: "none", cursor: "pointer", padding: 0,
        fontFamily: T.mono, fontSize: 10, color: T.indigo, letterSpacing: 1.5, marginBottom: 24,
      }}>← TOUTES LES ÉDITIONS</button>

      {state.loading && (
        <div style={{ fontFamily: T.mono, fontSize: 11, color: T.textMute, letterSpacing: 1.5, padding: "40px 0" }}>
          CHARGEMENT DE L'ÉDITION…
        </div>
      )}

      {!state.loading && !p && (
        <div style={{ padding: "40px 0" }}>
          <div style={{ fontFamily: BRIEF_SERIF, fontSize: 19, color: T.text, marginBottom: 12 }}>
            {state.error || "Cette édition est introuvable."}
          </div>
          <button onClick={() => go && go("news")} style={{
            background: "transparent", border: `1px solid ${T.borderStrong}`, borderRadius: 4,
            color: T.text, cursor: "pointer", padding: "8px 14px",
            fontFamily: T.mono, fontSize: 10, letterSpacing: 1.5,
          }}>VOIR LES DERNIÈRES ÉDITIONS</button>
        </div>
      )}

      {p && (
        <article>
          {/* Tête d'article : filet, kicker, manchette, chapeau */}
          <NewsRule weight={2}/>
          <div style={{
            display: "flex", alignItems: "center", justifyContent: "space-between",
            gap: 10, flexWrap: "wrap", padding: "10px 0 16px",
          }}>
            <div style={{ display: "flex", alignItems: "center", gap: 10 }}>
              <NewsChip category={p.category}/>
              <NewsKicker color={T.indigo}>{newsEdition(p.created_at)}</NewsKicker>
            </div>
            <NewsKicker>{newsDate(p.created_at, true).toUpperCase()}</NewsKicker>
          </div>

          <h1 style={{
            fontFamily: BRIEF_SERIF, fontSize: "clamp(28px, 4.5vw, 40px)", fontWeight: 600,
            color: T.text, letterSpacing: -1, lineHeight: 1.12, margin: "0 0 14px",
          }}>{p.title}</h1>

          {p.hook ? (
            <p style={{
              fontFamily: BRIEF_SERIF, fontStyle: "italic", fontSize: 18.5,
              color: briefInk(0.72), lineHeight: 1.5, margin: "0 0 20px",
            }}>{p.hook}</p>
          ) : <div style={{ height: 8 }}/>}

          {/* Barre de signature */}
          <div style={{
            display: "flex", alignItems: "center", justifyContent: "space-between", gap: 10, flexWrap: "wrap",
            padding: "10px 0", marginBottom: 26,
            borderTop: `1px solid ${T.border}`, borderBottom: `2px solid ${T.borderStrong}`,
          }}>
            <NewsKicker>PAR LE DESK NOMERUS · RÉDIGÉ PAR IA</NewsKicker>
            <NewsKicker color={T.indigo}>{newsReadMins(p.body_md)} MIN DE LECTURE</NewsKicker>
          </div>

          <NewsBody md={p.body_md}/>

          <NewsEndMark/>

          <NewsSources sources={p.sources}/>

          <div style={{ fontFamily: T.mono, fontSize: 8.5, color: T.textMute, letterSpacing: 1.5, lineHeight: 1.8, marginBottom: 10 }}>
            GÉNÉRÉ PAR {(p.model || "IA").toUpperCase()} · PUBLIÉ LE {newsDate(p.created_at, true).toUpperCase()}
          </div>
          <NewsDisclaimer/>
        </article>
      )}
    </div>
  );
};

// ── Vue kiosque (liste) ───────────────────────────────────────

const NewsMasthead = () => {
  const T = window.QT;
  return (
    <header style={{ marginBottom: 26 }}>
      <NewsRule weight={2}/>
      <div style={{
        display: "flex", justifyContent: "space-between", gap: 10, flexWrap: "wrap", padding: "8px 0",
      }}>
        <NewsKicker>NOMERUS — DESK MARCHÉS</NewsKicker>
        <NewsKicker>PARUTION LUN–VEN · JUSQU'À 3 ÉDITIONS/JOUR</NewsKicker>
      </div>
      <div style={{ textAlign: "center", padding: "10px 0 14px" }}>
        <div style={{
          fontFamily: BRIEF_SERIF, fontSize: "clamp(42px, 7vw, 58px)", fontWeight: 600,
          color: T.text, letterSpacing: -2, lineHeight: 1,
        }}>Le Brief</div>
        <div style={{
          fontFamily: BRIEF_SERIF, fontStyle: "italic", fontSize: 15,
          color: briefInk(0.62), marginTop: 10,
        }}>L'actualité des marchés, rédigée par IA — factuelle, sourcée, sans bruit.</div>
      </div>
      <NewsRule/>
      <div style={{
        display: "flex", alignItems: "center", justifyContent: "space-between",
        gap: 12, flexWrap: "wrap", padding: "9px 0",
      }}>
        <div style={{ display: "flex", alignItems: "center", gap: 16, flexWrap: "wrap" }}>
          {Object.keys(NEWS_CATEGORIES).map((k) => (
            <span key={k} style={{ display: "inline-flex", alignItems: "center", gap: 6 }}>
              <span style={{ width: 6, height: 6, borderRadius: 1, background: NEWS_CATEGORIES[k].color, display: "inline-block" }}/>
              <NewsKicker>{NEWS_CATEGORIES[k].label}</NewsKicker>
            </span>
          ))}
        </div>
        <NewsKicker color={T.textDim}>{newsDay(Date.now()).toUpperCase()}</NewsKicker>
      </div>
      <NewsRule weight={2}/>
    </header>
  );
};

const NewsFeaturedCard = ({ post, go }) => {
  const T = window.QT;
  return (
    <section style={{ marginBottom: 34 }}>
      <div style={{ display: "flex", justifyContent: "space-between", gap: 10, flexWrap: "wrap", marginBottom: 14 }}>
        <NewsKicker color={T.indigo}>// À LA UNE</NewsKicker>
        <NewsKicker>{newsEdition(post.created_at)} · {newsTime(post.created_at)}</NewsKicker>
      </div>
      <button onClick={() => go && go("news", { id: post.slug })} className="brief-item" style={{
        display: "block", width: "100%", textAlign: "left", cursor: "pointer",
        background: "transparent", border: "none", padding: 0,
      }}>
        <div className="brief-hl" style={{
          fontFamily: BRIEF_SERIF, fontSize: "clamp(25px, 3.6vw, 34px)", fontWeight: 600,
          color: T.text, letterSpacing: -0.8, lineHeight: 1.15, marginBottom: 12,
        }}>{post.title}</div>
        {post.hook && (
          <div style={{
            fontFamily: BRIEF_SERIF, fontStyle: "italic", fontSize: 17,
            color: briefInk(0.7), lineHeight: 1.55, maxWidth: 680, marginBottom: 14,
          }}>{post.hook}</div>
        )}
        <div style={{ display: "flex", alignItems: "center", gap: 12, flexWrap: "wrap" }}>
          <NewsChip category={post.category}/>
          <span style={{ fontFamily: T.mono, fontSize: 9.5, color: T.indigo, letterSpacing: 1.5 }}>
            LIRE L'ARTICLE →
          </span>
        </div>
      </button>
    </section>
  );
};

const NewsListItem = ({ post, go }) => {
  const T = window.QT;
  return (
    <button onClick={() => go && go("news", { id: post.slug })} className="brief-item" style={{
      display: "block", width: "100%", textAlign: "left", cursor: "pointer",
      background: "transparent", border: "none", borderTop: `1px solid ${T.border}`,
      padding: "16px 4px 18px",
    }}>
      <div style={{ display: "flex", alignItems: "center", gap: 10, marginBottom: 9, flexWrap: "wrap" }}>
        <NewsChip category={post.category}/>
        <NewsKicker>{newsEdition(post.created_at).replace("ÉDITION ", "")} · {newsTime(post.created_at)}</NewsKicker>
      </div>
      <div className="brief-hl" style={{
        fontFamily: BRIEF_SERIF, fontSize: 20, fontWeight: 600, color: T.text,
        letterSpacing: -0.3, lineHeight: 1.25, marginBottom: 7,
      }}>{post.title}</div>
      {post.hook && (
        <div style={{
          fontFamily: BRIEF_SERIF, fontSize: 14.5, color: briefInk(0.66), lineHeight: 1.55,
          display: "-webkit-box", WebkitLineClamp: 3, WebkitBoxOrient: "vertical", overflow: "hidden",
        }}>{post.hook}</div>
      )}
    </button>
  );
};

const NewsList = ({ go }) => {
  const T = window.QT;
  const [state, setState] = React.useState({ loading: true, posts: [], error: "" });

  React.useEffect(() => {
    let alive = true;
    window.nomerusNews.list().then((res) => {
      if (!alive) return;
      setState({ loading: false, posts: res.posts, error: res.ok ? "" : res.error });
    });
    return () => { alive = false; };
  }, []);

  // Éditions précédentes groupées par jour de parution.
  const [featured, ...rest] = state.posts;
  const days = [];
  rest.forEach((p) => {
    const label = newsDay(p.created_at);
    const last = days[days.length - 1];
    if (last && last.label === label) last.posts.push(p);
    else days.push({ label, posts: [p] });
  });

  return (
    <div style={{ maxWidth: 880, margin: "0 auto", padding: "26px 24px 60px", "--brief-accent": T.indigo }}>
      <NewsMasthead/>

      {state.loading && (
        <div style={{ fontFamily: T.mono, fontSize: 11, color: T.textMute, letterSpacing: 1.5, padding: "30px 0" }}>
          CHARGEMENT DE L'ÉDITION…
        </div>
      )}

      {!state.loading && state.error && (
        <div style={{ fontFamily: BRIEF_SERIF, fontSize: 16, color: T.textDim, padding: "30px 0" }}>{state.error}</div>
      )}

      {!state.loading && !state.error && state.posts.length === 0 && (
        <div style={{ padding: "34px 0 20px", textAlign: "center" }}>
          <div style={{ fontFamily: BRIEF_SERIF, fontSize: 22, fontWeight: 600, color: T.text, marginBottom: 10 }}>
            La première édition est sous presse.
          </div>
          <div style={{ fontFamily: BRIEF_SERIF, fontStyle: "italic", fontSize: 15, color: briefInk(0.66), lineHeight: 1.6, maxWidth: 480, margin: "0 auto" }}>
            Le Brief paraît plusieurs fois par jour, les jours de séance — repasse un peu plus tard.
          </div>
        </div>
      )}

      {featured && <NewsFeaturedCard post={featured} go={go}/>}

      {days.map((d, i) => (
        <section key={i} style={{ marginBottom: 8 }}>
          <div style={{ display: "flex", alignItems: "center", gap: 14, margin: "10px 0 4px" }}>
            <NewsKicker color={T.textDim}>{d.label.toUpperCase()}</NewsKicker>
            <div style={{ flex: 1, borderTop: `1px solid ${T.borderStrong}` }}/>
          </div>
          <div style={{
            display: "grid", gridTemplateColumns: "repeat(auto-fill, minmax(310px, 1fr))",
            columnGap: 34, rowGap: 0,
          }}>
            {d.posts.map((p) => <NewsListItem key={p.slug} post={p} go={go}/>)}
          </div>
        </section>
      ))}

      {!state.loading && state.posts.length > 0 && (
        <div style={{ marginTop: 26 }}>
          <NewsEndMark/>
          <NewsDisclaimer/>
        </div>
      )}
    </div>
  );
};

// ── Écran ─────────────────────────────────────────────────────

const QTNews = ({ go, tradeId }) => {
  return tradeId ? <NewsArticle go={go} slug={tradeId}/> : <NewsList go={go}/>;
};

window.QTNews = QTNews;
