Reduce motion isn't an accessibility checkbox: it's design
At Jornia, the brand animation is the only custom animation allowed in the whole app. Why that makes respecting reduce motion easy, and what got built first to make it that way.
Jornia's design system spends one sentence defining how much motion the app has: "standard M3 curves, durations from 150 to 300 ms, never more than 400." And then a second sentence, the one that actually matters: out of everything that could be animated, only one thing is allowed to carry its own custom animation. Everything else uses system transitions, full stop.
That restriction wasn't born out of accessibility thinking. It was born out of brand thinking. And it turned out to be the same decision.
The one animation with its own name
Jornia's brand signature is this: when you mark a stop as done on the timeline, the connector dot pulses (8→12→8 dp) and the dotted line to the next stop draws itself in. Three hundred milliseconds, a CheckCircle that scales in instead of just popping into view. It's described in the design system as the "only custom animation allowed in v1," with that explicit exclusivity clause attached.
This is a decision about restraint, not about resources: Compose doesn't cost more to animate five things than one. It was left out on purpose, because an app that animates everything doesn't have a signature — it has noise. If you want a single micro-interaction to be recognized as "this is Jornia," the price is that nothing else competes for attention.
The helper was built before the animation
Here's the detail that isn't obvious until you see it in the execution plan: the first item on the list, T1.0, isn't the signature animation. It's a thirty-minute helper, rememberReduceMotion(), that reads Settings.Global.ANIMATOR_DURATION_SCALE == 0f from the system.
The order isn't a coincidence. It went first because both the signature animation (T1.1) and "future animations," per the plan's own note, need it. The flashy piece wasn't built first with the accessibility switch bolted on afterward — which is how it usually goes when reduce motion gets treated as a compliance checkbox: the feature ships, someone runs an audit, and then an if gets retrofitted so accessibility QA doesn't flag it.
Here it went the other way around. The switch is infrastructure, and the animation is what gets built on top of it. That changes who has to remember to check it: if rememberReduceMotion() exists before the first animation, every animation written afterward is born wrapped in the helper, because there's no faster way to write it than the correct way. If the helper arrives later, every existing animation is a place someone has to go back to, remember, and patch.
What having just one animation actually buys you for free
This is what the "only one custom animation" restriction buys as a side effect: respecting reduce motion in Jornia isn't an audit through the codebase hunting down every loose animateFloatAsState. It's a check in one place.
Compare that to what it would be in an app that does animate ten different things — custom screen transitions, scroll parallax, micro-bounces on every button. There, reduce motion is a cross-cutting requirement you have to verify in ten places, and it only takes missing one for the accessibility promise to be false in practice even if it's true for most of the app. With one named animation and one helper wrapping it, the failure surface is the size of a function.
That doesn't mean the rest of the app "has no motion." Standard Material 3 transitions — navigation, Emphasized — are still there, and those are handled by the system itself, not by Jornia's code. reduce motion isn't its concern: turning off the brand signature wouldn't leave the app static, it would leave it looking exactly like any other Android app that respects the system preference. The only thing that changes is that the dot doesn't pulse and the line doesn't draw itself in: they jump straight to their final state.
And that check was explicitly requested, written as an acceptance criterion rather than a footnote: "with reduce motion, everything is instant and correct." Not "doesn't animate" — correct. The difference matters: a poorly implemented accessibility switch sometimes just turns off the animation and forgets to leave the dot at its final radius or the line fully drawn, and the result is a half-drawn screen that looks like a network bug, not a respected system preference.
The same rule, applied twice, independently
What confirms this is a design system rule and not a one-off decision on a single task is that it was applied twice, in two deliverables that have nothing to do with each other. The loading skeletons (T1.4) carry a subtle shimmer — a glint that sweeps across while the screen loads — and it too respects rememberReduceMotion(): with the preference on, there's no shimmer, just the static block with the card's real geometry.
Nobody explicitly asked for "apply reduce motion to the skeletons too." It got applied because the helper was already there and the rule — anything that moves without the user asking it to move can be turned off — is the same for the brand signature as it is for a loading shimmer. That's the sign that a design restriction has become the team's reflex: it repeats itself on its own, in a place where nobody wrote the requirement down.
What we take away from this
Less custom animation is, as a bonus, less accessibility surface to watch over. That wasn't why Jornia limited its brand signature to a single piece, but it's the consequence: with only one place that animates something of its own, there's only one place that can disobey reduce motion.
Build the switch before the thing it interrupts. If the accessibility helper exists before the first animation, every new animation is born obeying it because writing it any other way would be more work, not less. If it arrives later, every existing animation is a pending visit.
The acceptance criterion isn't "it can be turned off," it's "the final state is correct." Badly done reduce motion draws things half-finished and looks like a bug. Properly done reduce motion jumps straight to the end, and it's indistinguishable from there never having been anything to animate in the first place.
If in your app the list of "things that animate" no longer fits in one sentence, reduce motion probably doesn't fit in one if either. Write to me if you want to compare notes on how you solved it.