Sri Lanka captain Dimuth Karunaratne and seamer Vishwa Fernando have led a fightback against South Africa on the second day of the second test, but the visitors remain precariously placed in a fast-moving contest.
Fernando took his first-ever test five-wicket haul as Sri Lanka dismissed South Africa for 302 in their first innings, restricting the hosts to a 145-run lead, while Karunaratne scored an unbeaten 91 in the tourists' second innings.
They were 150/4 at stumps, leading by five runs with three days still to play at The Wanderers Stadium.
South Africa, who won the first test in Pretoria last week, started the day on 148/1 in reply to Sri Lanka's first innings tally of 157 and had hopes of settling in for a long stint at the crease to build a match-winning lead.
Dean Elgar, 92 not out overnight, went to his century while Rassie van der Dussen survived an early chance to pass 50.
But it all crumbled after the first hour's play as Elgar was removed for 127, after a 184-run second-wicket partnership, and Van der Dussen was dismissed in the next over for 67.
Sri Lanka's bowlers, after struggling on the opening day, found a steady line and length and bagged a procession of home wickets as the hosts lost their last nine for 84 runs, missing out on an opportunity to build a considerable lead.
Fernando cleaned up the home tail to finish with figures of 5/101.
Sri Lanka's second innings started poorly with Kusal Perera dismissed cheaply. Perera, a nemesis for South Africa in the last two series, was clean bowled by Lungi Ngidi for one.
But Karunaratne and Lahiru Thirimanne put on 85 runs for the second wicket before Ngidi snagged Thirimanne (31) and Kusal Mendis with successive balls down the leg side, that produced two impressive diving catches from wicketkeeper Quinton de Kock.
Karunaratne will resume on nine runs short of his century, with Niroshan Dickwella at the other end on 18 not out.