Count IDs into column A; classes, attributes and pseudo-classes into B; types and pseudo-elements into C. * and combinators count nothing. Compare A, then B, then C; columns never carry over, so eleven classes (0-11-0) still lose to one ID (1-0-0).
| Selector | Counted as | Result |
|---|---|---|
| #nav .item:hover | A #nav; B .item :hover | 1-2-0 |
| a[href]::before | B [href]; C a ::before | 0-1-2 |
| li:nth-child(2 of .x) | B :nth-child .x; C li | 0-2-1 |
| :is(#top, .hero) p | A #top (heaviest); C p | 1-0-1 |
| :where(#top, .hero) p | C p only | 0-0-1 |
A style attribute beats every selector and !important beats both, so keep them as last resorts. Keep most selectors at one or two classes and wrap resets in :where() so any class overrides them. To raise a rule, repeat a class (.btn.btn, 0-2-0) or move the weaker code into a lower cascade layer (@layer and @scope). A classic interview question, ul#menu li versus .nav .item a, is settled by column A: 1-0-2 beats 0-2-1 whatever the order.