"""
Copyright Malcolm J. Macleod (malcolm@simulationuniverse.com)

 * This software is free to use, modify, and distribute under creative commons
 * https://creativecommons.org/licenses/by-nc-sa/4.0/ (CC CC BY-NC-SA 4.0).
 * Any derivative works or redistributions must include appropriate credit to
 * Malcolm Macleod and this permission notice shall
 * be included in all copies or substantial portions of the Software.

"""

"""
spiral_branch.py  --  INTEGRATED SPIRAL + BRANCH
==================================================
The branch engine of branch_sim2.py attached to the spiral, with
diagnostics and plots.

DEFAULT SCENARIO
------------------
    branch opens at spiral step t = 17
    runs psi = 24,961,293 steps
    closes on the spiral at t = 17 + psi

PSI IS USER-SETTABLE. Set PSI_OVERRIDE to any positive integer, or leave
it None to derive psi from SIGMA. Either way psi is rounded to an exact
integer, which is required: closure must coincide with a spiral tick
(there is no external clock), and every monopole phase must be real at
the point-state. sigma = Omega^5 alone is EXCLUDED because it gives
psi = 5501.343.

THE TWO ENGINES
-----------------
  Planck (spiral) tau : 15 tau cycles per spiral tick, each generating
                        one Omega. Fast; the pacemaker.
  Branch tau          : ONE tau loop stretched over psi ticks -- the
                        same engine running psi times slower. It has not
                        finished its first Omega^15, which is why the
                        branch deposits nothing until it closes, and why
                        m = m_P/psi is the slowdown ratio itself.

Phase convention is pi per loop (Article 1b's Euler appendix:
Psi(e) = Omega^2 e^{i pi} = -Omega^2), so the state is -xi after one
cycle and +xi after two. Mass sees psi; spin sees 2 psi.

PERFORMANCE
-------------
psi = 2.5e7, so nothing is stepped 25 million times. The spiral angle
uses the exact arctan sum below a cutoff and the Theodorus asymptotic
Theta = 2 sqrt(t) - 2.157782997 above it (verified accurate to ~1e-3 by
t=1e5, improving as 1/sqrt(t)). All branch phases are linear in k and
are evaluated analytically, never accumulated.
"""

import math

PI = math.pi
TAU = 2.0*PI
ALPHA_INV = 137.035999084
OMEGA = math.sqrt(PI**math.e * math.e**(1.0 - math.e))
CONE = math.acos(1.0/3.0)
THEODORUS_K = -2.157782997          # Theta(t) -> 2 sqrt(t) + K
EXACT_BELOW = 20000                 # sum arctans exactly below this t

# ----------------------------------------------------------------------
# SCENARIO
# ----------------------------------------------------------------------
ALPHA_INV_TUNED = 16.5551369428**2/2            # 137.0362795974, +2.05 ppm
SIGMA = 16.5551369428*OMEGA**5                  # quantum + Dirac scaling
PSI_OVERRIDE = None                             # e.g. 101 for a fast run
PSI = float(round(PSI_OVERRIDE if PSI_OVERRIDE else SIGMA**3/TAU))

BRANCH_OPEN = 17
BRANCH_CLOSE = BRANCH_OPEN + PSI

# TURN TRIPLE. Constraint: sum(n) must be EVEN.
#   Holonomy requires the total phase to close at a multiple of 2pi.
#   Under the pi convention  sum phi(psi) = pi sum(n),  so sum(n) even.
#   (Under the OLD 2pi convention it was sum(n)=1; that is stale and was
#    the source of two compounding errors -- see CORRECTIONS below.)
TURNS = (-1, 1, 0)                              # S=0, D=0... see check below
TURNS = (-2, 0, 0)                              # S=-2, D=2 -> fermion, 2 cycles


# ----------------------------------------------------------------------
# SPIRAL
# ----------------------------------------------------------------------
_exact = [0.0]
for _k in range(1, EXACT_BELOW + 1):
    _exact.append(_exact[-1] + math.atan(1.0/math.sqrt(_k)))


