What we do:
First, a doc in which we essentially lay down the use cases. This doc usually starts with a dictionary, containing terms specific to the business domain, terms coined during discussions with the customer, terms which are more technical in nature but which the customer has to learn in order the communication to work properly. Then comes a list of unstructured, non-functional requirements. These are things like number of concurrent users, data load, availability expectations, and the like. If a specific non-functional requirement is big, it gets a chapter on its own. All functional requirements are then written down as use cases. These usually contain preconditions, scope, the actual use case description as a succession of steps, and post-conditions. However, we don't use such terms in the document - this starting document has to be extremely concise and completely understandable by the customer/end user.
This document almost always contains additional chapters, depending on what the customer requirements are. Typical case is a chapter about access rights, specific issues regarding deployment, specific technology issues.
Second, we do a design document. This, when there are code generators for the target language in our UML tool, is data models and plus UML diagrams, with lots of comments. If code generators are not available, we write a class dictionary as text, also heavily commented, maybe also generate some code skeletton - but we try to avoid code, since it is hard to maintain in sync with later changes to the code.
After this, we start coding from the specification. In parallel, testers start scripting and planning their tests. Once we are finished coding, we run the tests. Code goes to manual testing only after all scripted tests run without a glitch.
During coding the design documents at least have to be permanently updated. If you have smart tools and use UML, this is not so difficult.
I think that if we hadn't the right tools we'd rather go without thorough design documentation, just with some wiki pages on the general architecture. Out of sync docs are even worse than no docs at all. Unfortunately, customers often want to read most of the design documentation, so you often don't get away without it even if you decide you don't have the proper tools for doing it.
No matter how you document your design, your code must be self-documenting. There's no better documentation than the code itself, provided it is cleanly written and well maintained.
Depending on the customer, we either provide the customer with plans for acceptance testing, or they do them themselves. When we do this, it's just the initially laid down use cases plus input/test data and expected output. Once testers say everything is OK, we ship the binaries to the customer, and often we also perform the installation. Then we have to push the customers to actually do the acceptance tests. A time of support, bugfixes, updates, smaller or larger change requests follows. Change requests always lead to a revision of all documents.
The two documents I described (I never mess with the teser's documentation, they maintain this for themselves, and it's not really much, usually - they are even more extreme in that the test scripts are the documentation than we programmers are), can range in size from 10 or 20 pages per document for tiny projects of just a few dozens of man-days to hundreds of pages per document for large projects, of several man-years (as a small team, we don't do projects of tens of man years, where the documentation probably would require thousands of pages per document).
The main requirement about the documentation is that the non-technical customer should be able to read it and understand as much as possible of it. All that's not for the user to read should be documented as source code. That's how we think.