diff --git a/crates/engine/src/cmd/curves.rs b/crates/engine/src/cmd/curves.rs
--- a/crates/engine/src/cmd/curves.rs
+++ b/crates/engine/src/cmd/curves.rs
@@ -344,6 +344,11 @@ fn eq_variants(o: &TanObj) -> Vec<Eq3> {
 
 /// Circle tangent to three objects, nearest the pick points (Newton on all sign combinations).
 pub fn ttt(objs: [(TanObj, Vec2); 3]) -> Option<Circle> {
+    ttt_where(objs, |_| true)
+}
+
+/// [`ttt`] among the circles `ok` accepts.
+pub fn ttt_where(objs: [(TanObj, Vec2); 3], ok: impl Fn(&Circle) -> bool) -> Option<Circle> {
     let [(o1, p1), (o2, p2), (o3, p3)] = objs;
     let mut starts: Vec<[f64; 3]> = Vec::new();
     let cen = (p1 + p2 + p3) / 3.0;
@@ -380,6 +385,9 @@ pub fn ttt(objs: [(TanObj, Vec2); 3]) -> Option<Circle> {
                         continue;
                     }
                     let c = Circle::new(Vec2::new(x[0], x[1]), x[2]);
+                    if !ok(&c) {
+                        continue;
+                    }
                     let sc = score(&c, &objs);
                     if best.is_none_or(|(b, _)| sc < b - 1e-12) {
                         best = Some((sc, c));
diff --git a/crates/engine/src/cmd/draw.rs b/crates/engine/src/cmd/draw.rs
--- a/crates/engine/src/cmd/draw.rs
+++ b/crates/engine/src/cmd/draw.rs
@@ -740,6 +740,8 @@ impl Interactive for PlineM {
 struct CircleM {
     mode: u8, // 0 center-radius, 1 = 3P, 2 = 2P, 3 = TTR
     pts: Vec<Vec2>,
+    /// 3P: the circle or arc each point was picked on with a tangent snap, by point.
+    tans: Vec<Option<snap::SnapCurve>>,
     diameter: bool,
     /// The `Ttr` option hands over to the tangent-circle machine.
     delegate: Option<Box<dyn Interactive>>,
@@ -758,18 +760,22 @@ impl Interactive for CircleM {
         match (self.mode, n) {
             (0, 0) => Prompt::new("Specify center point for circle", Accept::POINT).kw(&["3P", "2P", "Ttr (tan tan radius)"]),
             (0, _) if self.diameter => {
-                Prompt::new("Specify diameter of circle", Accept::POINT_OR_NUMBER).base_opt(self.pts.first().copied()).distance()
+                Prompt::new("Specify diameter of circle", Accept::POINT_OR_NUMBER).base_opt(self.pts.first().copied()).distance().deferred()
             }
             (0, _) => {
-                let p =
-                    Prompt::new("Specify radius of circle", Accept::POINT_OR_NUMBER).kw(&["Diameter"]).base_opt(self.pts.first().copied()).distance();
+                let p = Prompt::new("Specify radius of circle", Accept::POINT_OR_NUMBER)
+                    .kw(&["Diameter"])
+                    .base_opt(self.pts.first().copied())
+                    .distance()
+                    .deferred();
                 if last_r > 0.0 { p.default(format!("{last_r:.4}")) } else { p }
             }
             (1, k) => Prompt::new(
                 ["Specify first point on circle", "Specify second point on circle", "Specify third point on circle"].get(k).copied().unwrap_or(""),
                 Accept::POINT,
             )
-            .base_opt(self.pts.last().copied()),
+            .base_opt(self.pts.last().copied())
+            .deferred(),
             (2, k) => Prompt::new(
                 if k == 0 { "Specify first end point of circle's diameter" } else { "Specify second end point of circle's diameter" },
                 Accept::POINT,
@@ -809,7 +815,14 @@ impl Interactive for CircleM {
                         let r = if self.diameter { c.dist(*e) / 2.0 } else { c.dist(*e) };
                         Some(Circle::new(*c, r))
                     }
-                    1 if self.pts.len() == 3 => Circle::from_3_points(self.pts[0], self.pts[1], self.pts[2]),
+                    1 if self.pts.len() == 3 => match self.three_points() {
+                        Some(c) => Some(c),
+                        None => {
+                            self.pts.pop();
+                            self.tans.truncate(self.pts.len());
+                            return Err(crate::EngineError::Other("Circle does not exist.".into()));
+                        }
+                    },
                     2 if self.pts.len() == 2 => Some(Circle::from_2_points(self.pts[0], self.pts[1])),
                     _ => None,
                 };
@@ -819,6 +832,29 @@ impl Interactive for CircleM {
                 }
                 Ok(Step::Continue)
             }
+            // 3P: a point picked with a tangent snap makes the circle tangent to that curve (#1512).
+            Input::Deferred(d) if self.mode == 1 => {
+                let tan = (d.mode == snap::mode::TAN && !matches!(d.curve, snap::SnapCurve::Line { .. })).then_some(d.curve);
+                self.tans.resize(self.pts.len(), None);
+                self.tans.push(tan);
+                self.input(s, Input::Point(d.at))
+            }
+            // A tangent picked for the radius: the circle around the center that touches the
+            // curve, on the side it was picked (#1512).
+            Input::Deferred(d) if self.mode == 0 && self.pts.len() == 1 => {
+                let Some(&c) = self.pts.first() else { return Ok(Step::Continue) };
+                // Around the picked curve's own center the circle would lie on it, not touch it.
+                let concentric =
+                    matches!(d.curve, snap::SnapCurve::Circle { center, .. } | snap::SnapCurve::Arc { center, .. } if center.near(c, 1e-9));
+                let touch = d.curve.perpendiculars(c, d.at).into_iter().filter(|_| !concentric).min_by(|a, b| a.dist(d.at).total_cmp(&b.dist(d.at)));
+                match touch.map(|t| c.dist(t)).filter(|r| *r > 1e-12 && r.is_finite()) {
+                    Some(r) => {
+                        finish_circle(s, Circle::new(c, r))?;
+                        Ok(Step::Done)
+                    }
+                    None => Err(crate::EngineError::Other("No circle around the center is tangent there.".into())),
+                }
+            }
             Input::Text(t) if self.mode == 0 && self.pts.len() == 1 => {
                 let v = number(&t).ok_or_else(|| crate::EngineError::Other("Requires numeric distance or second point.".into()))?;
                 let r = if self.diameter { v / 2.0 } else { v };
@@ -863,6 +899,38 @@ impl Interactive for CircleM {
     }
 }
 
+impl CircleM {
+    /// The 3P circle: through the three points, or tangent to the curves picked with TAN.
+    fn three_points(&self) -> Option<Circle> {
+        let [a, b, c] = <[Vec2; 3]>::try_from(self.pts.as_slice()).ok()?;
+        if self.tans.iter().all(Option::is_none) {
+            return Circle::from_3_points(a, b, c);
+        }
+        let tan = |i: usize| self.tans.get(i).copied().flatten();
+        // A plain point is a circle of radius zero to pass through; an arc is solved as its circle.
+        let target = |i: usize, p: Vec2| {
+            let circle = match tan(i) {
+                Some(snap::SnapCurve::Circle { center, radius } | snap::SnapCurve::Arc { center, radius, .. }) => Circle::new(center, radius),
+                _ => Circle::new(p, 0.0),
+            };
+            super::curves::TanObj::Circle(circle)
+        };
+        let pts = [a, b, c];
+        // The circle must touch an arc within its sweep, not elsewhere on the arc's circle, and
+        // not be the picked circle itself (which lies on it rather than touching it).
+        let touches = |found: &Circle| {
+            pts.iter().enumerate().all(|(i, p)| {
+                tan(i).is_none_or(|t| {
+                    let same = matches!(target(i, *p), super::curves::TanObj::Circle(o)
+                        if o.center.dist(found.center) + (o.radius - found.radius).abs() <= 1e-9 * o.radius);
+                    !same && t.contains(target(i, *p).touch(found))
+                })
+            })
+        };
+        super::curves::ttt_where([(target(0, a), a), (target(1, b), b), (target(2, c), c)], touches)
+    }
+}
+
 fn finish_circle(s: &mut Session, c: Circle) -> Result<()> {
     s.add_entity(circle(c.center, c.radius))?;
     s.doc_mut()?.header.set_f64("CIRCLERAD", c.radius);
diff --git a/crates/engine/src/prompt.rs b/crates/engine/src/prompt.rs
--- a/crates/engine/src/prompt.rs
+++ b/crates/engine/src/prompt.rs
@@ -38,8 +38,9 @@ pub struct Prompt {
     /// Rubber-band origin (for direct distance entry, ortho and polar).
     pub base: Option<Vec2>,
     /// The command resolves deferred tangent/perpendicular snaps ([`Input::Deferred`]) at this
-    /// prompt (a point with no base yet, e.g. the first point of a line). Elsewhere a deferred
-    /// pick arrives as the plain point it was picked at.
+    /// prompt (a point with no base yet, e.g. the first point of a line; with a base, only
+    /// tangents, e.g. a circle's radius). Elsewhere a deferred pick arrives as the plain point it
+    /// was picked at.
     pub deferred: bool,
     /// The base is a rectangle's first corner (ZOOM Window, RECTANG, ARRAYRECT's unit cell): ortho
     /// does not bend the opposite corner, so the rectangle keeps its area.
diff --git a/crates/engine/src/snap.rs b/crates/engine/src/snap.rs
--- a/crates/engine/src/snap.rs
+++ b/crates/engine/src/snap.rs
@@ -110,7 +110,7 @@ impl SnapCurve {
     }
     /// Points on the curve whose perpendicular passes through `p`; `picked` is where the curve
     /// was picked, kept when `p` is the center of a circle or arc (every radius is perpendicular).
-    fn perpendiculars(&self, p: Vec2, picked: Vec2) -> Vec<Vec2> {
+    pub(crate) fn perpendiculars(&self, p: Vec2, picked: Vec2) -> Vec<Vec2> {
         match self {
             SnapCurve::Circle { center, radius } | SnapCurve::Arc { center, radius, .. } => {
                 let u = (p - *center).normalized();
@@ -202,7 +202,9 @@ fn prim_segments(p: &Prim) -> Vec<Segment> {
 /// Tangent and perpendicular snaps need the base point (the other end of the line). With no
 /// base and `deferred` set (the prompt says it can resolve them, `Prompt.deferred`),
 /// they snap as *deferred*: the hit carries the curve and is resolved once the other end is
-/// known. Deferred hits only win where no other snap does (they are as unspecific as Nearest).
+/// known. With a base and `deferred` set, tangents to circles and arcs are deferred too (CIRCLE's
+/// radius: the circle around the base that touches the curve, #1512). Deferred hits only win
+/// where no other snap does (they are as unspecific as Nearest).
 pub fn osnap(d: &Drawing, space: &Space, cursor: Vec2, aperture: f64, osmode: u32, base: Option<Vec2>, deferred: bool) -> Option<SnapHit> {
     if osmode == 0 || osmode & mode::OFF != 0 {
         return None;
@@ -491,6 +493,8 @@ fn finish(
             }
             if osmode & mode::TAN != 0 {
                 let pts = match p {
+                    // A deferred prompt resolves tangents to circles and arcs itself.
+                    Prim::Seg(Segment::Arc { .. }) | Prim::Circle(_) if deferred => Vec::new(),
                     // Only the tangent points that lie on the arc itself (not its circle).
                     Prim::Seg(Segment::Arc { arc, .. }) => Circle::new(arc.center, arc.radius)
                         .tangent_points(bp)
@@ -516,10 +520,9 @@ fn finish(
     if let Some((m, p)) = best {
         return Some(SnapHit { point: *p, mode: *m, name: name_of(*m), viewport: None, deferred: None });
     }
-    if base.is_none()
-        && deferred
-        && let Some(h) = deferred_hit(near_prims, cursor, aperture, osmode, clip)
-    {
+    // With a base, perpendiculars are resolved from it above; only tangents are left to defer.
+    let deferrable = if base.is_some() { osmode & mode::TAN } else { osmode };
+    if deferred && let Some(h) = deferred_hit(near_prims, cursor, aperture, deferrable, clip) {
         return Some(h);
     }
     if osmode & mode::NEA != 0 {
@@ -1171,9 +1174,14 @@ mod tests {
         let df = h.deferred.unwrap();
         assert_eq!(df.curve, SnapCurve::Circle { center: Vec2::new(20.0, 0.0), radius: 2.0 });
         assert_eq!(h.input(), crate::Input::Deferred(df));
-        // With a base it is an ordinary tangent.
-        let t = osnap(&d, &Space::Model, Vec2::new(19.9, 1.9), 1.0, mode::TAN, Some(Vec2::new(10.0, 0.0)), true).unwrap();
+        // With a base it is an ordinary tangent, unless the prompt resolves it (CIRCLE's radius).
+        let t = osnap(&d, &Space::Model, Vec2::new(19.9, 1.9), 1.0, mode::TAN, Some(Vec2::new(10.0, 0.0)), false).unwrap();
         assert!(t.deferred.is_none() && t.name == "Tangent");
+        let t = osnap(&d, &Space::Model, at, 0.5, mode::TAN, Some(Vec2::new(10.0, 0.0)), true).unwrap();
+        assert_eq!(t.name, "Deferred Tangent");
+        // A perpendicular from the base is still resolved from it.
+        let p = osnap(&d, &Space::Model, Vec2::new(2.0, 0.2), 0.5, mode::PER, Some(Vec2::new(2.0, 5.0)), true).unwrap();
+        assert!(p.deferred.is_none() && p.point.near(Vec2::new(2.0, 0.0), 1e-9));
         // A specific snap still wins over a deferred one.
         let q = osnap(&d, &Space::Model, at, 0.5, mode::TAN | mode::QUA, None, true).unwrap();
         assert_eq!(q.mode, mode::QUA);
diff --git a/crates/engine/tests/it/snap_curves.rs b/crates/engine/tests/it/snap_curves.rs
--- a/crates/engine/tests/it/snap_curves.rs
+++ b/crates/engine/tests/it/snap_curves.rs
@@ -70,6 +70,9 @@ fn elliptical_arc_perpendicular_and_tangent_from_a_base_point() {
     let (q, m) = along_quarter(&s, mode::TAN, Some(base)).expect("a tangent point on the arc");
     assert_eq!(m, mode::TAN);
     assert!(on_quarter(q) && Vec2::new(q.x / 16.0, q.y / 4.0).dot(q - base).abs() < 1e-9, "{q:?}");
+    // The same tangent at a prompt that resolves deferred snaps (CIRCLE's 3P points, #1512).
+    let h = snap::osnap(s.doc().unwrap(), &Space::Model, q, 0.3, mode::TAN, Some(base), true).expect("tangent at a deferred prompt");
+    assert!(h.mode == mode::TAN && h.deferred.is_none() && h.point.near(q, 1e-9), "{h:?}");
     // Perpendicular from (10,10): the line from the base runs along the normal.
     let base = Vec2::new(10.0, 10.0);
     let (q, m) = along_quarter(&s, mode::PER, Some(base)).expect("a perpendicular foot on the arc");
diff --git a/crates/engine/tests/it/snap_overrides.rs b/crates/engine/tests/it/snap_overrides.rs
--- a/crates/engine/tests/it/snap_overrides.rs
+++ b/crates/engine/tests/it/snap_overrides.rs
@@ -21,6 +21,17 @@ fn last_line(s: &Session) -> (Vec2, Vec2) {
     s.doc().unwrap().model.iter().filter_map(|e| if let EntityKind::Line(l) = &e.kind { Some((l.a.xy(), l.b.xy())) } else { None }).last().unwrap()
 }
 
+/// The last circle drawn as (center, radius).
+fn last_circle(s: &Session) -> (Vec2, f64) {
+    s.doc()
+        .unwrap()
+        .model
+        .iter()
+        .filter_map(|e| if let EntityKind::Circle(c) = &e.kind { Some((c.center.xy(), c.radius)) } else { None })
+        .last()
+        .unwrap()
+}
+
 fn near(p: Vec2, x: f64, y: f64) -> bool {
     p.near(Vec2::new(x, y), 1e-9)
 }
@@ -116,3 +127,86 @@ fn a_command_keyword_wins_over_a_snap_word() {
     s.cmdline("arc _cen").unwrap();
     assert!(s.prompt_text().ends_with("Center of:"), "{}", s.prompt_text());
 }
+
+#[test]
+fn tan_for_a_circle_radius_touches_the_picked_circle() {
+    // #1512: the circle around the center that touches the circle at 20,20 radius 3, on the side
+    // it was picked: the near side (radius 7), the far side (13), and through Diameter.
+    for (script, center, r) in [
+        ("CIRCLE 30,20 TAN 23.02,20.03\n", (30.0, 20.0), 7.0),
+        ("CIRCLE 30,20 TAN 16.98,19.97\n", (30.0, 20.0), 13.0),
+        ("CIRCLE 20,10 D TAN 20.03,17.02\n", (20.0, 10.0), 7.0),
+    ] {
+        let mut s = drawing();
+        s.script(script).unwrap();
+        assert!(s.running.is_none(), "{script}: {}", s.prompt_text());
+        let (c, got) = last_circle(&s);
+        assert!(near(c, center.0, center.1) && (got - r).abs() < 1e-9, "{script}: {c:?} r={got}");
+    }
+}
+
+#[test]
+fn tan_for_a_3p_circle_touches_the_picked_circles() {
+    // #1512: through two points and tangent to the circle at 20,20 radius 3, the tangent pick
+    // first or last.
+    for script in ["CIRCLE 3P 26,20 26,26 TAN 23.02,20.03\n", "CIRCLE 3P TAN 23.02,20.03 26,20 26,26\n"] {
+        let mut s = drawing();
+        s.script(script).unwrap();
+        assert!(s.running.is_none(), "{script}: {}", s.prompt_text());
+        let (c, r) = last_circle(&s);
+        assert!((c.dist(Vec2::new(26.0, 20.0)) - r).abs() < 1e-9 && (c.dist(Vec2::new(26.0, 26.0)) - r).abs() < 1e-9, "{script}");
+        assert!((c.dist(Vec2::new(20.0, 20.0)) - (3.0 + r)).abs() < 1e-9, "{script}: {c:?} r={r}");
+    }
+    // Tan, Tan, Tan: the circle between three circles of radius 1, picked on their inner sides.
+    let mut s = Session::new();
+    s.script("CIRCLE 0,0 1\nCIRCLE 6,0 1\nCIRCLE 3,5 1\nCIRCLE 3P TAN 0.98,0.2 TAN 5.02,0.2 TAN 3.01,3.98\n").unwrap();
+    assert!(s.running.is_none(), "{}", s.prompt_text());
+    let (c, r) = last_circle(&s);
+    for k in [(0.0, 0.0), (6.0, 0.0), (3.0, 5.0)] {
+        assert!((c.dist(Vec2::new(k.0, k.1)) - (1.0 + r)).abs() < 1e-9, "{c:?} r={r}");
+    }
+}
+
+#[test]
+fn tan_for_a_3p_circle_touches_an_arc_within_its_sweep() {
+    // #1512: through 26,20 and 26,26, the circles tangent to the circle at 20,20 radius 3 touch it
+    // on the right or the far left, both off an arc swept from 90° to 100°: no circle.
+    let mut s = Session::new();
+    s.execute("arc", &serde_json::json!({"center": [20, 20], "radius": 3, "start": 90, "end": 100})).unwrap();
+    s.script("CIRCLE 3P 26,20 26,26 TAN 19.74,22.99\n").unwrap();
+    assert!(s.prompt_text().contains("third point"), "{}", s.prompt_text());
+    assert!(!s.doc().unwrap().model.iter().any(|e| matches!(e.kind, EntityKind::Circle(_))));
+}
+
+#[test]
+fn tan_for_a_3p_circle_takes_the_solution_that_touches_the_arc() {
+    // #1512: through 26,20 and 26,26, the circles tangent to the circle at 20,20 radius 3 touch it
+    // at about 29.6° and -103.3°. Picked at 20° on an arc swept from 200° to 25°, the 29.6°
+    // circle is nearer the pick but off the arc: the -103.3° one (radius 6.0826) is drawn.
+    let mut s = Session::new();
+    s.execute("arc", &serde_json::json!({"center": [20, 20], "radius": 3, "start": 200, "end": 25})).unwrap();
+    s.script("CIRCLE 3P 26,20 26,26 TAN 22.82,21.03\n").unwrap();
+    assert!(s.running.is_none(), "{}", s.prompt_text());
+    let (c, r) = last_circle(&s);
+    assert!((c.dist(Vec2::new(20.0, 20.0)) - (r - 3.0)).abs() < 1e-9 && (r - 6.082575694955838).abs() < 1e-9, "{c:?} r={r}");
+}
+
+#[test]
+fn tan_for_a_circle_radius_refuses_the_picked_circles_own_center() {
+    // #1512: a circle around 20,20 would lie on the circle there, not touch it.
+    let mut s = drawing();
+    s.script("CIRCLE 20,20 TAN 23.02,20.03\n").unwrap();
+    assert!(s.prompt_text().contains("radius of circle"), "{}", s.prompt_text());
+    assert!(s.log.iter().any(|l| l.contains("No circle around the center is tangent there.")), "{:?}", s.log);
+    assert_eq!(s.doc().unwrap().model.iter().filter(|e| matches!(e.kind, EntityKind::Circle(_))).count(), 1);
+}
+
+#[test]
+fn tan_for_a_3p_circle_refuses_the_picked_circle_itself() {
+    // #1512: tangent twice to the circle and through a point on it is only the circle itself.
+    let mut s = drawing();
+    s.script("CIRCLE 3P TAN 23.02,20.03 TAN 16.98,20.03 20,23\n").unwrap();
+    assert!(s.prompt_text().contains("third point"), "{}", s.prompt_text());
+    assert!(s.log.iter().any(|l| l.contains("Circle does not exist.")), "{:?}", s.log);
+    assert_eq!(s.doc().unwrap().model.iter().filter(|e| matches!(e.kind, EntityKind::Circle(_))).count(), 1);
+}
diff --git a/docs/ui-parity.md b/docs/ui-parity.md
--- a/docs/ui-parity.md
+++ b/docs/ui-parity.md
@@ -1,6 +1,6 @@
 # UI parity
 
-> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-22 · **Change:** minor (distinct polyline midpoint grips) · **Target:** Autodesk AutoCAD 2027 for Mac (26.0)
+> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-25 · **Change:** minor (CIRCLE tangent snaps) · **Target:** Autodesk AutoCAD 2027 for Mac (26.0)
 
 How CADCraft's interaction compares with AutoCAD's: point entry, object snaps, tracking, dynamic
 input, grips, selection, the command line, chrome and navigation. A drafter's speed in AutoCAD
@@ -69,7 +69,7 @@ ignored; there are no context menus. Remaining: **≈ 110–170 Opus 5.5 hours**
 | Extension | yes, with dashed extension path | yes: rest on a line or arc end, then the line runs on (a ray) and the arc round its circle; dotted path and "Extension: d < a°" (`snap/tracking.rs`); not from ellipse, spline or polyline-arc ends |
 | Insertion | text, mtext, blocks, attributes, attdefs | TEXT, MTEXT, INSERT; no ATTDEF or MLEADER |
 | Perpendicular | every curve, deferred | lines, arcs, circles, xlines; deferred for the first point (#168) |
-| Tangent | circles, arcs, ellipses, splines, deferred | arcs and circles; deferred for the first point; **no ellipse or spline** |
+| Tangent | circles, arcs, ellipses, splines, deferred | arcs and circles; deferred for the first point and for CIRCLE's radius and 3P points (#1512); **no ellipse or spline** |
 | Nearest | every curve | yes |
 | Apparent intersection | projected intersection | yes in 2D: where objects near the cursor would meet if extended; an object rested on sends its whole extension, so its crossing with another object snaps too (`snap.rs` `osnap_with`, `snap/tracking.rs`) |
 | Parallel | yes, with parallel path | yes: rest on a line, then a path parallel to it runs through the base point (`snap/tracking.rs`) |
@@ -203,6 +203,7 @@ down-arrow options menu (DYNPROMPT), and DYNDIM.
 
 | Date | Change | Summary |
 |---|---|---|
+| 2026-10-25 | minor | CIRCLE takes tangent snaps on circles and arcs (#1512): for the radius or diameter, the circle around the center touches the picked curve on the side it was picked; for 3P points, the circle passes through the plain points and touches the picked curves (Tan, Tan, Tan from three tangent picks) |
 | 2026-10-22 | minor | Polyline segment midpoint grips use rectangles, distinct from square vertex grips, with matching hover and pick bounds (#1950) |
 | 2026-10-13 | minor | Filled-region highlight boundaries are traversed in deterministic coordinate order, fixing dash-phase jumps on CPU hover/selection redraws and GPU highlight rebuilds; CPU dash-position, pixel and GPU mesh regressions |
 | 2026-10-14 | minor | Selection cycling (#1143): the list and badge of SELECTIONCYCLING, Shift+Space through overlapping objects (#1145) |