def spiral_theta(t):
    if t <= 1:
        return 0.0
    if t < EXACT_BELOW:
        n = int(t)
        frac = t - n
        return _exact[n-1] + frac*math.atan(1.0/math.sqrt(n))
    return 2.0*math.sqrt(t) + THEODORUS_K


def spiral_radius(t):
    return math.sqrt(t)


def spiral_xy(t):
    r, th = spiral_radius(t), spiral_theta(t)
    return r*math.cos(th), r*math.sin(th)


# ----------------------------------------------------------------------
# PLANCK (SPIRAL) TAU LOOP -- one cycle, tau: 1 -> e
# ----------------------------------------------------------------------
def tau_of(u):
    """u = ln(tau) in [0,1]."""
    return math.exp(u)


def amplitude(u):
    """A = Omega^(ln tau + 1): Omega at u=0, Omega^2 at u=1."""
    return OMEGA**(u + 1.0)


def tau_phase(u):
    """phi = pi ln tau: 0 -> pi. The HALF-cycle."""
    return PI*u


def standing_wave(u):
    return math.sin(PI*u)


def psi_state(u):
    """Psi = A e^{i phi}. Psi(1) = -Omega^2."""
    a, p = amplitude(u), tau_phase(u)
    return a*math.cos(p), a*math.sin(p)


# ----------------------------------------------------------------------
# BRANCH
# ----------------------------------------------------------------------
def branch_phases(k, turns=TURNS, psi=PSI):
    """pi convention, evaluated not accumulated."""
    return [PI*n*k/psi for n in turns]


def branch_delta(k, turns=TURNS, psi=PSI):
    p = branch_phases(k, turns, psi)
    return p[2] - 0.5*(p[0] + p[1])


def branch_sign(k, psi=PSI, turns=TURNS):
    """Spinor sign, tracked from Delta (the N-S azimuth), which is what
    actually rotates. Delta advances 2 pi * precession per cycle; the
    state is -xi when Delta has covered an odd number of half-turns."""
    d = branch_delta(k, turns, psi)
    return -1 if int(math.floor(abs(d)/PI + 1e-9)) % 2 == 1 else +1


def turn_sum(turns=TURNS):
    return sum(turns)


def admissible(turns=TURNS):
    """Holonomy: sum(n) must be even under the pi convention."""
    return sum(turns) % 2 == 0


def precession(turns=TURNS):
    """
    Rotation per branch cycle, in TURNS (units of 2 pi), read directly
    off the dynamics rather than asserted:

        delta(k) = phi3 - (phi1+phi2)/2,   phi_j = pi n_j k/psi
        delta(psi) = pi [n3 - (n1+n2)/2]
        precession = delta(psi)/(2 pi) = [n3 - (n1+n2)/2] / 2

    Equivalently (3 n3 - S)/4 with S = sum(n).

    NOTE: an earlier version hardcoded (3 n3 - 1)/4, which silently
    assumed S = 1. That was inherited from the 2pi convention and became
    wrong when the convention changed to pi. It agreed with this general
    form only for S=1 triples, which is why it went unnoticed.
    """
    return (turns[2] - 0.5*(turns[0] + turns[1]))/2.0


def classify(turns=TURNS):
    """D = 3 n3 - S; precession = D/4."""
    D = 3*turns[2] - sum(turns)
    if D == 0:
        return "spin-0 (no precession)"
    if abs(D) == 2:
        return "FERMION (2 cycles)"
    if abs(D) == 4:
        return "BOSON (1 cycle)"
    return f"other (D={D}, {abs(4/D):.2f} cycles)"


def monopole_vectors(k, turns=TURNS, psi=PSI, axis=(0.0, 0.0, 1.0)):
    s = axis
    tmp = (1.0, 0.0, 0.0) if abs(s[0]) < 0.9 else (0.0, 1.0, 0.0)
    u = (tmp[1]*s[2]-tmp[2]*s[1], tmp[2]*s[0]-tmp[0]*s[2], tmp[0]*s[1]-tmp[1]*s[0])
    un = math.sqrt(sum(c*c for c in u)); u = tuple(c/un for c in u)
    w = (s[1]*u[2]-s[2]*u[1], s[2]*u[0]-s[0]*u[2], s[0]*u[1]-s[1]*u[0])
    d = branch_delta(k, turns, psi)
    out = []
    for j in range(3):
        a = d + TAU*j/3
        out.append(tuple(math.cos(CONE)*s[i]
                         + math.sin(CONE)*(math.cos(a)*u[i] + math.sin(a)*w[i])
                         for i in range(3)))
    return out


def unit_sum(k, **kw):
    ms = monopole_vectors(k, **kw)
    tot = tuple(sum(m[i] for m in ms) for i in range(3))
    return math.sqrt(sum(c*c for c in tot))


# ----------------------------------------------------------------------
# DIAGNOSTICS
# ----------------------------------------------------------------------
def diagnostics():
    print("="*72)
    print("SPIRAL + BRANCH  --  integrated scenario")
    print("="*72)
    print(f"  alpha^-1 (tuned)  = {ALPHA_INV_TUNED:.10f}  "
          f"({(ALPHA_INV_TUNED-ALPHA_INV)/ALPHA_INV*1e6:+.2f} ppm)  <- INPUT")
    print(f"  sigma             = {SIGMA:.8f}")
    print(f"  psi               = {PSI:,.0f}   frac = {abs(SIGMA**3/TAU-PSI):.2e}")
    S = turn_sum()
    D = 3*TURNS[2] - S
    print(f"  turn triple       = {TURNS}   n3 = {TURNS[2]}, S = {S}, D = 3n3-S = {D}")
    print(f"  admissible (S even)? {'YES' if admissible() else 'NO -- holonomy violated'}")
    p = precession()
    if p:
        print(f"  precession        = {p:+.3f} turns/cycle "
              f"-> returns after {abs(1/p):.0f} cycles   [{classify()}]")
    else:
        print(f"  precession        = 0  [{classify()}]")
    if not admissible():
        print("  *** WARNING: sum(n) is odd. This triple does not close the")
        print("      holonomy and is not a valid configuration. ***")

    print("\n  BRANCH ON THE SPIRAL")
    print(f"    opens   at t = {BRANCH_OPEN:>14,}   radius {spiral_radius(BRANCH_OPEN):>12.4f}")
    print(f"    closes  at t = {BRANCH_CLOSE:>14,.0f}   radius {spiral_radius(BRANCH_CLOSE):>12.4f}")
    print(f"    spiral grows by a factor {spiral_radius(BRANCH_CLOSE)/spiral_radius(BRANCH_OPEN):,.1f}"
          f" during one branch cycle")
    turns_swept = (spiral_theta(BRANCH_CLOSE)-spiral_theta(BRANCH_OPEN))/TAU
    print(f"    spiral sweeps {turns_swept:,.1f} turns while the branch is open")

    print("\n  THE TWO ENGINES")
    print(f"    Planck tau: 15 cycles per spiral tick   (pacemaker)")
    print(f"    branch tau: 1 cycle per {PSI:,.0f} ticks   (slowdown = psi)")
    print(f"    slowdown ratio = psi = {PSI:,.0f}  ->  m/m_P = {1/PSI:.6e}")

    print("\n  COLLAPSE STRUCTURE (pi convention)")
    print("    (report SUM of phases -- the holonomy -- and Delta, the N-S")
    print("     azimuth. Using max(phases) was a display bug: for a triple")
    print("     with negative entries it reports 0 and hides the dynamics.)")
    for c in (1, 2, 3, 4):
        k = c*PSI
        tot = sum(branch_phases(k))
        dl = branch_delta(k)
        print(f"    after {c} cycle(s): sum(phi) = {tot/PI:+.3f} pi, "
              f"Delta = {dl/PI:+.3f} pi, state = {branch_sign(k):+d} xi"
              f"{'   <- spinor returns here' if c == 2 else ('   <- sign flip' if c == 1 else '')}")

    print("\n  STRUCTURE UNDER THE CORRECTED CONSTRAINT (S even)")
    print(f"    precession = (3 n3 - S)/4 = D/4")
    print(f"    |D|=2 -> fermion (2 cycles)   |D|=4 -> boson (1 cycle)")
    print(f"    D odd -> 4 cycles, no physical counterpart")
    print(f"    S even => D has the parity of n3, so n3 EVEN is the")
    print(f"    physical case. (The original parity rule; the 'odd n3'")
    print(f"    version was an artifact of the stale S=1 constraint.)")

    print("\n  CORRECTIONS APPLIED (found by this program, not by the theory)")
    print("    1. precession() hardcoded (3n3-1)/4, assuming S=1. Replaced")
    print("       with the general form read off branch_delta.")
    print("    2. The constraint S=1 was inherited from the 2pi convention.")
    print("       Under pi it is S EVEN. Both errors were mutually")
    print("       consistent, so every test still passed.")
    print("    3. WITHDRAWN: 'spin-0 is unreachable'. That relied on S=1")
    print("       forcing n3=1/3. With S even, D=0 is solvable -- e.g.")
    print("       (0,0,0) or (-1,1,0) -- so a zero-precession state EXISTS.")
    print("       The composite-Higgs commitment derived from it no longer")
    print("       follows and must be retracted.")
    print("    4. WITHDRAWN: 'exactly one triple returns in 2 cycles'.")
    print("       There is a family, not a unique spinor triple.")

    print("\n  CHECKS")
    tot1 = sum(branch_phases(PSI))
    print(f"    sum(phi) after 1 cycle closes mod 2pi?  "
          f"{'YES' if abs((tot1 % TAU)) < 1e-9 or abs((tot1 % TAU)-TAU) < 1e-9 else 'no'}"
          f"   ({tot1/PI:+.4f} pi)")
    d1 = branch_delta(PSI)
    print(f"    Delta after 1 cycle = pi (half turn)?   "
          f"{'YES' if abs(abs(d1)-PI) < 1e-9 else 'no'}   ({d1/PI:+.4f} pi)")
    print(f"    monopole unit sum (must be 1.0)    {unit_sum(0):.12f}")
    print(f"    duty fraction 1/psi                {1/PSI:.6e}")
    print(f"    holonomy closes (S even)?          "
          f"{'YES' if admissible() else 'NO'}   S = {turn_sum()}")
    import itertools as _it
    zero = [n for n in _it.product(range(-2, 3), repeat=3)
            if sum(n) % 2 == 0 and 3*n[2] - sum(n) == 0]
    print(f"    zero-precession triples exist?     "
          f"{'YES' if zero else 'no'}  ({len(zero)} within |n|<=2, e.g. {zero[0] if zero else '-'})")


