What design principles contribute to the effectiveness of Kotlin's ASI?

I’m working on a summary of different proglangs’ approaches to automatic semicolon insertion (ASI).

Kotlin’s approach seems better than most, but I’ve been unable to find any documentation on precisely how it works. Does anyone know details of how it works, or the design rationale, or how the Kotlin designers crafted a grammar that allows for such effective ASI?

Any insights on how it works, and the design rationale behind that would be much appreciated.

AFAICT, the reference docs only mention it briefly as a style concern:

Note: In Kotlin, semicolons are optional, and therefore line breaks are significant.

Omit semicolons whenever possible.

Neither the grammar nor kotlin-spec (works in progress both) mention it AFAICT.
The grammar for semi suggest that it’s not purely a grammar issue.

semi : EOF ;

Note: the ; at the end is a grammar meta-character, nothing to do with Kotlin tokens; semi has no definition except EOF.

IIUC, for a script to be allowed to have more than one statement, there must be some special handling in the lexer|parser.

Prior discussion: