IIRC, if you use y[x] then it gives the expression for y with x as the unknown. It is like writing in Mathematica
When you just use y, then it gives a function, which you can apply to a value (like 4 or x). It is like writing
Notice the difference, in the first case, you would need to do something like "x = 4; f[x]" or "f[x] /. x -> 4" to evaluate f at 4, in the second case you can just do f[4] (even if x already has a value).
Flatten removes all nesting in a list. In this case, I had to use it because NDSolve gives back something like
Solution = {{ y -> stuff }}
and you need something of the form
y /. {y -> stuff}
So you can do either
y /. Flatten[Solution]
or (in this case equivalently)
y /. Solution[[1]]
(N)Solve doesn't really seem to work in this case, but you could try
FindRoot[solution[x] == 0.5, {x, 0}]
where 0.5 is the intersection point and 0 is your guess (the more accurate your guess, the more accurate the result, in general). Note that there are not many checks built in here, for example,
FindRoot[solution[x] == 3, {x, 0}]
will - despite some warnings - still give you a value of x. However, if you look at the plot, you will see that there is no solution. The reason is of course that the result it was considering when it decided to bail out of the numerical procedure is actually returned; the lesson is you should be extra careful.