# ----------------------------------------------------------------------
# PLOTS
# ----------------------------------------------------------------------
def plot_planck_tau(path="fig1_planck_tau.png"):
    """ONE tau-cycle: the anatomy of a single loop.

    Three panels, all intra-cycle quantities. tau RESETS every cycle, so
    a second cycle here would be pixel-identical to the first -- it would
    duplicate the content and halve the horizontal resolution of what is
    being shown. The two-cycle RETURN is a different claim and lives in
    its own figure (plot_two_cycle_return), placed next to the spin-1/2
    argument that depends on it.
    """
    import matplotlib; matplotlib.use("Agg")
    import matplotlib.pyplot as plt
    import numpy as np

    us = np.linspace(0, 1, 500)
    fig, axs = plt.subplots(1, 3, figsize=(15, 4.6), facecolor="white")
    ax = [axs]                       # keep the ax[0][j] indexing below

    ax[0][0].plot(us, [tau_of(u) for u in us], color="#c0392b", lw=2)
    ax[0][0].axhline(math.e, ls="--", color="gray", lw=1)
    ax[0][0].set_title("(a) $\\tau = e^{u}$ over one loop\n"
                       "$u=\\ln\\tau$ runs 0 to 1, so $\\tau$ runs 1 to $e$", fontsize=10)
    ax[0][0].set_xlabel("$u$"); ax[0][0].set_ylabel("$\\tau$")

    ax[0][1].plot(us, [amplitude(u) for u in us], color="#2980b9", lw=2)
    ax[0][1].axhline(OMEGA, ls=":", color="gray"); ax[0][1].axhline(OMEGA**2, ls="--", color="gray")
    ax[0][1].set_title(f"(b) amplitude $A=\\Omega^{{\\ln\\tau+1}}$\n"
                       f"$\\Omega$={OMEGA:.4f} to $\\Omega^2$={OMEGA**2:.4f}: GAIN is $\\Omega$",
                       fontsize=10)
    ax[0][1].set_xlabel("$u$"); ax[0][1].set_ylabel("$A$")

    ax[0][2].plot(us, [tau_phase(u) for u in us], color="#8e44ad", lw=2, label="$\\phi=\\pi\\ln\\tau$")
    ax[0][2].plot(us, [standing_wave(u) for u in us], color="#16a085", lw=2,
                  label="$w=\\sin(\\pi\\ln\\tau)$")
    ax[0][2].axhline(PI, ls="--", color="gray", lw=1)
    ax[0][2].set_title("(c) phase and standing wave\n"
                       "phase reaches $\\pi$, NOT $2\\pi$ -- the half-cycle", fontsize=10)
    ax[0][2].set_xlabel("$u$"); ax[0][2].legend(fontsize=9)

    for a in axs:
        a.grid(alpha=0.25)
    fig.suptitle("The Planck ($\\tau$) loop: anatomy of ONE cycle", fontsize=13)
    fig.tight_layout()
    fig.savefig(path, dpi=130); print(f"  saved {path}")


