#!/usr/bin/env python3
"""
FormulaSpace Windows Screensaver
Formule de fizica si matematica cu explicatii in romana.

Argumente Windows screensaver:
  /s  — ruleaza screensaverul (fullscreen)
  /p  — preview (fereastra mica in setari)
  /c  — configurare (dialog info)
  fara argumente → dialog configurare
"""

import sys, os, random, io, time, textwrap

# ─── Detecteaza modul de rulare (Windows .scr protocol) ──────
def get_scr_mode():
    args = " ".join(sys.argv[1:]).lower()
    if "/s" in args or "-s" in args:
        return "screensaver"
    elif "/p" in args or "-p" in args:
        return "preview"
    elif "/c" in args or "-c" in args:
        return "configure"
    else:
        return "configure"

SCR_MODE = get_scr_mode()

# ─── Dialog configurare ──────────────────────────────────────
if SCR_MODE == "configure":
    try:
        import tkinter as tk
        from tkinter import messagebox
        root = tk.Tk()
        root.withdraw()
        messagebox.showinfo(
            "FormulaSpace Screensaver",
            "FormulaSpace — Formule de Fizica si Matematica\n\n"
            "Screensaver cu 47+ formule din:\n"
            "  • Mecanica cuantica (Schrödinger, Dirac, Heisenberg)\n"
            "  • Relativitate (Einstein, Lorentz)\n"
            "  • Electromagnetism (Maxwell)\n"
            "  • Matematica pura (Euler, Fourier, Riemann)\n"
            "  • Termodinamica & Mecanica statistica\n"
            "  • Teoria stringurilor & QFT\n\n"
            "Fiecare formula include explicatii complete in romana\n"
            "si descrierea fiecarui termen in parte.\n\n"
            "Apasa ESC sau miscati mouse-ul pentru a iesi."
        )
        root.destroy()
    except Exception:
        pass
    sys.exit(0)

# ─── Import-uri principale ────────────────────────────────────
import pygame
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt

# ═══════════════════════════════════════════════════════════════
#  BAZA DE FORMULE
# ═══════════════════════════════════════════════════════════════
FORMULAS = [

  { "latex": r"$i\hbar\,\dfrac{\partial \Psi}{\partial t} = \hat{H}\Psi$",
    "title": "Ecuatia Schrödinger",
    "desc":  "Descrie evolutia in timp a starii cuantice a oricarui sistem fizic.",
    "terms": [
      ("i",     "unitatea imaginara  (√−1)"),
      ("ℏ",     "constanta Planck redusa  ℏ = h / 2π ≈ 1.055 × 10⁻³⁴ J·s"),
      ("Ψ",     "functia de unda — contine toata informatia despre sistem"),
      ("∂Ψ/∂t", "rata de schimbare a functiei de unda in timp"),
      ("Ĥ",     "operatorul hamiltonian — energia totala a sistemului"),
    ]},

  { "latex": r"$\Delta x \cdot \Delta p \;\geq\; \dfrac{\hbar}{2}$",
    "title": "Principiul de incertitudine Heisenberg",
    "desc":  "Nu pot fi cunoscute simultan pozitia si impulsul cu precizie arbitrar de mare.",
    "terms": [
      ("Δx",  "incertitudinea pozitiei particulei"),
      ("Δp",  "incertitudinea impulsului particulei"),
      ("ℏ",   "constanta Planck redusa ≈ 1.055 × 10⁻³⁴ J·s"),
      ("≥",   "produsul incertitudinilor nu poate cobori sub ℏ/2"),
    ]},

  { "latex": r"$(i\gamma^\mu \partial_\mu - m)\psi = 0$",
    "title": "Ecuatia Dirac",
    "desc":  "Ecuatia relativista a electronului; a prezis existenta antimaterie.",
    "terms": [
      ("i",    "unitatea imaginara"),
      ("γᵘ",   "matricele Dirac (4×4) — implementeaza spinul in relativitate"),
      ("∂ᵤ",   "derivata covarianta in spatiu-timp"),
      ("m",    "masa de repaus a particulei"),
      ("ψ",    "spinorul Dirac — functia de unda cu 4 componente"),
    ]},

  { "latex": r"$[\hat{x},\,\hat{p}] = i\hbar$",
    "title": "Relatia de comutare fundamentala",
    "desc":  "Pozitia si impulsul nu comuta — sursa matematica a incertitudinii cuantice.",
    "terms": [
      ("[A,B]", "comutatorul: AB − BA"),
      ("x̂",    "operatorul de pozitie"),
      ("p̂",    "operatorul de impuls  p̂ = −iℏ ∂/∂x"),
      ("iℏ",   "valoarea nenula indica incompatibilitatea marimilor"),
    ]},

  { "latex": r"$\hat{H}\psi_n = E_n\psi_n$",
    "title": "Ecuatia valorilor proprii (starile stationare)",
    "desc":  "Starile stationare ale unui sistem cuantic au energii bine definite.",
    "terms": [
      ("Ĥ",  "operatorul hamiltonian — energia totala"),
      ("ψₙ", "functia proprie (starea stationara n)"),
      ("Eₙ", "valoarea proprie — energia masurabila a starii n"),
    ]},

  { "latex": r"$E_n = \hbar\omega\!\left(n + \tfrac{1}{2}\right)$",
    "title": "Energia oscilatorului armonic cuantic",
    "desc":  "Nivelurile de energie sunt discrete; la n=0 exista energie de punct zero.",
    "terms": [
      ("ℏ",   "constanta Planck redusa"),
      ("ω",   "frecventa unghiulara a oscilatorului (rad/s)"),
      ("n",   "numarul cuantic: n = 0, 1, 2, 3, ..."),
      ("1/2", "energia de punct zero — sistemul vibreaza chiar si la 0 K"),
    ]},

  { "latex": r"$\langle A \rangle = \langle\psi|\hat{A}|\psi\rangle$",
    "title": "Valoarea de asteptare a unui observabil",
    "desc":  "Media rezultatelor masuratorilor repetate ale marimii A in starea ψ.",
    "terms": [
      ("⟨A⟩", "media asteptata a observabilului A"),
      ("⟨ψ|", "bra — conjugatul hermitic al starii cuantice"),
      ("|ψ⟩", "ket — starea cuantica a sistemului (notatia Dirac)"),
      ("Â",   "operatorul asociat marimii fizice A"),
    ]},

  { "latex": r"$Z = \int \mathcal{D}\phi\;e^{iS[\phi]/\hbar}$",
    "title": "Integrala de drum Feynman",
    "desc":  "In mecanica cuantica, sistemul exploreaza simultan toate caile posibile.",
    "terms": [
      ("Z",        "functia de partitie — suma peste toate traiectoriile"),
      ("𝒟φ",      "masura de integrare peste toate configuratiile campului"),
      ("S[φ]",     "actiunea asociata unui drum particular"),
      ("e^{iS/ℏ}", "amplitudinea de probabilitate a fiecarei cai"),
    ]},

  { "latex": r"$E = mc^2$",
    "title": "Echivalenta masa-energie (Einstein, 1905)",
    "desc":  "Masa si energia sunt echivalente; o masa mica corespunde unei energii enorme.",
    "terms": [
      ("E", "energia totala a corpului in repaus (Joule)"),
      ("m", "masa de repaus a corpului (kg)"),
      ("c", "viteza luminii in vid  c ≈ 2.998 × 10⁸ m/s"),
    ]},

  { "latex": r"$G_{\mu\nu} + \Lambda g_{\mu\nu} = \dfrac{8\pi G}{c^4}\,T_{\mu\nu}$",
    "title": "Ecuatiile campului gravitational Einstein",
    "desc":  "Geometria spatiu-timpului este curbata de distributia de masa si energie.",
    "terms": [
      ("Gᵤᵥ", "tensorul Einstein — descrie curbura spatiu-timpului"),
      ("Λ",   "constanta cosmologica — asociata energiei intunecate"),
      ("gᵤᵥ", "tensorul metric — masoara distantele in spatiu-timp"),
      ("G",   "constanta gravitationala ≈ 6.674 × 10⁻¹¹ N·m²/kg²"),
      ("Tᵤᵥ", "tensorul energie-impuls — distributia de materie si energie"),
    ]},

  { "latex": r"$\gamma = \dfrac{1}{\sqrt{1-v^2/c^2}}$",
    "title": "Factorul Lorentz (relativitate speciala)",
    "desc":  "La viteze mari, timpul se dilata si lungimile se contracta cu factorul γ.",
    "terms": [
      ("γ", "factorul Lorentz — γ=1 la v=0, γ→∞ cand v→c"),
      ("v", "viteza relativa a sistemului de referinta (m/s)"),
      ("c", "viteza luminii  c ≈ 2.998 × 10⁸ m/s"),
    ]},

  { "latex": r"$E^2 = (pc)^2 + (mc^2)^2$",
    "title": "Relatia energie-impuls relativista",
    "desc":  "Generalizeaza E=mc² pentru corpuri in miscare. Pentru foton (m=0): E=pc.",
    "terms": [
      ("E", "energia totala a particulei"),
      ("p", "impulsul relativist al particulei"),
      ("m", "masa de repaus (zero pentru fotoni)"),
      ("c", "viteza luminii"),
    ]},

  { "latex": r"$\nabla \cdot \mathbf{E} = \dfrac{\rho}{\epsilon_0}$",
    "title": "Legea Gauss pentru campul electric (Maxwell I)",
    "desc":  "Sarcinile electrice sunt surse ale campului electric.",
    "terms": [
      ("∇·",  "divergenta — masoara cat camp iese dintr-un punct"),
      ("E",   "vectorul camp electric (V/m)"),
      ("ρ",   "densitatea de sarcina electrica (C/m³)"),
      ("ε₀",  "permitivitatea electrica a vidului ≈ 8.854 × 10⁻¹² F/m"),
    ]},

  { "latex": r"$\nabla \times \mathbf{B} = \mu_0\mathbf{J} + \mu_0\epsilon_0\dfrac{\partial\mathbf{E}}{\partial t}$",
    "title": "Legea Ampere-Maxwell (Maxwell IV)",
    "desc":  "Curentii electrici si campurile electrice variabile genereaza camp magnetic.",
    "terms": [
      ("∇×",      "rotorul — masoara rotatia campului"),
      ("B",       "vectorul camp magnetic (Tesla)"),
      ("μ₀",      "permeabilitatea magnetica a vidului = 4π × 10⁻⁷ T·m/A"),
      ("J",       "densitatea de curent electric (A/m²)"),
      ("∂E/∂t",   "curentul de deplasare Maxwell"),
    ]},

  { "latex": r"$\nabla \times \mathbf{E} = -\dfrac{\partial\mathbf{B}}{\partial t}$",
    "title": "Legea inductiei Faraday (Maxwell III)",
    "desc":  "Un camp magnetic variabil in timp genereaza un camp electric rotational.",
    "terms": [
      ("∇×E",   "rotorul campului electric"),
      ("∂B/∂t", "rata de variatie a campului magnetic in timp"),
      ("−",     "semnul minus — legea lui Lenz (opozitie la cauza)"),
    ]},

  { "latex": r"$c = \dfrac{1}{\sqrt{\mu_0\epsilon_0}}$",
    "title": "Viteza luminii din constantele electromagnetice",
    "desc":  "Maxwell a demonstrat ca lumina este o unda electromagnetica din aceasta relatie.",
    "terms": [
      ("c",  "viteza luminii in vid ≈ 2.998 × 10⁸ m/s"),
      ("μ₀", "permeabilitatea magnetica a vidului"),
      ("ε₀", "permitivitatea electrica a vidului"),
    ]},

  { "latex": r"$e^{i\pi} + 1 = 0$",
    "title": "Identitatea lui Euler",
    "desc":  "Considerata cea mai frumoasa formula — uneste 5 constante fundamentale.",
    "terms": [
      ("e",  "baza logaritmului natural ≈ 2.71828..."),
      ("i",  "unitatea imaginara  i² = −1"),
      ("π",  "raportul circumferintei la diametru ≈ 3.14159..."),
      ("1",  "elementul neutru al inmultirii"),
      ("0",  "elementul neutru al adunarii"),
    ]},

  { "latex": r"$\zeta(s) = \sum_{n=1}^{\infty} \dfrac{1}{n^s}$",
    "title": "Functia Riemann Zeta",
    "desc":  "Legata de distributia numerelor prime; ipoteza Riemann ramane nedemonstrara.",
    "terms": [
      ("ζ(s)", "functia Riemann zeta"),
      ("s",   "argument complex  s = σ + it"),
      ("n",   "indicele sumei — parcurge toate numerele naturale"),
    ]},

  { "latex": r"$\hat{f}(\xi) = \int_{-\infty}^{\infty} f(x)\,e^{-2\pi i x\xi}\,dx$",
    "title": "Transformata Fourier",
    "desc":  "Descompune orice semnal in frecventele sale componente.",
    "terms": [
      ("f̂(ξ)",       "transformata Fourier — spectrul de frecvente"),
      ("f(x)",       "functia originala in domeniul timp/spatiu"),
      ("ξ",          "frecventa (Hz)"),
      ("e^{−2πixξ}", "nucleul Fourier — rotatie in planul complex"),
    ]},

  { "latex": r"$e^x = \sum_{n=0}^{\infty} \dfrac{x^n}{n!}$",
    "title": "Seria Taylor a lui e^x",
    "desc":  "Functia exponentiala se poate exprima ca o suma infinita de puteri.",
    "terms": [
      ("eˣ",  "functia exponentiala"),
      ("xⁿ",  "puterea n a argumentului"),
      ("n!",  "factorialul: n! = 1·2·3·...·n"),
    ]},

  { "latex": r"$\int_{-\infty}^{\infty} e^{-x^2}\,dx = \sqrt{\pi}$",
    "title": "Integrala gaussiana",
    "desc":  "Fundamentala in probabilitati si mecanica statistica.",
    "terms": [
      ("∫",       "integrala pe intreaga axa reala"),
      ("e^{−x²}", "functia gaussiana — curba in clopot"),
      ("√π",      "rezultatul exact — demonstrat prin coordonate polare"),
    ]},

  { "latex": r"$S = k_B \ln\Omega$",
    "title": "Entropia Boltzmann",
    "desc":  "Entropia este proportionala cu logaritmul numarului de microstate.",
    "terms": [
      ("S",   "entropia termodinamica (J/K)"),
      ("k_B", "constanta Boltzmann ≈ 1.381 × 10⁻²³ J/K"),
      ("ln",  "logaritmul natural"),
      ("Ω",   "numarul de microstate compatibile cu starea macroscopica"),
    ]},

  { "latex": r"$dS \geq \dfrac{\delta Q}{T}$",
    "title": "Al doilea principiu al termodinamicii",
    "desc":  "Entropia unui sistem izolat nu poate scadea — fundamenteaza ireversibilitatea timpului.",
    "terms": [
      ("dS",   "variatia infinitezimala a entropiei"),
      ("δQ",   "caldura schimbata cu mediul"),
      ("T",    "temperatura absoluta (Kelvin)"),
      ("≥",    "egalitatea — doar pentru procese reversibile"),
    ]},

  { "latex": r"$PV = nRT$",
    "title": "Legea gazului ideal",
    "desc":  "Relatia dintre presiunea, volumul si temperatura unui gaz perfect.",
    "terms": [
      ("P", "presiunea gazului (Pascal)"),
      ("V", "volumul (m³)"),
      ("n", "numarul de moli (mol)"),
      ("R", "constanta universala a gazelor ≈ 8.314 J/(mol·K)"),
      ("T", "temperatura absoluta (Kelvin)"),
    ]},

  { "latex": r"$\mathbf{F} = m\mathbf{a}$",
    "title": "A doua lege a lui Newton",
    "desc":  "Forta aplicata unui corp este egala cu produsul masei si acceleratiei.",
    "terms": [
      ("F", "forta rezultanta aplicata corpului (Newton)"),
      ("m", "masa inerttiala a corpului (kg)"),
      ("a", "acceleratia corpului (m/s²)"),
    ]},

  { "latex": r"$\dfrac{d}{dt}\dfrac{\partial\mathcal{L}}{\partial\dot{q}} - \dfrac{\partial\mathcal{L}}{\partial q} = 0$",
    "title": "Ecuatiile Euler-Lagrange",
    "desc":  "Formuleaza mecanica clasica prin minimizarea actiunii.",
    "terms": [
      ("ℒ",    "lagrangianul  ℒ = Ec − Ep"),
      ("q",    "coordonata generalizata"),
      ("q̇",   "viteza generalizata (dq/dt)"),
      ("d/dt", "derivata totala in raport cu timpul"),
    ]},

  { "latex": r"$H = \sum_i p_i\dot{q}_i - \mathcal{L}$",
    "title": "Hamiltonianul clasic",
    "desc":  "Energia totala in coordonate generalizate si impulsuri conjugate.",
    "terms": [
      ("H",  "hamiltonianul — energia totala (Ec + Ep)"),
      ("pᵢ", "impulsul generalizat conjugat lui qᵢ"),
      ("q̇ᵢ","viteza generalizata"),
      ("ℒ",  "lagrangianul sistemului"),
    ]},

  { "latex": r"$\rho\dfrac{D\mathbf{v}}{Dt} = -\nabla p + \mu\nabla^2\mathbf{v} + \mathbf{f}$",
    "title": "Ecuatia Navier-Stokes (fluide vascoase)",
    "desc":  "Guverneaza miscarea fluidelor vascoase; inca nerezolvata complet matematic.",
    "terms": [
      ("ρ",    "densitatea fluidului (kg/m³)"),
      ("D/Dt", "derivata materiala — urmarind particula de fluid"),
      ("v",    "campul de viteza (m/s)"),
      ("∇p",   "gradientul de presiune"),
      ("μ",    "vascozitatea dinamica (Pa·s)"),
      ("f",    "forte externe (ex: gravitatia)"),
    ]},

  { "latex": r"$\mathcal{L} = -\tfrac{1}{4}F_{\mu\nu}F^{\mu\nu} + \bar\psi(i\!\not\!\!D - m)\psi$",
    "title": "Lagrangianul QED (electrodinamica cuantica)",
    "desc":  "Descrie interactia dintre electroni si fotoni — cea mai precisa teorie din fizica.",
    "terms": [
      ("Fᵤᵥ",  "tensorul campului electromagnetic (contine E si B)"),
      ("ψ̄",    "spinorul Dirac conjugat (campul electronului)"),
      ("iD̸",   "derivata covarianta — include cuplajul electromagnetic"),
      ("m",    "masa electronului"),
    ]},

  { "latex": r"$S_{BH} = \dfrac{k_B c^3}{4 G \hbar}\,A$",
    "title": "Entropia Bekenstein-Hawking (gauri negre)",
    "desc":  "Entropia gaurii negre este proportionala cu aria orizontului de evenimente.",
    "terms": [
      ("S_BH", "entropia gaurii negre (J/K)"),
      ("k_B",  "constanta Boltzmann"),
      ("c",    "viteza luminii"),
      ("G",    "constanta gravitationala"),
      ("ℏ",   "constanta Planck redusa"),
      ("A",    "aria orizontului de evenimente"),
    ]},

  { "latex": r"$T_H = \dfrac{\hbar c^3}{8\pi G M k_B}$",
    "title": "Temperatura Hawking",
    "desc":  "Gaurille negre emit radiatii termice — descoperire teoretica a lui Stephen Hawking.",
    "terms": [
      ("T_H", "temperatura de radiatie (extrem de mica pentru gauri negre reale)"),
      ("ℏ",  "constanta Planck redusa"),
      ("c",   "viteza luminii"),
      ("G",   "constanta gravitationala"),
      ("M",   "masa gaurii negre (kg)"),
      ("k_B", "constanta Boltzmann"),
    ]},

  { "latex": r"$E_n = -\dfrac{m_e e^4}{2\hbar^2}\dfrac{1}{n^2}$",
    "title": "Nivelurile de energie ale atomului de hidrogen (Bohr)",
    "desc":  "Electronul in atomul de hidrogen ocupa doar niveluri discrete de energie.",
    "terms": [
      ("Eₙ",  "energia nivelului n  (E₁ ≈ −13.6 eV)"),
      ("mₑ",  "masa electronului ≈ 9.109 × 10⁻³¹ kg"),
      ("e",   "sarcina elementara ≈ 1.602 × 10⁻¹⁹ C"),
      ("ℏ",  "constanta Planck redusa"),
      ("n",   "numarul cuantic principal: 1, 2, 3, ..."),
    ]},

  { "latex": r"$\lambda = \dfrac{h}{p} = \dfrac{h}{mv}$",
    "title": "Lungimea de unda de Broglie",
    "desc":  "Orice particula de materie are asociata o lungime de unda — dualitatea unda-corpuscul.",
    "terms": [
      ("λ", "lungimea de unda asociata particulei (m)"),
      ("h", "constanta Planck ≈ 6.626 × 10⁻³⁴ J·s"),
      ("p", "impulsul particulei  p = mv"),
      ("m", "masa particulei (kg)"),
      ("v", "viteza particulei (m/s)"),
    ]},

  { "latex": r"$\oint_{\partial\Omega}\omega = \int_\Omega d\omega$",
    "title": "Teorema Stokes generalizata",
    "desc":  "Integrala pe frontiera unui domeniu egalizeaza integrala derivatei in interior.",
    "terms": [
      ("∮",  "integrala de-a lungul frontierei ∂Ω"),
      ("ω",  "forma diferentiala de grad k"),
      ("dω", "derivata exterioara a formei ω"),
      ("Ω",  "domeniul de integrare"),
    ]},

  { "latex": r"$\nabla^2 f = \dfrac{\partial^2 f}{\partial x^2}+\dfrac{\partial^2 f}{\partial y^2}+\dfrac{\partial^2 f}{\partial z^2}$",
    "title": "Operatorul Laplace",
    "desc":  "Masoara diferenta intre valoarea unei functii si media valorilor din jur.",
    "terms": [
      ("∇²",       "operatorul Laplace — suma derivatelor de ordinul 2"),
      ("∂²f/∂x²",  "derivata partiala de ordinul 2 dupa x"),
    ]},
]

