diff --git a/PROJECT.md b/PROJECT.md
index 8536788..1a9aae5 100644
--- a/PROJECT.md
+++ b/PROJECT.md
@@ -5127,7 +5127,7 @@ replay button"*. Both are netplay-only by construction, which is why neither had
→ both courts come up 0-0 with full blood, the friend standing, no gore, "REMATCH — YOUR SERVE"
against "REMATCH — THEIR SERVE". 146 tests.
-## THE RALLY GOES FLAT — diagnosis (2026-10-13, UNDER DISCUSSION, nothing built)
+## THE RALLY GOES FLAT — diagnosis, plan, and step 1 (2026-10-13, STEP 1 SHIPPED v361, phone verdict pending)
Oliver: *"jedes Spiel läuft am Ende gleich ab (vor allem in höheren Levels): Aufschlag, dann schnell
vor ans Netz (Spieler und Opponent), von wo aus ein sehr schneller Ballwechsel passiert und durch eine
@@ -5214,13 +5214,62 @@ the bot. That is expected: once the geometry is fixed, what is missing is the to
4. **Retune the escalation** against the new shape, with `tools/rally-sim.mjs` and the step-1 test as the
gauge.
+**Oliver's answers (2026-10-13): "a) ja b) ja c) erstmal nur kurze bälle — go".** (a) Step 1 first, in
+both modes, then a phone test. (b) The down-flick becomes the soft ball (short = drop, long = lob), which
+is APPROVED and is step 3. (c) The player goes to the net ONLY on a short ball for now. Following an
+attacking up-flick in was offered and deferred.
+
+### Step 1, as shipped (v361): THE COURT HAS ITS LENGTH
+All dials are in TUNE's block of that name. Rally modes only (`rallyFeel()`); gore's prologue and the duel
+are byte-identical.
+- **Depth**: `rallyMid` 2.8 / `rallyDeep` 1.9 m inside the line. Timing only SHORTENS the ball:
+ `(1-q)·shortK·(0.5..1.5)`. Pinned: a rally ball never lands nearer than ~1.4 m to the line. (solveShot
+ aims at ty 0.08, so the real bounce sits a few dm past the mark.) The down-flick keeps the old
+ `SHOT_DEPTH.short` until step 3.
+- **The plan, `ball.rx`, latched once per shot** (every strike clears it; `rxPlan` sets it on the
+ receiver's first planning frame). `net` = the receiver stood inside `netFrom` (7 m) when the shot left;
+ `short` = it lands more than `shortBall` (4.9 m) inside his line and is not a serve. The latch is
+ load-bearing: re-reading position every frame flipped a man running in for a short ball into a volleyer
+ the moment he crossed `netFrom`.
+- **From the back you let it bounce.** `intercept` meets the ball between its bounce and the next, at the
+ top or falling through `rallyHit`+0.3, up to `rallyBehind` (2.2 m) behind the line. A short ball is met
+ the first moment it is up off the grass. The old earliest-contact candidates are only the fallback.
+ `racketAI` does the same in closed form (`bounceContact`), keeps THE READ's blend on x, and is now
+ allowed behind its own baseline (the old `>= 1.5` clamp). `letBounce()` refuses a below-the-tape
+ pick-up on the full from the back, for both CPUs (in their near-checks, or the cooldown eats the
+ bounce) and for the player (in `trySwing`, where his swing simply waits for the bounce).
+- **The approach**: a short ball taken sets `ball.approach`, and the striker's recovery (`rallyHome`)
+ heads for `netStand` (3.2 m) while it flies. Inside `netFrom` you stay at the net; otherwise you
+ recover `rallyBack` (0.6 m) behind your line. **Nobody approaches a man already at the net**
+ (`ball.from`, the striker's distance): that ball is a pass. Without this rule, both bodies ended up at
+ the net at a quarter of a second per shot, which was the old bug in a new place.
+- **A net man facing a lob** (the ball will clear his racket height at his depth) turns and runs it down
+ as a baseliner. Nothing hits a lob yet; it is groundwork for steps 2 and 3.
+- **A volley below the tape** is capped at `lowVolleyQ` 0.3: soft, short, little width. This is the
+ net's cost.
+
+**Measured after** (`tools/rally-sim.mjs`, same bot): both sides now meet the ball 10.5-13.7 m from the
+net, back-court volleys are 0-8%, and a baseline exchange takes 0.8-1.0 s per shot (it was 0.7 s at the
+T). Approaches happen off short balls only, mostly the opponent's at the high rungs, because the bot
+mistimes. Classic shows the same shape. Suite 150, plus three new tests: the rally is played from the
+baselines (back-court volley share, time per shot), short means approach / deep means stay back / never
+approach a net man, and depth never goes long. Fuzzed over 8 seeds.
+
+**What step 1 did NOT fix, and it is the next lever: THE LEGS.** `rzChaseSpeed` at the Climb's rungs is
+about 3.4 m/s (1), 5.6 (6), 8.8 (12) and **15.7 m/s (18, faster than a sprinter)**, against the player's
+~6.5. Oliver's hunch that "the opponents get very fast" was literally true. Under the new geometry a
+late opponent at the net covers every pass, so the bot loses ~95% of the points where the Champion
+comes in. That is step 4 (and the passing/lob game of steps 2-3); it is deliberately not mixed into
+step 1, so its phone verdict reads one change.
+
# OPEN — leftovers, in rough priority order
Nothing here is broken; these are known gaps and unverified risks.
-0. **THE RALLY GOES FLAT (2026-10-13), the top item.** Every match converges on serve, both at the net,
- reflex volleys, won by a wrong-foot. Diagnosed and measured; a four-step plan is awaiting Oliver's go.
- See the section of that name just above. Fallback tag `rally-baseline-v360`.
+0. **THE RALLY GOES FLAT (2026-10-13), the top item.** Every match converged on serve, both at the net,
+ reflex volleys, won by a wrong-foot. Step 1 (the court gets its length) SHIPPED v361, awaiting the
+ phone verdict. Next up: step 3 (the soft ball, approved), step 2 (opponent styles), and step 4 (the legs:
+ the Champion runs 15.7 m/s). See the section of that name above. Fallback tag `rally-baseline-v360`.
1. **`RES` 4 is unverified on a real phone under load.** It nearly doubled the fill rate (810 -> 1080
device px across). Oliver has not reported stutter, but he also has not played a late horde since.
diff --git a/index.html b/index.html
index e47d5d8..355a142 100644
--- a/index.html
+++ b/index.html
@@ -1140,6 +1140,6 @@ if (location.hostname !== 'splatter-tennis.wuwi.one' && !window.Capacitor?.isNat
REC
-
+