def plot_two_cycle_return(path="fig1b_two_cycle_return.png"):
    """TWO cycles of Psi in the complex plane -- a separate figure.

    This carries one claim: the state reaches -Omega^2 after one cycle
    and returns to +Omega^2 only after two. It is the load-bearing
    result for spin-1/2 and belongs next to that argument, not among the
    intra-cycle panels of fig1, whose time base is different.

    The radial JUMP at the cycle boundary is not an artefact: the
    amplitude resets (tau restarts) while the accumulated phase carries.
    Without that carry every closure would give -Omega^2 and nothing
    would ever return.
    """
    import matplotlib; matplotlib.use("Agg")
    import matplotlib.pyplot as plt
    import numpy as np

    fig, ax = plt.subplots(figsize=(7.2, 6.6), facecolor="white")

    def psi2(c):
        u = c - math.floor(c)
        if u == 0.0 and c > 0:
            u = 1.0
        a = OMEGA**(u + 1.0)
        p = PI*c
        return a*math.cos(p), a*math.sin(p)

    for lo, hi, col, lab in [(0.0, 1.0, "#d35400", "cycle 1: upper half-plane"),
                             (1.0, 2.0, "#2980b9", "cycle 2: lower half-plane")]:
        cs = np.linspace(lo, hi, 800)
        pts = [psi2(c) for c in cs]
        ax.plot([p[0] for p in pts], [p[1] for p in pts],
                color=col, lw=2.4, label=lab)

    # the reset jump, drawn explicitly rather than left as a gap
    xa, ya = psi2(1.0)                 # end of cycle 1, at -Omega^2
    xb, yb = psi2(1.0 + 1e-12)         # start of cycle 2, at -Omega
    ax.annotate("", xy=(xb, yb - 0.28), xytext=(xa, ya - 0.28),
                arrowprops=dict(arrowstyle="-|>", color="#444444", lw=1.8))
    ax.text((xa + xb)/2, ya - 1.5,
            "amplitude resets $\\Omega^2\\!\\to\\!\\Omega$\n"
            "phase carries: no reset",
            fontsize=8.5, ha="center", va="top", color="#333333",
            bbox=dict(boxstyle="round,pad=0.35", facecolor="white",
                      edgecolor="#bbbbbb", alpha=0.95))

    ax.scatter([OMEGA], [0], s=90, color="green", zorder=5,
               label="$\\Psi(0)=+\\Omega$")
    ax.scatter([-OMEGA**2], [0], s=170, marker="*", color="red", zorder=5,
               label="after 1 cycle: $-\\Omega^2$")
    ax.scatter([OMEGA**2], [0], s=170, marker="*", color="darkgreen", zorder=5,
               label="after 2 cycles: $+\\Omega^2$")
    ax.axhline(0, color="gray", lw=0.6); ax.axvline(0, color="gray", lw=0.6)
    lim = OMEGA**2*1.2
    ax.set_xlim(-lim, lim); ax.set_ylim(-lim, lim)
    ax.set_aspect("equal"); ax.grid(alpha=0.25)
    ax.legend(fontsize=8, loc="lower right")
    ax.set_xlabel("Re"); ax.set_ylabel("Im")
    ax.set_title("$\\Psi = A\\,e^{i\\phi}$ over TWO $\\tau$-cycles\n"
                 "one cycle advances the phase by $\\pi$, so two are needed"
                 " to return", fontsize=11)
    fig.tight_layout()
    fig.savefig(path, dpi=140); print(f"  saved {path}")