# ═══════════════════════════════════════════════════════════════
#  RENDER FORMULA
# ═══════════════════════════════════════════════════════════════
def render_formula(latex, target_width, dpi=90):
    fig = plt.figure(figsize=(11, 1.9), dpi=dpi)
    fig.patch.set_alpha(0.0)
    ax = fig.add_axes([0, 0, 1, 1])
    ax.set_axis_off()
    ax.patch.set_alpha(0.0)
    try:
        ax.text(0.5, 0.5, latex, color="white", fontsize=28,
                ha="center", va="center", transform=ax.transAxes,
                math_fontfamily="dejavusans")
    except Exception:
        ax.text(0.5, 0.5, latex.replace("$", ""), color="white", fontsize=22,
                ha="center", va="center", transform=ax.transAxes)
    buf = io.BytesIO()
    fig.savefig(buf, format="png", dpi=dpi, transparent=True,
                bbox_inches="tight", pad_inches=0.05)
    plt.close(fig)
    buf.seek(0)
    surf = pygame.image.load(buf).convert_alpha()
    fw, fh = surf.get_size()
    if fw > target_width:
        scale = target_width / fw
        surf = pygame.transform.smoothscale(surf, (target_width, int(fh * scale)))
    return surf


# ═══════════════════════════════════════════════════════════════
#  PRE-RENDER CARD COMPLET
# ═══════════════════════════════════════════════════════════════
def build_card(entry, formula_surf, W, font_title, font_desc, font_sym, font_exp):
    MARGIN  = 60
    PAD_TOP = 18
    PAD_BOT = 30

    fw, fh = formula_surf.get_size()
    title_s = font_title.render(entry["title"], True, (110, 200, 255))

    max_chars = max(10, (W - 2 * MARGIN) // max(font_desc.size("A")[0], 1))
    desc_surfs = [font_desc.render(l, True, (160, 185, 160))
                  for l in textwrap.wrap(entry["desc"], width=max_chars)]

    term_rows = []
    for sym, expl in entry.get("terms", []):
        ss  = font_sym.render(f"  {sym}", True, (255, 200, 80))
        arr = font_sym.render("  →  ",   True, (70, 95, 80))
        max_e = max(20, (W - 2*MARGIN - ss.get_width() - arr.get_width()) //
                    max(font_exp.size("A")[0], 1))
        expl_s = [font_exp.render(l, True, (200, 210, 200))
                  for l in textwrap.wrap(expl, width=max_e)]
        term_rows.append((ss, arr, expl_s))

    lh = font_sym.get_height()
    h = PAD_TOP + fh + 6 + title_s.get_height() + 6
    for ds in desc_surfs:
        h += ds.get_height() + 2
    h += 12
    for (ss, arr, exs) in term_rows:
        h += max(lh, sum(e.get_height() for e in exs)) + 4
    h += PAD_BOT

    card = pygame.Surface((W, h), pygame.SRCALPHA)
    card.fill((0, 0, 0, 0))
    y = PAD_TOP

    pygame.draw.line(card, (35, 55, 75), (MARGIN, y-4), (W-MARGIN, y-4), 1)
    card.blit(formula_surf, (W//2 - fw//2, y));  y += fh + 6
    card.blit(title_s, (W//2 - title_s.get_width()//2, y));  y += title_s.get_height() + 6
    for ds in desc_surfs:
        card.blit(ds, (W//2 - ds.get_width()//2, y));  y += ds.get_height() + 2
    y += 10
    pygame.draw.line(card, (30, 50, 65), (MARGIN*2, y), (W-MARGIN*2, y), 1)
    y += 8
    for (ss, arr, exs) in term_rows:
        x = MARGIN + 10
        card.blit(ss,  (x, y));  x += ss.get_width()
        card.blit(arr, (x, y));  x += arr.get_width()
        for li, es in enumerate(exs):
            card.blit(es, (x, y + li * es.get_height()))
        y += max(ss.get_height(), sum(e.get_height() for e in exs)) + 4

    return card


# ═══════════════════════════════════════════════════════════════
#  MAIN ANIMATION
# ═══════════════════════════════════════════════════════════════
def run_screensaver(preview_hwnd=None):
    pygame.init()

    if preview_hwnd:
        # Preview mode: fereastra mica in panoul de setari Windows
        os.environ["SDL_WINDOWID"] = str(preview_hwnd)
        W, H = 320, 240
        screen = pygame.display.set_mode((W, H))
    else:
        info = pygame.display.Info()
        W, H = info.current_w, info.current_h
        screen = pygame.display.set_mode((W, H), pygame.FULLSCREEN | pygame.NOFRAME)

    pygame.display.set_caption("FormulaSpace")
    pygame.mouse.set_visible(False)
    clock = pygame.time.Clock()

    font_title = pygame.font.SysFont("segoeui",   22, bold=True)
    font_desc  = pygame.font.SysFont("segoeui",   16)
    font_sym   = pygame.font.SysFont("segoeui",   15, bold=True)
    font_exp   = pygame.font.SysFont("segoeui",   15)
    font_hint  = pygame.font.SysFont("consolas",  11)

    formula_max_w = int(W * 0.82)

    # Pre-render toate cardurile
    print("Pre-rendering formule...", flush=True)
    cards_data = []
    random.shuffle(FORMULAS)
    for i, entry in enumerate(FORMULAS):
        sys.stdout.write(f"\r  [{i+1}/{len(FORMULAS)}] {entry['title'][:45]:<45}")
        sys.stdout.flush()
        try:
            fsurf = render_formula(entry["latex"], formula_max_w)
            csurf = build_card(entry, fsurf, W,
                               font_title, font_desc, font_sym, font_exp)
            cards_data.append(csurf)
        except Exception as e:
            print(f"\n  ! {entry['title']}: {e}")
    print(f"\nGata: {len(cards_data)} carduri.")

    if not cards_data:
        pygame.quit(); sys.exit(1)

    SPEED = 0.55
    GAP   = 50

    active = []
    card_idx = 0

    def add_card(y):
        nonlocal card_idx
        s = cards_data[card_idx % len(cards_data)]
        card_idx += 1
        return [s, float(y)]

    y_cur = -H * 0.15
    while y_cur < H + 200:
        c = add_card(y_cur)
        active.append(c)
        y_cur += c[0].get_height() + GAP

    # Fundal gradient
    bg = pygame.Surface((W, H))
    for yy in range(H):
        r = int(4  + 6  * yy / H)
        g = int(8  + 8  * yy / H)
        b = int(16 + 14 * yy / H)
        pygame.draw.line(bg, (r, g, b), (0, yy), (W, yy))

    hint_surf = font_hint.render("ESC / miscare mouse — iesire", True, (35, 55, 75))

    running = True
    t0 = time.time()
    mouse_start = pygame.mouse.get_pos()

    while running:
        for ev in pygame.event.get():
            if ev.type == pygame.QUIT:
                running = False
            elif ev.type == pygame.KEYDOWN:
                running = False
            elif ev.type == pygame.MOUSEBUTTONDOWN:
                running = False
            elif ev.type == pygame.MOUSEMOTION:
                # Pe Windows screensaver, orice miscare semnificativa inchide
                mx, my = pygame.mouse.get_pos()
                sx, sy = mouse_start
                if time.time() - t0 > 1.5 and (abs(mx-sx) > 5 or abs(my-sy) > 5):
                    running = False

        screen.blit(bg, (0, 0))

        for item in active:
            item[1] += SPEED
            y = int(item[1])
            if y + item[0].get_height() > 0 and y < H:
                screen.blit(item[0], (0, y))

        if active:
            top_y = active[0][1]
            if top_y > -GAP:
                new_y = top_y - cards_data[card_idx % len(cards_data)].get_height() - GAP
                active.insert(0, add_card(new_y))

        active = [c for c in active if c[1] < H + 10]

        if not preview_hwnd:
            screen.blit(hint_surf, (W - hint_surf.get_width() - 8, H - 16))

        pygame.display.flip()
        clock.tick(30)

    pygame.quit()


# ─── Entry point ─────────────────────────────────────────────
if __name__ == "__main__":
    # Detecteaza hwnd pentru preview (/p <hwnd>)
    hwnd = None
    args = sys.argv[1:]
    for i, a in enumerate(args):
        if a.lower() in ("/p", "-p") and i + 1 < len(args):
            try:
                hwnd = int(args[i + 1])
            except ValueError:
                pass

    run_screensaver(preview_hwnd=hwnd)
