Drupal is weird. Just... weird.
So (at least the way we're currently doing things) we have a bunch of appropriately named (so Drupal can work its magic and find them) twig templates in our theme folder that then refer to page templates in our pattern library.
The individual pattern library page templates extend pages/_base.twig. However, base.twig is not a complete template! There's a note saying:
> The doctype, html, head and body tags are not in this template. Instead they can be found in the html.html.twig template.
WTF? Ok... html.html.twig lives in core/modules/system/templates... Looking in there, we can **finally**
see `<body{{ attributes }}>`. So all the crazy classes Drupal applies to the body tag are part of this attributes variable. **We don't want to fuck that up**! We can't pass twig variables back *up* the chain, and besides these are hooked together with Drupal black magic, not twig logic. Put code similar to this in your theme_name.theme file to add classes to that attribute variable without breaking the universe:
```php
///**
// * Implements hook_preprocess_HOOK() for html.html.twig.
// */
function prc_theme_preprocess_html(&$variables)
{
$route_name = \Drupal::routeMatch()->getRouteName();
switch ($route_name) {
case 'system.401':
$variables['attributes']['class'][] = 'error-page-401';
break;
case 'system.403':
$variables['attributes']['class'][] = 'error-page-403';
break;
case 'system.404':
$variables['attributes']['class'][] = 'error-page-404';
break;
}
}
```
Note that [routing](https://www.drupal.org/docs/8/api/routing-system/introductory-drupal-8-routes-and-controllers-example) is how Drupal controls what is rendered at what path... In this case, I'm using it to detect error pages, kind of like using `is_page_template` in WP. Obviously there are lots of different conditionals you could use here, such as node type etc.