def plot_branch(path="fig2_branch.png"):
    import matplotlib; matplotlib.use("Agg")
    import matplotlib.pyplot as plt
    import numpy as np

    ks = np.linspace(0, 2*PSI, 1200)
    fig, ax = plt.subplots(2, 2, figsize=(13, 9), facecolor="white")

    cols = ["#c0392b", "#27ae60", "#2980b9"]
    for j in range(3):
        ax[0][0].plot(ks/PSI, [branch_phases(k)[j]/PI for k in ks],
                      color=cols[j], lw=2, label=f"$\\phi_{j+1}$  ($n_{j+1}$={TURNS[j]})")
    ax[0][0].axhline(1, ls="--", color="gray"); ax[0][0].axhline(2, ls="--", color="gray")
    ax[0][0].set_title("(a) the three monopole phases\n"
                       f"rate $n_j\\pi$ per cycle; $n$={TURNS}, sum={sum(TURNS)} (even)",
                       fontsize=10)
    ax[0][0].set_xlabel("branch cycles"); ax[0][0].set_ylabel("phase / $\\pi$")
    ax[0][0].legend(fontsize=9)

    # The spinor sign is carried by Delta (the N-S azimuth), NOT by
    # phi_3. An earlier version plotted cos(phi_3), which is identically
    # 1 whenever n3 = 0 -- so the curve sat flat at +1 while the markers
    # claimed -1 at one cycle. Delta advances pi per cycle for any
    # admissible triple, so cos(Delta) is the sign for all of them.
    ax[0][1].plot(ks/PSI, [math.cos(branch_delta(k)) for k in ks],
                  color="#8e44ad", lw=2)
    ax[0][1].axhline(1, ls=":", color="gray"); ax[0][1].axhline(-1, ls=":", color="gray")
    ax[0][1].scatter([1], [-1], s=150, color="red", zorder=5, label="$-\\xi$ at 1 cycle")
    ax[0][1].scatter([2], [1], s=150, marker="*", color="green", zorder=5,
                     label="$+\\xi$ at 2 cycles")
    ax[0][1].set_title("(b) spinor sign $=\\cos\\Delta$\n"
                       "state returns to $-\\xi$, then $+\\xi$", fontsize=10)
    ax[0][1].set_xlabel("branch cycles"); ax[0][1].legend(fontsize=9)

    ax[1][0].plot(ks/PSI, [branch_delta(k)/PI for k in ks], color="#d35400", lw=2)
    ax[1][0].axhline(2, ls="--", color="gray", label="$2\\pi$: N-S axis returns")
    ax[1][0].set_title(f"(c) N-S azimuth $\\Delta$\n"
                       f"precession {precession():+.2f} turns/cycle -> "
                       f"{abs(1/precession()):.0f} cycles", fontsize=10)
    ax[1][0].set_xlabel("branch cycles"); ax[1][0].set_ylabel("$\\Delta/\\pi$")
    ax[1][0].legend(fontsize=9)

    kk = np.linspace(0, 2*PSI, 400)
    ax[1][1].plot(kk/PSI, [unit_sum(k) for k in kk], color="#16a085", lw=2)
    ax[1][1].axhline(1.0, ls="--", color="gray")
    ax[1][1].set_ylim(0.9, 1.1)
    ax[1][1].set_title("(d) monopole unit sum\n"
                       "exactly 1 throughout (symmetric triplet, no field)", fontsize=10)
    ax[1][1].set_xlabel("branch cycles"); ax[1][1].set_ylabel("$|\\sum m_i|$")
    for a in ax.flat:
        a.grid(alpha=0.25)
    fig.suptitle(f"The branch loop -- ONE $\\tau$ loop stretched over "
                 f"$\\psi$={PSI:,.0f} ticks", fontsize=13)
    fig.tight_layout()
    fig.savefig(path, dpi=130); print(f"  saved {path}")


