Maybe there's a more efficient approach, but here's what I came up with:
data = {{"foo", "foo", "blah", "blah", "foo", "blah", "argh"},
{"pfft", ".", ".", ".", ".", ".", "foo"},
{"foo", ".", "foo", ".", "pfft", "blah", "."},
{".", ".", "pfft", ".", ".", ".", "blah"},
{".", "pfft", "blah", ".", ".", ".", "."},
{"blah", ".", ".", ".", "argh", ".", "."},
{"blah", "foo", "foo", "argh", ".", ".", "pfft"},
{".", ".", "pfft", ".", "argh", ".", "."},
{"foo", ".", "blah", ".", "argh", ".", "."},
{"blah", "pfft", ".", "pfft", "foo", "argh", "."}};
fillblanks[list_, dummy_: "."] :=
Flatten[ConstantArray[First[#], Length[#]] & /@ Split[list, StringMatchQ[#2, dummy] &]]
Transpose[fillblanks /@ Transpose[data]]
which yields
{{"foo", "foo", "blah", "blah", "foo", "blah", "argh"},
{"pfft", "foo", "blah", "blah", "foo", "blah", "foo"},
{"foo", "foo", "foo", "blah", "pfft", "blah", "foo"},
{"foo", "foo", "pfft", "blah", "pfft", "blah", "blah"},
{"foo", "pfft", "blah", "blah", "pfft", "blah", "blah"},
{"blah", "pfft", "blah", "blah", "argh", "blah", "blah"},
{"blah", "foo", "foo", "argh", "argh", "blah", "pfft"},
{"blah", "foo", "pfft", "argh", "argh", "blah", "pfft"},
{"foo", "foo", "blah", "argh", "argh", "blah", "pfft"},
{"blah", "pfft", "blah", "pfft", "foo", "argh", "pfft"}}