diff --git a/PROJECT.md b/PROJECT.md
index 74f4c8e..d6b03a8 100644
--- a/PROJECT.md
+++ b/PROJECT.md
@@ -5286,6 +5286,43 @@ bekommen."* Two real defects, measured, and neither of them was a balance value:
the rig guard (`> 7 m/s`) moved, to `> legKnee*0.8`. Rungs 1-7 are unchanged: the Steward (6) already
ran 5.6. Ball PACE is untouched; it is at full pace times the league tier from rung 5.
+### Step 3: THE SOFT BALL (2026-10-14, v363)
+**In rally modes the down-flick is SOFT, and its length is HOW FAR**: a flick of `flickMin` is a drop
+(`dropNet` 2 m past the net, low arc), a flick of `flickFull` or more is an attacking lob (`lobDeep` 1.6 m
+inside his line, `lobApex` 5.5 m), with a continuum of floaters in between. It is one gesture with one
+meaning everywhere, which is why it does not repeat the 2026-08-22 cut. Lateral sway still comes from
+the swipe's x. Keys take the lob. `aim.soft` (0..1) lets a caller without a swipe ask for one, which is
+the hook for step 2's opponent.
+- **Ballistics** are the cut lob's (4f4534e). The pace is derived from the apex, so the arc is the same
+ from anywhere. There is no topspin. From the baseline the net-clearance loop lofts a drop to ~2.8 m,
+ which is correct (a 2 m arc from there clips the tape).
+- **Mistiming pulls the target toward `softSitter`** (5.5 m, the service line): a drop that sits up, a
+ lob that falls short. It never goes out by depth.
+- **Backspin: `ball.spin`.** A drop keeps `dropSpin` 0.3 of its pace through the bounce and (`spinLow`)
+ half that loss in height too, so it dies. `bXZ()`/`bY()` are the ONE bounce rule. The physics,
+ `intercept`, `bounceContact` and `matchOutOfReachFlight` all read them; a planner rolling the court
+ numbers would predict a ball that is not there. Netplay sends `spin` with the shot, so both phones
+ bounce it alike (an old build reads 1).
+- **What makes it WIN, measured against the CPU** (a well-timed bot, q >= 0.75). It was ~100% returned
+ until four things went in, each of them real tennis:
+ 1. `softRead` 0.35 s: any opponent stands reading a soft ball, because it is disguised until contact.
+ 2. `netReact` 0.22 s: a net man reads every pass before moving. Without it nothing could pass him.
+ 3. `lobTurn` 0.6: a lobbed net man backpedals.
+ 4. Weak replies. A lobbed net man who runs it down (`rx.lob`) and a drop dug out below `scoopY`
+ 0.45 m (backspin balls only) are capped at `lowVolleyQ`.
+
+ A first cut capped EVERY low contact. Since contact fires on the first frame in reach, that turned
+ every rally ball into a sitter and parked the player at the net, so it was reverted at once.
+- **Result:** a drop played from inside the court wins outright against the slower half of the ladder.
+ Against the rest, a drop or a lob draws a defensive ball back (CPU reply q ~0.40-0.45 against 0.65
+ after a drive) for the player to put away. Rally shape unchanged. A deep lob's high bounce is taken
+ on the RISE when its fall would land past `rallyBehind` (`bounceContact`), otherwise it was unplayable.
+- Tests: drop/lob shape and the lob clearing a net man's racket by 0.5 m, mistimed toward the sitter,
+ the disguise, the lobbed reply cap. 155, fuzzed over 8 seeds. Verified with real touch events in the
+ pane: a short down-swipe is a drop with spin 0.38, a long one a spinless lob.
+- **Not done:** a lesson for the gesture (the ghost hand only teaches the side flick), and a "LOB"/"DROP"
+ word at contact. The arc says it. Add one if the phone test shows nobody finds it.
+
# OPEN — leftovers, in rough priority order
Nothing here is broken; these are known gaps and unverified risks.
diff --git a/index.html b/index.html
index 6a34c97..5ea265f 100644
--- a/index.html
+++ b/index.html
@@ -1140,6 +1140,6 @@ if (location.hostname !== 'splatter-tennis.wuwi.one' && !window.Capacitor?.isNat
REC
-
+