def plot_integration(path="fig3_spiral_branch.png"):
    import matplotlib; matplotlib.use("Agg")
    import matplotlib.pyplot as plt
    import numpy as np

    fig, ax = plt.subplots(1, 3, figsize=(16, 5.2), facecolor="white")

    ts = np.logspace(0, math.log10(BRANCH_CLOSE*1.3), 400)
    ax[0].loglog(ts, [spiral_radius(t) for t in ts], color="#2980b9", lw=2)
    ax[0].axvline(BRANCH_OPEN, color="gold", lw=2, label=f"branch opens t={BRANCH_OPEN}")
    ax[0].axvline(BRANCH_CLOSE, color="darkgreen", lw=2, ls="--",
                  label=f"closes t={BRANCH_CLOSE:,.0f}")
    ax[0].set_title("(a) spiral radius $\\sqrt{t}$\nbranch span marked", fontsize=10)
    ax[0].set_xlabel("t (spiral ticks)"); ax[0].set_ylabel("radius / $\\ell_P$")
    ax[0].legend(fontsize=8); ax[0].grid(alpha=0.25, which="both")

    tt = np.linspace(1, 60, 2000)
    pts = [spiral_xy(t) for t in tt]
    ax[1].plot([p[0] for p in pts], [p[1] for p in pts], color="#b0c4de", lw=1.5)
    x0, y0 = spiral_xy(BRANCH_OPEN)
    ax[1].scatter([x0], [y0], s=160, color="gold", edgecolors="black", zorder=5,
                  label=f"branch opens (t={BRANCH_OPEN})")
    for t in range(1, 61, 5):
        x, y = spiral_xy(t)
        ax[1].scatter([x], [y], s=12, color="#4a76b8", zorder=3)
    ax[1].set_aspect("equal"); ax[1].grid(alpha=0.25)
    ax[1].set_title("(b) the spiral near the branch origin\n"
                    "(t=1..60; the full span is unplottable)", fontsize=10)
    ax[1].set_xlabel("Re"); ax[1].set_ylabel("Im"); ax[1].legend(fontsize=8)

    cyc = np.linspace(0, 3, 600)
    duty = [(1.0 if abs(c - round(c)) < 0.004 and c > 0 else 0.0) for c in cyc]
    ax[2].fill_between(cyc, 0, [1-d for d in duty], color="#5dade2", alpha=0.4,
                       label="wave-state (massless)")
    ax[2].fill_between(cyc, 0, duty, color="#c0392b", alpha=0.9,
                       label="point-state ($m_P$, 1 tick)")
    ax[2].set_ylim(0, 1.4); ax[2].set_xlabel("branch cycles")
    ax[2].set_title(f"(c) duty cycle\n1 tick in {PSI:,.0f} -> "
                    f"$m/m_P$={1/PSI:.2e}", fontsize=10)
    ax[2].legend(fontsize=8, loc="upper center"); ax[2].grid(alpha=0.25)

    fig.suptitle("Spiral and branch integrated", fontsize=13)
    fig.tight_layout()
    fig.savefig(path, dpi=130); print(f"  saved {path}")


if __name__ == "__main__":
    diagnostics()
    print("\n  PLOTS")
    plot_planck_tau()
    plot_two_cycle_return()
    plot_branch()
    plot_integration()