from pathlib import Path
import csv
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
from xml.etree import ElementTree as ET
OUT=Path(__file__).resolve().parent
with (OUT/"coordinates.csv").open(encoding="utf-8") as f: rows=list(csv.DictReader(f))
assert [(r["point"],float(r["original_x"]),float(r["original_z"]),float(r["image_x"]),float(r["image_z"])) for r in rows]==[("A",-3,2,-3,-2),("B",1,4,1,-4),("C",3,1,3,-1)]
plt.rcParams.update({"font.family":"DejaVu Sans","svg.fonttype":"none","svg.hashsalt":"mirror-mobile-1","font.size":12.24})
fig=plt.figure(figsize=(3.6,10.7),facecolor="#f3f6ff")
def text(x,y,t,size=18,color="#172b4d",weight="normal"):
 fig.text(x/360,1-y/1070,t,fontsize=size*.72,color=color,weight=weight,va="top",linespacing=1.4)
text(18,22,"What a flat mirror\nchanges",25,weight="bold")
text(18,100,"(x, z) → (x, −z)",21)
text(18,142,"Ideal geometry • arbitrary units",17)
ax=fig.add_axes([.14,.40,.80,.41],facecolor="#f3f6ff")
ax.set_xlim(-4.4,4.4);ax.set_ylim(-5,5);ax.set_aspect("equal")
ax.set_xticks([-4,0,4]);ax.set_yticks([-4,0,4]);ax.tick_params(labelsize=12.24)
for sp in ax.spines.values():sp.set_visible(False)
ax.grid(alpha=.2);ax.axhline(0,color="#172b4d",lw=2);ax.axvline(0,color="#8392a9",lw=.8)
xs=[float(r["original_x"])for r in rows];zs=[float(r["original_z"])for r in rows]
ax.plot(xs+[xs[0]],zs+[zs[0]],color="#235b91",lw=1.5)
ax.plot(xs+[xs[0]],[-v for v in zs+[zs[0]]],color="#8b469c",lw=1.5)
for r,x,z in zip(rows,xs,zs):
 ax.plot([x,x],[z,-z],"--",color="#8392a9",lw=1)
 ax.scatter([x],[z],color="#235b91",s=22,zorder=4);ax.scatter([x],[-z],color="#8b469c",s=22,zorder=4)
 ax.annotate(r["point"],(x,z),xytext=(4,7),textcoords="offset points",fontsize=13,color="#235b91",bbox=dict(facecolor="#f3f6ff",edgecolor="none",pad=.5))
 ax.annotate(r["point"]+"′",(x,-z),xytext=(4,-19),textcoords="offset points",fontsize=13,color="#8b469c",bbox=dict(facecolor="#f3f6ff",edgecolor="none",pad=.5))
text(18,180,"z: perpendicular",17)
text(18,648,"x: parallel to the mirror",17)
text(18,688,"Dark horizontal line: mirror z = 0",17,weight="bold")
text(18,725,"Original → reflected image",18,weight="bold")
text(18,762,"A (−3, 2) → A′ (−3, −2)\nB (1, 4) → B′ (1, −4)\nC (3, 1) → C′ (3, −1)",18)
text(18,852,"Same x coordinate.\nSame distance to mirror.\nThe sign of z reverses.",18,weight="bold")
text(18,946,"Dashed lines pair the points;\nthey are not light rays.",17)
text(18,1005,"Mirror plane shown edge-on.\nNot measured data.\nNot a 3D chirality test.",17,color="#415574")
fig.savefig(OUT/"mirror-reflection-mobile.svg",metadata={"Date":None});fig.savefig(OUT/"mirror-reflection-mobile.png",dpi=200);plt.close(fig)
p=OUT/"mirror-reflection-mobile.svg";tree=ET.parse(p);root=tree.getroot();ns="{http://www.w3.org/2000/svg}"
root.set("role","img");root.set("aria-labelledby","mirror-title mirror-desc")
t=ET.Element(ns+"title",{"id":"mirror-title"});t.text="Flat mirror: x stays the same and z reverses sign"
d=ET.Element(ns+"desc",{"id":"mirror-desc"});d.text="Three original points and three images lie at matching distances above and below z=0; exact coordinate pairs appear beneath. Geometric construction, not measurements or a chirality test."
root.insert(0,d);root.insert(0,t);tree.write(p,encoding="utf-8",xml_declaration=True)
print("Mobile figure generated; CSV read only; minimum equivalent font17 at360 width,15.58 at330.")
