{
// Line 1 (fixed): x + 2y = 4 → y = −0.5x + 2
const m1 = -0.5, b1 = 2;
const m2 = geomSlope, b2 = geomIntercept;
const EPS_S = 0.03; // slope tolerance (slider step is 0.05)
const EPS_B = 0.06; // intercept tolerance (slider step is 0.1)
const sameSlope = Math.abs(m2 - m1) < EPS_S;
const coincident = sameSlope && Math.abs(b2 - b1) < EPS_B;
const parallel = sameSlope && !coincident;
let caseLabel, caseColor;
if (coincident) {
caseLabel = "Infinitely many solutions — same line";
caseColor = "#059669";
} else if (parallel) {
caseLabel = "No solution — parallel lines (0 = c, impossible)";
caseColor = "#dc2626";
} else {
const xi = (b2 - b1) / (m1 - m2);
const yi = m1 * xi + b1;
caseLabel = `Unique solution — intersection at (${xi.toFixed(2)}, ${yi.toFixed(2)})`;
caseColor = "#2563eb";
}
const W = 340, H = 280, PAD = 44;
const xMin = -5, xMax = 5, yMin = -3, yMax = 6;
const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
svg.setAttribute("width", W);
svg.setAttribute("height", H);
svg.setAttribute("viewBox", `0 0 ${W} ${H}`);
svg.style.cssText = "display:block;font-family:inherit;border:1px solid #e5e7eb;border-radius:6px;";
const ns = "http://www.w3.org/2000/svg";
function mk(tag, attrs) {
const e = document.createElementNS(ns, tag);
if (attrs) for (const [k, v] of Object.entries(attrs)) e.setAttribute(k, v);
return e;
}
function mkT(tag, attrs, text) { const e = mk(tag, attrs); e.textContent = text; return e; }
function spx(x) { return PAD + (x - xMin) / (xMax - xMin) * (W - 2 * PAD); }
function spy(y) { return H - PAD - (y - yMin) / (yMax - yMin) * (H - 2 * PAD); }
const clipId = "geom-clip";
const defs = mk("defs");
const cp = mk("clipPath", { id: clipId });
cp.appendChild(mk("rect", { x: PAD, y: PAD, width: W - 2*PAD, height: H - 2*PAD }));
defs.appendChild(cp);
svg.appendChild(defs);
svg.appendChild(mk("rect", { x: 0, y: 0, width: W, height: H, fill: "#f9fafb", rx: 6 }));
svg.appendChild(mk("rect", { x: PAD, y: PAD, width: W-2*PAD, height: H-2*PAD, fill: "#fff", stroke: "#e5e7eb", "stroke-width": 1 }));
// Grid
const gridG = mk("g", { "clip-path": `url(#${clipId})` });
for (let x = Math.ceil(xMin); x <= Math.floor(xMax); x++)
gridG.appendChild(mk("line", { x1: spx(x), y1: PAD, x2: spx(x), y2: H-PAD, stroke: "#f3f4f6", "stroke-width": 1 }));
for (let y = Math.ceil(yMin); y <= Math.floor(yMax); y++)
gridG.appendChild(mk("line", { x1: PAD, y1: spy(y), x2: W-PAD, y2: spy(y), stroke: "#f3f4f6", "stroke-width": 1 }));
svg.appendChild(gridG);
// Axes
const clip = { "clip-path": `url(#${clipId})` };
svg.appendChild(mk("line", { x1: PAD, y1: spy(0), x2: W-PAD, y2: spy(0), stroke: "#d1d5db", "stroke-width": 1.5, ...clip }));
svg.appendChild(mk("line", { x1: spx(0), y1: PAD, x2: spx(0), y2: H-PAD, stroke: "#d1d5db", "stroke-width": 1.5, ...clip }));
svg.appendChild(mkT("text", { x: W-PAD+6, y: spy(0)+4, fill: "#9ca3af", "font-size": 12 }, "x"));
svg.appendChild(mkT("text", { x: spx(0)+5, y: PAD-4, fill: "#9ca3af", "font-size": 12 }, "y"));
function addLine(m, b, color, dash, width, opacity) {
svg.appendChild(mk("line", {
x1: spx(xMin), y1: spy(m*xMin+b),
x2: spx(xMax), y2: spy(m*xMax+b),
stroke: color, "stroke-width": width,
"stroke-dasharray": dash || "",
opacity: opacity || 1,
"clip-path": `url(#${clipId})`
}));
}
// Line 1 — fixed, solid blue
addLine(m1, b1, "#3b82f6", "", 2.5, 1);
const lx1 = 2.5;
svg.appendChild(mkT("text", { x: spx(lx1)+4, y: spy(m1*lx1+b1)-5, fill: "#3b82f6", "font-size": 11, "font-weight": "600" }, "x + 2y = 4"));
// Line 2 — controlled
if (coincident) {
addLine(m2, b2, "#059669", "8 4", 5, 0.55);
} else {
addLine(m2, b2, "#f59e0b", parallel ? "" : "7 4", 2.5, 1);
// Label line 2 near its left end
const lx2 = -3.5, ly2 = m2*lx2+b2;
if (ly2 >= yMin && ly2 <= yMax)
svg.appendChild(mkT("text", { x: spx(lx2), y: spy(ly2)-6, fill: "#f59e0b", "font-size": 11, "font-weight": "600" }, "line 2"));
}
// Intersection dot
if (!parallel && !coincident) {
const xi = (b2 - b1) / (m1 - m2);
const yi = m1 * xi + b1;
if (xi >= xMin && xi <= xMax && yi >= yMin && yi <= yMax)
svg.appendChild(mk("circle", { cx: spx(xi), cy: spy(yi), r: 5, fill: "#2563eb", stroke: "#fff", "stroke-width": 2 }));
}
const footer = document.createElement("div");
footer.style.cssText = `font-size:0.88em;font-weight:600;color:${caseColor};margin-top:0.4rem;`;
footer.textContent = caseLabel;
const container = document.createElement("div");
container.style.marginTop = "0.5rem";
container.append(svg, footer);
return container;
}