Given a deeply nested object, return a **flat object** where keys use dot notation to represent the path. Only flatten plain objects — arrays should remain as values.
Input: obj = { a: { b: { c: 1 }, d: 2 }, e: 3 }
Output: { "a.b.c": 1, "a.d": 2, "e": 3 }
Input: obj = { x: { y: [1, 2, 3] } }
Output: { "x.y": [1, 2, 3] }