It seems like I found the reason. I've recreated the "content_idx" gin (content jsonb_path_ops) with fastupdate=false, and good plan stayed even on deadtuples = 4000+ ( as I said previously good plan changed to bad starting on ~300 dead tuples in table).
So, as far as I understand the issue raises once gin pending-entry list reaches ~300 entries. AFAIK gin pending-entry list is stored unsorted, so optimizer may decide to choose another plan to be used since cost estimations for scanning unsorted gin pending-entry list may be to high.
Once I disabled fastupdate mechanism I've raised overhead for write operations, but scanning uses only index body, without gin pending-entry (since it's not presented anymore).
Would much appreciate if someone can confirm or disprove my conclusions.