I think of them as effectively CSS variables with types and that can be animated.
By default CSS variables can't be animated since it has no idea what unit it's animating between
Critically, CSS custom properties are not evaluated by default until you use them. They're more akin to preprocessor substitution. Yes, this does mean that:
calc(var(--foo) * 2)
can have a different result than: calc((var(--foo)) * 2)
Since they're basically just strings, there's no way for the animation system to interpolate between different values. `@property` fixes this allowing the immediate evaluation of the value into a concrete value that _can_ be interpolated.