/* Bootstrap 3 panel chrome, for EDITOR-AUTHORED article bodies only (#839).
 *
 * WHY THIS FILE EXISTS
 *
 * mag-components.css dropped `.panel*` on a stated premise: open_body and
 * locked_body are ProseEditorField(sanitize=True), whose nh3 allowlist strips
 * every class attribute, so the legacy vocabulary is "unreachable from
 * templates AND unreachable from content".
 *
 * The first half holds. The second does not. Sanitising happens on SAVE, and
 * 20 of the 380 mag entries were written years before that field existed --
 * their stored HTML still carries `panel-default`, `panel-heading`,
 * `panel-body`, `panel-collapse` and `panel-group` (1,059 uses), and
 * `{{ object.open_body|safe }}` puts all of it in the DOM verbatim. Verified by
 * rendering /magasin/dyreforsikring-2021/ on master: every one of those class
 * names is present in the response.
 *
 * The render-parity gate measured the cost: 6,760 of the 8,574 findings on
 * magasin/<path>/ touch a panel anchor.
 *
 * SCOPED, NOT RESTORED
 *
 * Under `.article-content` so it can only reach the editor-authored body. The
 * migrated chrome around it stays on Tailwind, and a new article -- which
 * cannot contain these classes, because sanitising DOES apply on save -- is
 * unaffected. Rules lifted verbatim from the deployed tag's magasin.css so the
 * two renders agree by construction rather than by re-derivation.
 *
 * ONE SECTION IS NOT SCOPED: modals, since #1135. It is the only vocabulary
 * here the tag itself defined globally, and the only one that has to reach
 * `mag.entry.extra_bottom`, a third editor-authored field `entry_detail.html`
 * renders outside the `.article-content` div and cannot move out of
 * `{% block js %}`. The full argument, and the test that keeps it honest, are
 * in that section's own header. Everything else in this file stays prefixed;
 * the three `#utenforScope*` controls in `test_bootstrap_teardown.py` are what
 * says so.
 *
 * THE COLLAPSED STATE
 *
 * The handler already exists. collapse.js (#510) is a delegated
 * `data-toggle="collapse"` listener written for exactly this stored-HTML case,
 * and _migration_assets_scripts.html loads it on every page including this one.
 * Its own header says it depends on `.collapse:not(.show)` "(norskfamilie-
 * components.css:953)" to do the hiding.
 *
 * That is the rule mag pages never had. base_mag.html loads mag-components.css,
 * not norskfamilie-components.css, and the `.collapse` rule went with the
 * `.panel*` block on the same (half-true) premise. So on a mag article the JS
 * ran, set aria-expanded and toggled `.show` -- and nothing looked different,
 * because every panel was already visible. 1,650 "appeared here, absent on the
 * deployed ref" findings, and 470 `aria-expanded: None -> 'false'` from the
 * handler working correctly against CSS that was not there.
 *
 * Lifted verbatim from Bootstrap 4.6.2, which is what the deployed tag ships,
 * and which is why `.show` rather than BS3's `.in` is the open class.
 * `.collapsing` is not carried: collapse.js does not do the height transition,
 * so nothing ever has that class.
 *
 * `.panel-footer` is omitted too: no entry uses it, and mag-components.css's
 * rule is to carry only what something actually renders.
 *
 * Panels only. `.col-*` was the separate gap named here; it is addressed now,
 * in the grid section further down (#1110), the tables that sit inside those
 * columns in the tables section below it (#1118, cluster 1 of 6), and the cards
 * inside those in the section after that (cluster 2), the modals after that
 * (cluster 3), the pull quotes and figure captions after those (cluster 4),
 * the utility vocabulary after those (cluster 5) and magasin.css's own
 * leftovers in the last section of all (cluster 6).
 * `thead-default` stays out for good: it is a Bootstrap 4 ALPHA name that 4.6.2
 * dropped, so it was inert on the deployed tag too. #1118 is now CLOSED: zero
 * of its 61 classes are still open. Four are closed but deliberately NOT
 * carried: `lead` (typography section), `card-text` and `card-title` (cards)
 * and `nav-pills` (utilities). `nav-pills` joined that list when cluster 5
 * excluded both its tag rules -- `.nav-link` occurs 0 times in the stored
 * bodies and Bootstrap defines no bare `.nav-pills{}`, so the class restores
 * nothing. `modal-lg` was the fifth and is no longer: it was excluded only
 * because the `.article-content` prefix made its one use unreachable, and
 * #1135 dropped that prefix from the modal section, so it is carried. The
 * other three are excluded on their own merits and #1135 does not change them
 * -- `card-text` and `card-title` are 100% `extra_bottom` too, but they sit
 * inside `.card`, whose section stays scoped for the modifier reason below.
 * Measured with `coverage.py` BEFORE #1135, the mag surface was missing 11 of
 * the 61 before cluster 6 (6 cluster-6 + those 5) and 5 after it; #1135 has not
 * been re-measured that way, it removes `modal-lg` from that list by
 * construction.
 *
 * SCOPE A BASE, AND YOU MUST SCOPE ITS MODIFIERS TOO
 *
 * Read this before adding a cluster. Prefixing a tag-era class with
 * `.article-content` raises it from (0,1,0) to (0,2,0), which lifts it above
 * EVERY unscoped modifier the tag layered on that base. On the tag those
 * modifiers won on source order at equal specificity -- base_mag.html loaded
 * bootstrap.min.css at :30 and magasin.css at :33 -- so scoping the base alone
 * silently INVERTS the layering and paints the base's own values over the
 * modifier's.
 *
 * Cards are the worked example: `.card-grey` sits bare at (0,1,0) in
 * mag-components.css:587, and a lone `.article-content .card` would have turned
 * 40 grey cards white -- worse than carrying nothing at all. The rule is to
 * scope the base AND every modifier of it the tag defined, in that source
 * order. This bites `.alert-*`, `.nav*` and `.text-*` in the three remaining
 * clusters exactly the same way; census the modifiers before writing the base
 * rule, not after. Cluster 3 ran that census and found the empty case, which is
 * a result rather than a skip: `magasin.css` on the tag has ZERO occurrences of
 * `modal`, `fade` or `close`, so there was no modifier to invert and every
 * modal rule is Bootstrap's own.
 *
 * That empty result is what let #1135 UNSCOPE the modal section a cluster
 * later. The rule runs in both directions: removing a prefix drops the base
 * from (0,2,0) back to (0,1,0) and hands the win back to every unscoped
 * modifier -- which is right when the tag layered one there and wrong when
 * cluster 2 had to scope four of them to stop the inversion. Modals had none,
 * cards have four, and that asymmetry is the whole reason one section moved and
 * the other did not.
 *
 * WHAT CHECKS THIS FILE
 *
 * `uv run python scripts/check_db_bootstrap_classes.py` (#839), against a
 * populated database. It reads the class tokens out of the stored bodies, reads
 * the selectors out of this file and mag-components.css, and reports every class
 * that has no rule here but HAD one at v2.0.49.16 -- the comparison this whole
 * header is written around, made by measurement instead of by hand. Run it
 * whenever a rule is removed from this file or a component sheet is re-subset,
 * and before a release that touches either.
 *
 * It knows the two fields apart: `extra_bottom` renders outside
 * `.article-content`, so a scoped rule does not count as reaching it, which is
 * what #1135 turned on. What it CANNOT see is one rule of several for the same
 * class -- deleting the `.article-content .panel-heading` block alone leaves
 * four other rules naming `panel-heading`, and the script stays quiet. It
 * answers "does any rule reach this class", which is the shape every case from
 * #1110 to #1137 actually had.
 *
 * The five classes it reports on this surface -- `lead`, `nav-pills`, `card`,
 * `card-text`, `card-title` -- are the deliberate exclusions this header
 * already argues for, and they are listed in the script's KNOWN_GAPS with a
 * citation each rather than dropped from its vocabulary.
 */

.article-content .panel {
  margin-bottom: 20px;
  background-color: #fff;
  border: 1px solid transparent;
  border-radius: 4px;
  box-shadow: 0 1px 1px rgba(0, 0, 0, .05);
}

.article-content .panel-body {
  padding: 15px;
}

.article-content .panel-heading {
  padding: 10px 15px;
  border-bottom: 1px solid transparent;
  border-top-left-radius: 3px;
  border-top-right-radius: 3px;
}

.article-content .panel-title {
  margin-top: 0;
  margin-bottom: 0;
  font-size: 120%;
  color: inherit;
}

.article-content .panel-title > a,
.article-content .panel-title > small,
.article-content .panel-title > .small,
.article-content .panel-title > small > a,
.article-content .panel-title > .small > a {
  color: inherit;
}


/* .panel-group: the accordion wrapper. 16 of the 20 articles use it. */
.article-content .panel-group {
  margin-bottom: 20px;
}

.article-content .panel-group .panel {
  margin-bottom: 0;
  border-radius: 4px;
}

.article-content .panel-group .panel + .panel {
  margin-top: 5px;
}

.article-content .panel-group .panel-heading {
  border-bottom: 0;
}

.article-content .panel-group .panel-heading + .panel-collapse > .panel-body {
  border-top: 1px solid #ddd;
}



/* .panel-default is the only variant these bodies use -- no -primary,
 * -success, -info, -warning or -danger anywhere in the 380 entries. */
.article-content .panel-default {
  border-color: #ddd;
}

.article-content .panel-default > .panel-heading {
  color: #333;
  background-color: #f5f5f5;
  border-color: #ddd;
}

.article-content .panel-default > .panel-heading + .panel-collapse > .panel-body {
  border-top-color: #ddd;
}


/* Bootstrap 4.6.2, verbatim. Scoped like the rest of this file: the identical
 * rule already exists unscoped in norskfamilie-components.css:953 for pages
 * built on base.html, and mag pages are the ones that lost it. */
.article-content .collapse:not(.show) {
  display: none;
}

/* ------------------------------------------------------------------ buttons
 *
 * `<a class="btn btn-primary">` in a stored body rendered as blue link text on
 * master: no background, 19.2px instead of 16px (inheriting
 * `.article-content p{font-size:120%}` because nothing set a size), 35.2px
 * line-height instead of 24px. ~690 findings, the largest cluster left on
 * magasin/<path>/ after the panels and the collapse rule.
 *
 * `.btn` is genuinely undefined on mag pages -- mag-components.css names it
 * only inside a comment -- so all of this is missing, not merely overridden.
 *
 * Two sources, because that is what the deployed tag composes: the base rules
 * from its bootstrap.min.css (4.6.2), then magasin.css's `border-radius: 0`,
 * which won on source order there and is folded in here.
 *
 * NOT CARRIED: `.btn-default`. It is Bootstrap 3 -- BS4 renamed it
 * btn-secondary -- so the 53 uses in these bodies are unstyled on the DEPLOYED
 * tag too. Adding a rule would invent a difference rather than restore one.
 */

.article-content .btn {
  display: inline-block;
  font-weight: 400;
  color: #212529;
  text-align: center;
  vertical-align: middle;
  user-select: none;
  background-color: transparent;
  border: 1px solid transparent;
  padding: .375rem .75rem;
  font-size: 1rem;
  line-height: 1.5;
  /* magasin.css:  .btn { border-radius: 0 } -- square, not BS4's .25rem. */
  border-radius: 0;
  transition:
    color .15s ease-in-out,
    background-color .15s ease-in-out,
    border-color .15s ease-in-out,
    box-shadow .15s ease-in-out;
}

.article-content .btn-primary {
  color: #fff;
  background-color: #007bff;
  border-color: #007bff;
}

.article-content .btn-primary:hover {
  color: #fff;
  background-color: #0069d9;
  border-color: #0062cc;
}

.article-content .btn-lg {
  padding: .5rem 1rem;
  font-size: 1.25rem;
  line-height: 1.5;
  border-radius: .3rem;
}

.article-content .btn-sm {
  padding: .25rem .5rem;
  font-size: .875rem;
  line-height: 1.5;
  border-radius: .2rem;
}

.article-content .btn-link {
  font-weight: 400;
  color: #007bff;
  text-decoration: none;
}

.article-content .btn-link:hover {
  color: #0056b3;
  text-decoration: underline;
}


/* --------------------------------------------------------------------- grid
 *
 * #1110. `<div class="row"><div class="col-xs-12 col-lg-6">` around the two
 * result tables of mag.entry pk 80 (/aktuelt/2015/jan/29/norges-beste-banker-
 * 2014/) rendered as one stacked column on master: 6054 -> 7430px, 24.8% of the
 * page differing from the deployed tag. 44 of the 380 entries put a `.row` in a
 * stored body.
 *
 * The whole grid is missing here, not just the columns. mag-components.css
 * carries no `.row` and no `.col-*` at all -- it was subset against the mag
 * TEMPLATES, which are fully on tw: utilities -- and base_mag.html has never
 * loaded norskfamilie-components.css, where the base.html subtree keeps its own
 * shim. So on the deployed tag these bodies were laid out by bootstrap.min.css
 * (4.6.2), and on master by nothing: the columns are block elements at 100%.
 *
 * CARRIED: the 12 grid classes the stored bodies actually use, with the object
 * counts from the parity content sample -- row (44), col-12 (21), col-4 (19),
 * col-7 (19), col-sm-2 (10), col-sm-6 (5), col-6 (2), col-sm-3 (2), col-sm-4,
 * col-lg-3, col-lg-6, col-lg-9 (1 each). Verbatim from 4.6.2, so the shimmed
 * classes resolve to the percentages and breakpoints they had on the tag.
 *
 * NOT CARRIED, same reason `.btn-default` is not: 4.6.2 has no rule for them,
 * so they were already inert on the DEPLOYED tag and a shim would invent a
 * difference rather than restore one. That is every `col-xs-*` (88 uses -- the
 * Bootstrap 3 spelling, and the one on pk 80 above), `pull-left` / `pull-right`
 * (21), and the BS3 `col-*-offset-*` spelling, including the `col-lg-offset-2`
 * that netmeeting/forms.py:27 emits on /nettmoete/. Nor the `card-white`,
 * `card-sm` and `thead-default` in these bodies: those are Bootstrap 4 ALPHA
 * names, dropped before 4.6.2, and equally inert on the tag.
 *
 * The `m-b-*` / `m-t-*` in these bodies were on that list too, and the claim
 * was wrong twice (#1118 ADDENDUM 3 s7). They are not Bootstrap names in any
 * sense -- 4.6.2 defines ZERO `m-*-*` rules; the spelling is `magasin.css`'s
 * own -- and they were not all inert: the tag's `magasin.css` defines
 * `.m-b-4`..`.m-b-6` and `.m-t-4`..`.m-t-10`. Of the eight spellings the
 * bodies use, six were dead on the tag and `m-b-4` (2 uses) and `m-t-4` (1)
 * were LIVE. They are carried, in the magasin.css leftovers section at the
 * end of this file; the other six stay out on the reachability grounds the
 * rest of this file uses, not on this one.
 *
 * Scoped to .article-content like the rest of this file, which is both stored
 * bodies: entry_detail.html renders open_body at :59 and the locked_body block
 * at :160 inside it. extra_bottom is outside (it is injected into {% block js %}
 * at :246) and uses none of these classes.
 *
 * That last clause is about the GRID classes only, and it does not generalise:
 * `extra_bottom` is stored body HTML like the other two and carries plenty of
 * the rest of #1118's vocabulary -- all 15 `card-text` and all 3 `card-title`
 * live there, and 5 of the 18 `modal`. Nothing scoped on `.article-content` can
 * reach any of it. Tracked as #1135; census that field separately per cluster.
 *
 * The remaining gap on this surface is NOT grid and is not addressed here: the
 * same sweep finds 61 more classes that 4.6.2 defined and mag-components.css
 * dropped (#1118). The tables among them -- `.table*`, `.thead-dark` -- are the
 * section below; `.card-*`, `.modal-*`, `.blockquote*`, `.figure*`, `.alert*`,
 * `.embed-responsive*`, `.nav`, `.text-*`, `.img-fluid` and magasin.css's own
 * `.card-lightgrey` are in the sections after it, and magasin.css's
 * `.blockquote-brd`, `.fontello-icon`, `.brd-wht`, `.brd-rgt`, `.m-b-4` and
 * `.m-t-4` in the last one. Nothing is still to come.
 * Restoring the columns does not make
 * pk 80 pixel-match the tag on its own; the card chrome inside them is still
 * missing.
 */

.article-content .row {
  display: -ms-flexbox;
  display: flex;
  -ms-flex-wrap: wrap;
  flex-wrap: wrap;
  margin-right: -15px;
  margin-left: -15px;
}

.article-content .col-4,
.article-content .col-6,
.article-content .col-7,
.article-content .col-12,
.article-content .col-sm-2,
.article-content .col-sm-3,
.article-content .col-sm-4,
.article-content .col-sm-6,
.article-content .col-lg-3,
.article-content .col-lg-6,
.article-content .col-lg-9 {
  position: relative;
  width: 100%;
  padding-right: 15px;
  padding-left: 15px;
}

.article-content .col-4 {
  -ms-flex: 0 0 33.333333%;
  flex: 0 0 33.333333%;
  max-width: 33.333333%;
}

.article-content .col-6 {
  -ms-flex: 0 0 50%;
  flex: 0 0 50%;
  max-width: 50%;
}

.article-content .col-7 {
  -ms-flex: 0 0 58.333333%;
  flex: 0 0 58.333333%;
  max-width: 58.333333%;
}

.article-content .col-12 {
  -ms-flex: 0 0 100%;
  flex: 0 0 100%;
  max-width: 100%;
}

@media (min-width: 576px) {
  .article-content .col-sm-2 {
    -ms-flex: 0 0 16.666667%;
    flex: 0 0 16.666667%;
    max-width: 16.666667%;
  }

  .article-content .col-sm-3 {
    -ms-flex: 0 0 25%;
    flex: 0 0 25%;
    max-width: 25%;
  }

  .article-content .col-sm-4 {
    -ms-flex: 0 0 33.333333%;
    flex: 0 0 33.333333%;
    max-width: 33.333333%;
  }

  .article-content .col-sm-6 {
    -ms-flex: 0 0 50%;
    flex: 0 0 50%;
    max-width: 50%;
  }
}

@media (min-width: 992px) {
  .article-content .col-lg-3 {
    -ms-flex: 0 0 25%;
    flex: 0 0 25%;
    max-width: 25%;
  }

  .article-content .col-lg-6 {
    -ms-flex: 0 0 50%;
    flex: 0 0 50%;
    max-width: 50%;
  }

  .article-content .col-lg-9 {
    -ms-flex: 0 0 75%;
    flex: 0 0 75%;
    max-width: 75%;
  }
}


/* ------------------------------------------------------------------- tables
 *
 * #1118, cluster 1 of 6. `mag-components.css` was subset against the mag
 * TEMPLATES, so the table vocabulary that only ever appears in editor-authored
 * body HTML went with the rest of Bootstrap. 93 `.table` elements across 24 of
 * the 380 entries in the parity content sample render with no cell padding, no
 * rules, no stripes and no header band on master; on the deployed tag
 * `bootstrap.min.css` (4.6.2) styled every one of them.
 *
 * CARRIED, with the element counts from the sample: `table` (93), `table-
 * responsive` (71), `table-striped` (36), `table-hover` (27), `thead-dark`
 * (20), `table-bordered` (16), `table-sm` (10). Verbatim from 4.6.2, scoped to
 * `.article-content` like the rest of this file.
 *
 * Those are ELEMENT counts, which is what #1118's table holds even though its
 * column is headed "objects using it" -- it counted class-attribute tokens. The
 * distinct-object counts are much smaller and are the ones that matter for how
 * far a regression can spread: 24 objects for `table`, 19 `table-responsive`,
 * 15 `table-striped`, 10 `table-hover`, 9 `table-bordered`, and just 2 for
 * `thead-dark` (pk 305, 342) and 1 for `table-sm` (pk 80).
 *
 * SOURCE IS BOOTSTRAP ONLY -- magasin.css's table half never applied here.
 * #1118's table credits `table`, `table-responsive` and `table-bordered` to
 * "both" sheets, but every table rule magasin.css has is `.panel > .table...`
 * with a child combinator, and no sampled body puts a `.table` inside a
 * `.panel` at all: `.panel .table` matches 0 elements across all 380 entries,
 * as do all nine of the other `.panel > .table*` shapes. So on the tag those
 * rules were already inert on this surface, and folding them in would invent a
 * difference rather than restore one -- the same test `.btn-default` and the
 * `col-xs-*` classes failed. Nothing here is composed from two sheets the way
 * `.btn`'s `border-radius: 0` was.
 *
 * NOT CARRIED, because nothing in the 380 entries renders them, which is this
 * file's standing rule (`.panel-footer`, `.collapsing`):
 *   - `.table tbody + tbody` -- no entry has two tbody children in one table;
 *   - `.table caption` padding -- no entry has a `<caption>`;
 *   - the nine `.table-hover .table-{primary,secondary,...}:hover` contextual
 *     row variants -- none of those context classes appears in any body;
 *   - `.thead-light`, and the `.table-responsive-{sm,md,lg,xl}` breakpoint
 *     variants -- likewise unused.
 * `<tfoot>` appears twice (pk 84) and needs no rule of its own: 4.6.2 styles
 * its cells through the same `.table td, .table th` descendant selector.
 *
 * SPECIFICITY: `.article-content .table td` is (0,2,1) where the tag's
 * `.table td` was (0,1,1). Nothing loses a cascade it used to win -- the only
 * other rules reaching a table on this surface are mag-components.css's three
 * bare-element reboot rules (`table{border-collapse}`, `caption`, `th`) and its
 * `@media print{tr{page-break-inside:avoid}}`, all at (0,0,1), which the tag's
 * `.table` selectors already outranked in the same direction.
 *
 * The `@media print` rules are carried for the same reason: 4.6.2 defined them
 * for these classes, and mag-components.css kept the tag's print block but
 * dropped its table half with everything else.
 */

.article-content .table {
  width: 100%;
  margin-bottom: 1rem;
  color: #212529;
}

.article-content .table td,
.article-content .table th {
  padding: .75rem;
  vertical-align: top;
  border-top: 1px solid #dee2e6;
}

.article-content .table thead th {
  vertical-align: bottom;
  border-bottom: 2px solid #dee2e6;
}

.article-content .table-sm td,
.article-content .table-sm th {
  padding: .3rem;
}

.article-content .table-bordered {
  border: 1px solid #dee2e6;
}

.article-content .table-bordered td,
.article-content .table-bordered th {
  border: 1px solid #dee2e6;
}

.article-content .table-bordered thead td,
.article-content .table-bordered thead th {
  border-bottom-width: 2px;
}

.article-content .table-striped tbody tr:nth-of-type(odd) {
  background-color: rgba(0, 0, 0, .05);
}

.article-content .table-hover tbody tr:hover {
  color: #212529;
  background-color: rgba(0, 0, 0, .075);
}

/* `thead-dark` is always `<thead class="thead-dark">` inside a `.table` in
 * these bodies (20 of 20), which is the only shape 4.6.2 styles it in. */
.article-content .table .thead-dark th {
  color: #fff;
  background-color: #343a40;
  border-color: #454d55;
}

.article-content .table-responsive {
  display: block;
  width: 100%;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

.article-content .table-responsive > .table-bordered {
  border: 0;
}

@media print {
  .article-content .table {
    border-collapse: collapse !important;
  }

  .article-content .table td,
  .article-content .table th {
    background-color: #fff !important;
  }

  .article-content .table-bordered td,
  .article-content .table-bordered th {
    border: 1px solid #dee2e6 !important;
  }

  .article-content .table .thead-dark th {
    color: inherit;
    border-color: #dee2e6;
  }
}


/* -------------------------------------------------------------------- cards
 *
 * #1118, cluster 2 of 6. Same shape as the tables section above: card
 * vocabulary that only ever appears in editor-authored body HTML, dropped with
 * the rest of Bootstrap when `mag-components.css` was subset against the mag
 * TEMPLATES. 81 `.card` elements across 32 of the 380 entries in the parity
 * content sample render with no background, no border and no padding on
 * master; on the deployed tag `bootstrap.min.css` (4.6.2) and `magasin.css`
 * styled every one of them.
 *
 * CARRIED, with element counts / distinct objects from the sample: `card`
 * (81 / 32), `card-body` (20 / 8), `card-default` (9 / 2), `card-lightgrey`
 * (1 / 1), plus `.card ul` (23 / 8). Element counts are what #1118's table
 * holds; the object counts are the ones that bound how far a regression can
 * spread.
 *
 * `card-text` (15) and `card-title` (3) are NOT here even though #1118 lists
 * them. Both are 100% `extra_bottom`, in one object each, and
 * `entry_detail.html:246` renders `extra_bottom` inside `{% block js %}` --
 * OUTSIDE the `.article-content` div that opens at :53. An
 * `.article-content .card-text` rule would match 0 elements. Restoring that
 * surface needs a different scope and is its own issue.
 *
 * SOURCE IS BOTH SHEETS HERE, unlike cluster 1. The tables were Bootstrap
 * only, because every magasin.css table rule was `.panel > .table...` and no
 * body puts a table inside a panel. Cards are the opposite: magasin.css
 * composes onto the Bootstrap base the way `.btn`'s `border-radius: 0` did.
 * `.card { border-radius: 0 }` (magasin.css:859) is folded into the base rule
 * rather than repeated -- base_mag.html loaded bootstrap.min.css at :30 and
 * magasin.css at :33 on the tag, both selectors are (0,1,0), so square corners
 * won on source order and `.25rem` never applied.
 *
 * NO PRINT HALF. Cluster 1 carried four `@media print` rules; the census here
 * finds ZERO. Bootstrap 4.6.2's print block is 28 rules and none of them
 * carries a card class; magasin.css's is 3 rules, all `.article-content`
 * typography. Screen only, by measurement.
 *
 * NOT CARRIED, because the context class has 0 uses in any of the 380 entries
 * -- this file's standing rule (`.panel-footer`, `.collapsing`, `.table
 * caption`):
 *   - `.card > hr` (0 elements) and the four `.card > .list-group` radius
 *     rules (`list-group` 0 uses);
 *   - every `.card-deck` / `.card-group` / `.card-columns` / `.accordion`
 *     rule, including the ten inside `@media (min-width:576px)`;
 *   - `.card-header`, `.card-footer`, `.card-img-top`, `.card-img-bottom`;
 *   - magasin's `.img-container .card` (+ its `h2` rule and that rule's
 *     992px variant), `.card.card-img-container`, `.card.card-no-bg`, and the
 *     `.card-inverse` group -- all 0 uses.
 * `card-block` (76 uses), `card-white` (28) and `card-sm` (10) are the
 * big-looking numbers in the bodies and they stay out for the opposite
 * reason: NEITHER tag sheet defines them, so they were inert on the tag too.
 *
 * THE CASCADE REPAIR -- why `card-grey` and `card-no-brd` are here
 *
 * #1118 names four card classes; this section carries six. Both extra names are
 * already on master, so they look out of scope. They are not, and the reason is
 * this file's own doctrine, stated in the grid section above: a class stays out
 * when 4.6.2 "has no rule for them, so they were already inert on the DEPLOYED
 * tag and a shim would invent a difference rather than restore one" -- which is
 * why `card-white`, `card-sm` and `thead-default` are excluded here too. The
 * converse is the same rule. The tag DID define `.card-grey` (magasin.css:867)
 * and `.card.card-no-brd` (:863) on this surface, so carrying them scoped
 * RESTORES a difference. See the header's specificity note for the general form.
 *
 * Concretely: scoping the base rule raises it from (0,1,0) to (0,2,0) and
 * inverts two cascades the tag resolved the other way. Without these two rules
 * 76 of the 85 card elements -- across 28 of the 32 objects -- paint WRONG, and
 * the 40 `card-grey` ones get worse than they are today:
 *
 *   - `.card-grey` is defined in the TAG's magasin.css (:867) and again bare
 *     in `mag-components.css:587`. On the tag it beat `.card`'s white on
 *     source order at equal specificity. Against `.article-content .card` it
 *     loses on specificity instead, and 40 grey cards turn white. The scoped
 *     copy below restores the tag by sitting at (0,2,0) AFTER the base. Its
 *     declarations are byte-identical to the bare rule, which keeps every
 *     other surface -- and `entry_detail.html:162`'s `mag-card card-grey`
 *     chrome, which is inside `.article-content` -- painting exactly as now.
 *   - `.card.card-no-brd` was (0,2,0) on the tag. Master's version is
 *     `.mag-card.card-no-brd`, which needs a `mag-card` token no CMS body
 *     element has, so it is inert on this surface: 36 elements would GAIN a
 *     1px border they never had on the tag or on master.
 *
 * SPECIFICITY: `.article-content .card` is (0,2,0) where the tag's `.card` was
 * (0,1,0). The only other master rules reaching these elements are the two
 * named above; `card-white`, `card-block`, `card-sm`, `m-b-1`, `m-b-2` and
 * `mb-1` match nothing on either side.
 *
 * CHURN: none. `mag-legacy-body.css` is loaded from one place
 * (`base_mag.html:42`), every rule here is `.article-content`-scoped, and the
 * closure of base_mag.html over extends + include + `{% component %}` is 15
 * templates in which the token `card`, `card-body`, `card-default` and
 * `card-lightgrey` appear ZERO times -- the mag chrome migrated to `mag-card`.
 * The `mag-article` baseline seeds `_MAG_ARTICLE_BODY_HTML`, which carries no
 * class attribute at all.
 */

.article-content .card {
  position: relative;
  display: -ms-flexbox;
  display: flex;
  -ms-flex-direction: column;
  flex-direction: column;
  min-width: 0;
  word-wrap: break-word;
  background-color: #fff;
  background-clip: border-box;
  border: 1px solid rgba(0, 0, 0, .125);
  /* magasin.css:859 `.card{border-radius:0}`, folded in -- see the header. */
  border-radius: 0;
}

.article-content .card-body {
  -ms-flex: 1 1 auto;
  flex: 1 1 auto;
  min-height: 1px;
  padding: 1.25rem;
}

/* magasin.css:406, which is already `.article-content`-scoped in the tag. */
.article-content .card ul {
  padding-left: 24px;
}

/* magasin.css:863/865/867/868, in source order. The last three are (0,2,0)
 * like the base rule above, so they win on order exactly as they did on the
 * tag; `.card.card-no-brd` is (0,3,0) and wins on specificity, as it did. */
.article-content .card.card-no-brd {
  border: none;
}

.article-content .card-default {
  background: #f3f3f3;
}

.article-content .card-grey {
  background: #f3f3f3;
  border-color: #f3f3f3;
}

.article-content .card-lightgrey {
  background: #f3efed;
  border-color: #f3efed;
}


/* ------------------------------------------------------------------- modals
 *
 * #1118, cluster 3 of 6, and the one that had to wait for a handler. Same
 * shape as tables and cards above -- modal vocabulary that only ever appears in
 * editor-authored body HTML, dropped when `mag-components.css` was subset
 * against the mag TEMPLATES -- but with one difference that made it dangerous
 * to ship first: the rules below HIDE things.
 *
 * THE ONE UNSCOPED SECTION IN THIS FILE, AND WHY (#1135)
 *
 * Every other section here is prefixed `.article-content`. This one is not,
 * because on the deployed tag it was not either: `bootstrap.min.css` defined
 * `.modal*`, `.fade` and `.close` globally, while `magasin.css`'s
 * `.article-content p` / `ul` / `ol` were ALREADY `.article-content`-scoped in
 * the tag's own source (`v2.0.49.17:magasin.css:390-400`). Page-level chrome
 * global, body flow scoped -- restoring that split is what this file is for.
 *
 * `mag.entry` has a third HTML field. `entry_detail.html` renders `open_body`
 * and `locked_body` inside the `.article-content` div it opens at :53, and
 * `extra_bottom` at :265, inside `{% block js %}` -- which `base_mag.html:254`
 * emits after the footer. The tag did exactly the same (`v2.0.49.17:mag/
 * entry_detail.html:83` vs `:269`), so this is not drift to undo. It also
 * cannot be undone: `entry_detail.html:261` loads `Chart-2.3.0.min.js`
 * immediately above the field, and 10 of the 11 entries with a non-empty
 * `extra_bottom` hold nothing but `<script>` -- moving the render into
 * `.article-content` would run those scripts before the loader they need.
 *
 * So the field stays where it is, and the vocabulary in it is reached the way
 * the tag reached it. The eleventh entry is `mag.Entry` pk 154, and its
 * `extra_bottom` is the whole of what the prefix was locking out: 65 class
 * uses, all 65 inside five sibling `.modal` containers. With this section
 * scoped, those five rendered UNHIDDEN -- 13.6 KB of markup, 10,367 characters
 * of dialog text, below the footer of a published article, every visit, for
 * everyone. That is the bug #1135 is filed on, and dropping the prefix here is
 * its fix.
 *
 * The card vocabulary nested inside pk 154's `#if_modal` (`card` 3,
 * `card-block` 3, `card-title` 3, `card-text` 15) stays unreached, and stays
 * that way deliberately: `.card` is a BASE with modifiers -- `.card-no-brd`,
 * `.card-default`, `.card-grey` and `.card-lightgrey` -- and unscoping it would
 * re-invert the layering cluster 2 had to scope all four to get right (see this
 * file's header). Modals have no modifier to invert, which is exactly why this
 * section can move and that one cannot. `card-block` is dropped for the older
 * reason regardless: it is a BS4-alpha name 4.6.2 does not define, so the tag
 * gave those three divs nothing either.
 *
 * WHY THIS ONE IS ORDERED AFTER #1137
 *
 * `.modal{display:none}` and `.fade:not(.show){opacity:0}` are how Bootstrap
 * keeps a modal shut at rest; `bootstrap.min.js` was what reopened it. no-wh7
 * dropped that bundle from `base_mag.html`, so landing these two rules alone
 * would have taken 13 containers from *rendered inline* to *unreachable* --
 * content the reader can see today, gone, with the visual baselines unable to
 * notice because their fixture bodies carry no class attributes. The opener is
 * `static/js/modal.js` (#1137, PR #1142); it loads from
 * `_migration_assets_scripts.html` on every page this sheet loads on, and
 * `test_bootstrap_teardown.py`'s Gate 6 is its behaviour gate. The CSS lands
 * with or after it, never before.
 *
 * The split is Bootstrap's own and `collapse.js` set the precedent above:
 * CSS owns the resting state, JS owns the transitions. `modal.js` deliberately
 * does not hide `.modal` itself, which is why the resting state is this
 * section's job rather than the script's.
 *
 * CARRIED, with element counts / distinct objects across ALL THREE body
 * fields in the parity content sample -- `open_body` + `locked_body` first,
 * then `extra_bottom`, which #1135 made reachable: `modal` (13 + 5 / 3),
 * `modal-dialog` (13 + 5 / 3), `modal-content` (13 + 5 / 3), `modal-body`
 * (13 + 5 / 3), `fade` (13 + 5 / 3), `modal-footer` (13 + 0 / 2),
 * `modal-header` (1 + 5 / 2), `modal-title` (1 + 5 / 2), `close` (1 + 5 / 2),
 * `modal-lg` (0 + 1 / 1). Three entries carry modal markup at all: `mag.Entry`
 * pk 50 and pk 54 in scope, pk 154 in `extra_bottom`.
 *
 * SOURCE IS BOOTSTRAP ONLY, and for a stronger reason than cluster 1's.
 * `magasin.css` on the tag has ZERO occurrences of `modal`, `fade` or `close`
 * -- not "defines them but inertly", zero. So the "scope a base and you must
 * scope its modifiers too" trap in this file's header, which cost cluster 2 two
 * extra rules, has nothing to find here: there were no modifiers to invert.
 * Every rule below is 4.6.2 verbatim modulo the `.article-content` prefix.
 *
 * NO PRINT HALF, like cluster 2 and unlike cluster 1: none of the 45 rules in
 * the tag's `bootstrap.min.css` carrying one of these classes sits in
 * `@media print`. The two `@media (prefers-reduced-motion: reduce)` blocks ARE
 * carried, interleaved directly after the rules they cancel exactly as 4.6.2
 * orders them -- they are (0,2,0) once scoped, same as their base, so source
 * order is the whole of what makes them win.
 *
 * NOT CARRIED, because the class or element matches 0 nodes in any of the 380
 * entries -- this file's standing rule (`.panel-footer`, `.collapsing`,
 * `.table caption`, `.card > hr`):
 *   - `a.close.disabled` and `.alert-dismissible .close`: the one `.close` in
 *     the sample is a `<button>` inside a `.modal-header`, so `button.close`
 *     and `.modal-header .close` are carried and these two are not;
 *   - `.modal.modal-static .modal-dialog`, `.modal-scrollbar-measure`, the five
 *     `.modal-dialog-centered` rules (including `::before`) and the four
 *     `.modal-dialog-scrollable` ones;
 *   - `.modal-sm` and `.modal-xl`, and their `@media (min-width: 576px)` /
 *     `(min-width: 1200px)` blocks.
 * `modal-lg` WAS dropped here, for the #1135 reason: its 1 use is 100%
 * `extra_bottom`, so an `.article-content .modal-lg` rule would have matched
 * nothing and excluding it avoided dead CSS rather than trimming scope. #1135
 * removed the prefix, so it is carried now, at the bottom of this section.
 * `.modal-xl` shares Bootstrap's rule with it and is still dropped: 0 uses.
 *
 * `.modal-open` AND `.modal-backdrop` ARE A REAL GAP, AND STILL NOT OURS
 *
 * The tag's `bootstrap.min.css` defines `.modal-open{overflow:hidden}` and
 * `.modal-open .modal{overflow-x:hidden;overflow-y:auto}`, and no sheet on
 * master has a `.modal-open` or `.modal-backdrop` selector at all. Porting them
 * would still be writing CSS that can never match: `.modal-open` is a class
 * Bootstrap's JS put on `<body>`, and `modal.js` deliberately does not set it
 * (with no backdrop element drawn, it would be inert -- see its header).
 *
 * The consequence is bounded and measured rather than assumed. With
 * `.modal{overflow:hidden;height:100%}` standing alone, a modal taller than the
 * viewport clips and cannot be scrolled -- but the two containers a reader can
 * actually open are nowhere near that: pk 50's `#bestilling` is 227 characters
 * of text, and pk 54's `#modal1`, with its nested `.modal` subtrees discounted,
 * is 132. If an editor ever pastes a long modal body, the fix is `modal.js`
 * setting the body class AND these two rules together -- one change, not this
 * one.
 *
 * WHAT THIS ACTUALLY REOPENS: SEVEN CONTAINERS, NOT EIGHTEEN
 *
 * pk 54's stored HTML closes `.modal-content` but leaves `.modal-dialog` and
 * `.modal` open, so `#modal2` parses INSIDE `#modal1`'s dialog, `#modal3`
 * inside `#modal2`'s, twelve deep (confirmed with lxml, not a regex), while all
 * 12 of its triggers sit at top level. An ancestor's `display:none` keeps 11 of
 * the 12 dark whatever a stylesheet writes on the target itself. Bootstrap 4
 * did not reparent an in-DOM modal either, so these were equally shut on the
 * deployed tag: this is pre-existing stored-content pathology, documented in
 * `scripts/check_db_bootstrap_hooks.py`, not something this cluster regresses
 * or can fix. pk 154's five are all top-level siblings and all five have a
 * trigger, so they cost nothing to that pathology -- but the triggers are in
 * its `locked_body`, which `getLockedContent()` fetches only for a member. A
 * signed-out reader has never been able to open them; before #1135 they were
 * simply always open. The reachable containers are seven: pk 50's
 * `#bestilling`, pk 54's `#modal1`, and pk 154's five.
 *
 * SPECIFICITY: every selector here is now byte-identical to the tag's, so
 * (0,1,0) where the tag was (0,1,0) and nothing can lose a cascade it used to
 * win. Dropping the prefix only LOWERS these rules, so the check is what could
 * now beat them. Inside `.article-content` the candidates are
 * `.article-content p` (0,1,1) and `.article-content .btn` (0,2,0), and neither
 * sets a property any rule here sets; outside it there is nothing, because
 * these class names occur nowhere on this surface but stored bodies. Bare `h4`
 * / `button` reboot rules at (0,0,1) still lose to `.modal-title` (0,1,0) and
 * `button.close` (0,1,1), the same direction as before.
 *
 * CHURN: none, and it is now this section's load-bearing safety argument
 * rather than a footnote -- the prefix was what used to guarantee it. Across
 * the 17 templates that can render on a page loading this sheet --
 * `base_mag.html` and everything that extends or includes it, with two edges a
 * source scan cannot follow resolved explicitly: `entry_list.html`'s dynamic
 * `{% include page_template %}`, and `base_mag.html:177`'s `{% show_categories %}`
 * inclusion_tag, which renders `mag/categories.html`. Cluster 3 counted 16 here
 * and had missed that second one. Across all 17 the tokens `modal`,
 * `modal-dialog`, `modal-content`, `modal-body`,
 * `modal-header`, `modal-footer`, `modal-title`, `modal-lg`, `fade` and `close`
 * appear ZERO times once `{% comment %}` blocks are stripped. The lone raw hit
 * is `base_mag.html:240`, the stickybadge close button inside a `{% comment %}`
 * that never renders. `stickybadge.js` is disjoint from this by construction
 * anyway: it binds `#<badge-id> .close` for two ids whose buttons carry
 * `data-dismiss="stickybadge"`, not `"modal"`. A census in a comment is not a
 * guard, so #1135 also pinned it:
 * `test_bootstrap_teardown.py::test_mag_templates_do_not_use_the_unscoped_modal_vocabulary`
 * recomputes that closure and fails if a template ever claims one of these
 * names. That test is what makes this section safe to leave unprefixed.
 */

/* Bootstrap orders `.fade` before `.close` before `.modal*`, and the two
 * reduced-motion overrides directly after the rules they cancel. Kept. */
.fade {
  transition: opacity .15s linear;
}

@media (prefers-reduced-motion: reduce) {
  .fade {
    transition: none;
  }
}

/* One of the two independent ways a modal is shut at rest; `modal.js` adds
 * `.show`, which lifts this, and sets `display: block` inline, which lifts the
 * `.modal` rule below. Every `.fade` in these bodies is on a `.modal` (18 of
 * 18 once #1135 counted `extra_bottom` too), so this reaches nothing else. */
.fade:not(.show) {
  opacity: 0;
}

.close {
  float: right;
  font-size: 1.5rem;
  font-weight: 700;
  line-height: 1;
  color: #000;
  text-shadow: 0 1px 0 #fff;
  opacity: .5;
}

.close:hover {
  color: #000;
  text-decoration: none;
}

.close:not(:disabled):not(.disabled):focus,
.close:not(:disabled):not(.disabled):hover {
  opacity: .75;
}

button.close {
  padding: 0;
  background-color: transparent;
  border: 0;
}

.modal {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 1050;
  display: none;
  width: 100%;
  height: 100%;
  overflow: hidden;
  outline: 0;
}

.modal-dialog {
  position: relative;
  width: auto;
  margin: .5rem;
  pointer-events: none;
}

.modal.fade .modal-dialog {
  transition: -webkit-transform .3s ease-out;
  transition: transform .3s ease-out;
  transition: transform .3s ease-out, -webkit-transform .3s ease-out;
  -webkit-transform: translate(0, -50px);
  transform: translate(0, -50px);
}

@media (prefers-reduced-motion: reduce) {
  .modal.fade .modal-dialog {
    transition: none;
  }
}

/* `modal.js` adds `.show` in the same tick as `display: block`, so the panel
 * snaps rather than slides -- collapse.js's panels do the same. This rule is
 * what makes it land square instead of 50px high; it is (0,3,0) like the
 * `.fade` rule above, so it wins on source order, as it did on the tag. */
.modal.show .modal-dialog {
  -webkit-transform: none;
  transform: none;
}

.modal-content {
  position: relative;
  display: -ms-flexbox;
  display: flex;
  -ms-flex-direction: column;
  flex-direction: column;
  width: 100%;
  pointer-events: auto;
  background-color: #fff;
  background-clip: padding-box;
  border: 1px solid rgba(0, 0, 0, .2);
  border-radius: .3rem;
  outline: 0;
}

.modal-header {
  display: -ms-flexbox;
  display: flex;
  -ms-flex-align: start;
  align-items: flex-start;
  -ms-flex-pack: justify;
  justify-content: space-between;
  padding: 1rem 1rem;
  border-bottom: 1px solid #dee2e6;
  border-top-left-radius: calc(.3rem - 1px);
  border-top-right-radius: calc(.3rem - 1px);
}

.modal-header .close {
  padding: 1rem 1rem;
  margin: -1rem -1rem -1rem auto;
}

.modal-title {
  margin-bottom: 0;
  line-height: 1.5;
}

.modal-body {
  position: relative;
  -ms-flex: 1 1 auto;
  flex: 1 1 auto;
  padding: 1rem;
}

.modal-footer {
  display: -ms-flexbox;
  display: flex;
  -ms-flex-wrap: wrap;
  flex-wrap: wrap;
  -ms-flex-align: center;
  align-items: center;
  -ms-flex-pack: end;
  justify-content: flex-end;
  padding: .75rem;
  border-top: 1px solid #dee2e6;
  border-bottom-right-radius: calc(.3rem - 1px);
  border-bottom-left-radius: calc(.3rem - 1px);
}

.modal-footer > * {
  margin: .25rem;
}

@media (min-width: 576px) {
  .modal-dialog {
    max-width: 500px;
    margin: 1.75rem auto;
  }
}

/* `.modal-lg`, carried by #1135 -- it is the one class the `.article-content`
 * prefix had made unreachable rather than genuinely absent. Bootstrap writes
 * `.modal-lg,.modal-xl{max-width:800px}`; `modal-xl` occurs 0 times in the 380
 * entries, so it is dropped under this file's standing rule and `modal-lg` is
 * carried alone. Its 1 use is `mag.Entry` pk 154's `#if_modal`. */
@media (min-width: 992px) {
  .modal-lg {
    max-width: 800px;
  }
}


/* -------------------------------------------------- typography / blockquote
 *
 * #1118, cluster 4 of 6. Same shape as tables, cards and modals above: pull
 * quotes and figure captions that only ever appear in editor-authored body
 * HTML, dropped when `mag-components.css` was subset against the mag
 * TEMPLATES. Measured against the tag, master renders a
 * `<blockquote class="blockquote">` at 16px/left where it was 20px/centred,
 * and its `<footer class="blockquote-footer">` at 16px in the body's #444
 * where it was 12px in #6c757d; on the deployed tag `bootstrap.min.css`
 * (4.6.2) and `magasin.css` styled every one.
 *
 * CARRIED, with element counts / distinct objects from the parity content
 * sample: `blockquote` (35 / 33), `blockquote-footer` (25 / 23), `figure`
 * (1 / 1), `figure-caption` (1 / 1), plus the two already-scoped magasin rules
 * that reach the 67 `<p>` inside those blockquotes and the 34 of them that
 * carry `quote-sign` (34 / 32). Zero uses of any of them in `extra_bottom`
 * (#1135), so unlike clusters 2 and 3 nothing here is dead on reachability
 * grounds and there is nothing to exclude for it.
 *
 * `lead` (8 / 4) is NOT here even though #1118 lists it, and this is the one
 * exclusion in the cluster that is a cascade result rather than a reach one.
 * `.lead` is (0,1,0); `.article-content p` -- in `magasin.css` on the tag and
 * lifted verbatim into `mag-components.css` on master -- is (0,1,1) and sets
 * `font-size:120%; font-weight:400`. So the tag never rendered `.lead`'s
 * 1.25rem/300 on this surface: all 8 uses are `<p>`, and every one of them
 * lost. Master reproduces that by having no rule at all. Scoping it would
 * INVERT the result rather than restore it -- `.article-content .lead` is
 * (0,2,0) and beats (0,1,1) -- measured at 19.2px/400 on the tag against
 * 20px/300 with the scoped rule added, on all 8. `entry_detail.html:75`
 * already carries the same finding for the template half of this surface,
 * where the migration DROPPED `lead` for exactly this reason. There is no
 * scoped spelling that keeps the tag's outcome: any prefix adds a class and
 * lands above (0,1,1).
 *
 * `blockquote-brd` (34 / 32) was cluster 6's, with `fontello-icon`, `brd-wht`
 * and `brd-rgt`; it is `magasin.css`-only and independent of everything here,
 * and it is in the last section of this file.
 *
 * SOURCE IS BOTH SHEETS, and this is the cluster where that matters most.
 * `magasin.css` (`base_mag.html:33` on the tag, after bootstrap at `:30`)
 * redefines three of the six Bootstrap selectors, so the rendered value is the
 * union with magasin's declarations last -- the same fold cluster 2 did for
 * `.card{border-radius:0}`. Both halves are below, in each sheet's own source
 * order, bootstrap first. Carrying only Bootstrap's half would be verbatim on
 * its face and still wrong on the page: `magasin.css:471` blanks the em-dash
 * with `content:""`, and a bootstrap-only port prints an em-dash and a
 * non-breaking space in front of all 25 `blockquote-footer` texts that
 * production does not show. The visual
 * baselines cannot catch it -- their fixture bodies carry no class attributes,
 * which is this issue's stated invariant.
 *
 * TWO RULES ARE ALREADY `.article-content`-SCOPED IN THE TAG and are ported
 * verbatim, NOT prefixed again: `magasin.css:417` and `:419`, the same case as
 * `.article-content .card ul` (`magasin.css:406`) in the cards section above.
 * Prefixing them would spell `.article-content .article-content .blockquote p`,
 * which parses, matches nothing we render, and no baseline can see.
 *
 * SPECIFICITY: nothing inverts except `.lead`, which is why it is excluded.
 * The only element-reaching rules on this surface are `.article-content p` and
 * `.article-content ul, .article-content ol` at (0,1,1), both the tag's own and
 * both byte-identical on master; neither reaches a `<blockquote>`, `<footer>`,
 * `<figure>` or `<figcaption>`. Bootstrap's Reboot `blockquote{margin:0 0 1rem}`,
 * `figure{margin:0 0 1rem}` and `figcaption{display:block}` are still present
 * and unchanged in `mag-components.css` at (0,0,1), below the scoped classes
 * here exactly as they were below the bare ones on the tag.
 *
 * CHURN: none. `mag-legacy-body.css` is loaded from one place
 * (`base_mag.html:42`), every rule here is `.article-content`-scoped, and the
 * 16-template closure of base_mag.html over extends + include +
 * `{% component %}` contains ZERO bare `blockquote`, `blockquote-footer`,
 * `quote-sign`, `figure` or `figure-caption` class tokens, comments stripped or
 * not.
 */

.article-content .blockquote {
  margin-bottom: 1rem;
  font-size: 1.25rem;
}

.article-content .blockquote-footer {
  display: block;
  font-size: .875em;
  color: #6c757d;
}

.article-content .blockquote-footer::before {
  content: "\2014\00A0";
}

.article-content .figure {
  display: inline-block;
}

.article-content .figure-caption {
  font-size: 90%;
  color: #6c757d;
}

/* magasin.css:416/417/418/419/471, in source order. The three that redefine a
 * Bootstrap selector above land at the same specificity as the rule they
 * redefine, so they win on order exactly as they did on the tag; `:417` and
 * `:419` are the already-scoped pair. */
.article-content .blockquote {
  border-left: none;
  text-align: center;
  margin-bottom: 0;
}

.article-content .blockquote p {
  margin-bottom: 0 !important;
}

.article-content .blockquote-footer {
  font-size: 60%;
  margin-top: 1rem;
}

.article-content .blockquote p.quote-sign {
  font-size: 250% !important;
  color: #fd6d38;
  line-height: normal;
  margin-bottom: 1rem !important;
  -ms-transform: rotate(180deg) !important;
  -webkit-transform: rotate(180deg) !important;
  transform: rotate(180deg) !important;
}

.article-content .blockquote-footer::before {
  content: "";
}


/* ---------------------------------------------------------------- utilities
 *
 * #1118, cluster 5 of 6. The Bootstrap utility vocabulary the stored bodies
 * lean on for spacing, alignment and colour -- `.text-*`, `.mb-*` / `.mt-*`,
 * `.d-flex`, `.align-items-center`, `.rounded-circle`, `.embed-responsive*`,
 * `.nav` and `.alert*` -- plus `.img-fluid`, which is #1118's single largest
 * item at 140 uses and which the issue's original six-way split assigned to no
 * cluster at all.
 *
 * ALL BOOTSTRAP, so this is cluster 3's shape rather than cluster 4's:
 * `magasin.css` on the tag carries ZERO of the 44 rules that mention a
 * cluster-5 class. Measured, not assumed -- which means no override pairs and
 * no half-carried stack. Master's `mag-components.css` and the sections above
 * define none of them either, so every rule below is new.
 *
 * CARRIED: 27 rules -- the 26 live ones of the 44, plus `.img-fluid`. Element
 * counts / distinct objects from the parity content sample, all measured with
 * lxml against `.article-content`'s two fields: `img-fluid` (140 / 56),
 * `text-center` (32 / 15), `rounded-circle` (29 / 21), `text-muted` (29 / 9),
 * `mb-4` (22 / 20), `align-items-center` (21 / 19), `d-flex` (21 / 19),
 * `mt-3` (21 / 19), `mb-0` (18 / 7), `text-sm-center` (16 / 4), `alert`
 * (10 / 10), `alert-info` (9 / 9), `alert-link` (6 / 6), `text-info` (5 / 1),
 * `embed-responsive` (4 / 4), `embed-responsive-16by9` (4 / 4),
 * `embed-responsive-item` (3 / 3), `text-right` (3 / 3), `nav` (2 / 2),
 * `text-danger` (2 / 1), `mb-1`, `mb-2`, `mb-3`, `mt-4`, `text-success`
 * (1 each). ZERO `extra_bottom` uses across all of them (#1135), so nothing
 * here is dead by field the way `card-text` and `modal-lg` were.
 *
 * EXCLUDED: the other 18, each because the stored bodies never reach it --
 * dead CSS, not trimmed scope. `.nav-link` appears 0 times, which kills both
 * `.nav-pills` rules (Bootstrap has no bare `.nav-pills{}`, so `nav-pills`'
 * two uses restore nothing and `.nav` is the only live nav rule);
 * `a.text-*` appears 0 times, killing the three `a.text-X:focus,:hover` pairs;
 * `.alert-info hr` appears 0 times; `alert-info` is the only alert modifier in
 * the bodies, so 7 of the 8 `.alert-X .alert-link` variants are dead; and
 * `mt-0`, `mt-1`, `mt-2`, `mt-5`, `mb-5` are spellings that never occur, so
 * `.mt-0,.my-0`, `.mt-1,.my-1`, `.mt-2,.my-2`, `.mt-5,.my-5` and `.mb-5,.my-5`
 * are whole rules with no reachable arm.
 *
 * THE `.my-*` ARMS STAY, and that is not the same call. `my-0` ... `my-5`
 * appear 0 times too, but their rules are reachable through the `.mt-*` /
 * `.mb-*` arm beside them. Rewriting `.mt-3,.my-3` down to `.mt-3` would be
 * the deviation; verbatim is the doctrine, and a dead arm inside a live rule
 * costs nothing. The exclusions above are whole rules with no live arm at all.
 *
 * THE FIVE-ARM `embed-responsive` SELECTOR IS CARRIED WHOLE, and this is the
 * trap of the cluster. A class census reads `embed-responsive` 4 and
 * `embed-responsive-item` 3, which looks like grounds to trim the selector to
 * its first arm. It is not: there are four containers and pk 134's iframe
 * carries no class, so it is reached ONLY by the `.embed-responsive iframe`
 * arm. Trimming leaves that video uncollapsed inside a 56.25% padding box --
 * the same shape as cluster 4's blanked em-dash, a class-keyed census
 * under-counting a rule that has an element arm, and equally invisible to the
 * visual baselines. `norskfamilie-components.css` already made this exact port
 * for the `base.html` subtree and kept all five arms; the block below matches
 * it, scoped. It drops the tag's `-21by9`, `-4by3` and `-1by1` ratios for the
 * same reason as the 18 above -- no body uses them.
 *
 * SPECIFICITY: nothing here inverts the tag, and that is measured rather than
 * inherited. A ported rule inverts only if it declares a property the (0,1,1)
 * element rules on this surface also declare -- `.article-content p`
 * (font-size, font-weight, line-height, margin-bottom) and
 * `.article-content ul, ol` (font-size, font-weight, line-height), both the
 * tag's own and both byte-identical in `mag-components.css` -- AND does not
 * carry `!important`. Bootstrap 4's `text-*` and `m*-*` utilities are all
 * `!important`, so every rule landing on a `<p>` or `<ul>` here is immune;
 * `.nav` on `<ul>` x2 is not `!important` but declares none of those three
 * properties (its `margin-bottom` is not among them); everything else lands on
 * `<div>`, `<img>`, `<iframe>`, `<i>`, `<a>`, `<h3>`, `<h4>`, `<hr>` or
 * `<small>`, which no (0,1,1) rule on this surface reaches. The control for
 * that check is `.lead`, which it flags and which is why cluster 4 left it out.
 *
 * NO MODIFIER TO INVERT, which the header's `.card-grey` warning demands be
 * censused rather than assumed. The only cluster-5 base with a live modifier is
 * `.alert`, and both `.alert-info` and `.alert-info .alert-link` are below in
 * the tag's own source order. The other tokens sharing an element with these
 * classes -- `alert-notice`, `img-responsive`, `m-b-2`, `m-t-2` and Froala's
 * `fr-dii` / `fr-dib` / `fr-fil` / `fr-draggable` -- are defined by NO sheet
 * either surface loads, so they were inert on the tag and stay inert here.
 *
 * `.img-fluid` IS NOT A RENAME. The mag templates were deliberately migrated to
 * `.mag-img-fluid` (`base_mag.html:105` explains why: the `.logo-container img`
 * 185px cap must keep winning, so that shim is unlayered). Stored bodies say
 * the literal `img-fluid` and cannot be rewritten -- they are user content, and
 * `ProseEditorField(sanitize=True)` only strips classes on save. All 140 uses
 * are `<img>` inside `.article-content`, and the logo this rule must not reach
 * is in the header, outside it.
 *
 * ONE RESIDUAL, AND IT IS CLUSTER 6'S. Probed in Chromium over all 113 stored
 * bodies that use a cluster-5 class, this section takes the tag-vs-master gap
 * on those 316 elements from 573 differing (element, property) pairs to 3, and
 * all 3 are the same shape: `magasin.css` defines `.m-b-4` / `.m-t-4` at 4rem
 * `!important`, and pk 242, pk 277 and pk 272 spell BOTH the Bootstrap and the
 * magasin name -- `class="panel-group mb-4 m-b-4"`, `class="m-t-4 mt-4"`. On
 * the tag magasin loaded second and its 4rem won the tie at (0,1,0); here
 * `.mb-4` is the only one of the pair present, so those three elements read
 * 24px where the tag rendered 64px. Cluster 6 closes it -- and must put its
 * `.m-b-4` / `.m-t-4` AFTER this section, since both sides land at (0,2,0)
 * `!important` and source order is again what decides. Appending cluster 6 at
 * the end of this file does that; inserting it earlier would not.
 *
 * CHURN: none. `mag-legacy-body.css` is loaded from one place
 * (`base_mag.html:42`), every rule here is `.article-content`-scoped, and the
 * 16-template closure of base_mag.html over extends + include +
 * `{% component %}` contains ZERO renderable bare tokens for any of these 26
 * class names -- the single raw hit is `img-fluid` inside the `{% comment %}`
 * at `base_mag.html:245`, which cannot repaint anything. Site-wide the tokens
 * are common (379 `text-center` alone), which is exactly why the prefix and
 * the single load site are what isolate them.
 */

.article-content .img-fluid {
  max-width: 100%;
  height: auto;
}

.article-content .nav {
  display: -ms-flexbox;
  display: flex;
  -ms-flex-wrap: wrap;
  flex-wrap: wrap;
  padding-left: 0;
  margin-bottom: 0;
  list-style: none;
}

.article-content .alert {
  position: relative;
  padding: .75rem 1.25rem;
  margin-bottom: 1rem;
  border: 1px solid transparent;
  border-radius: .25rem;
}

.article-content .alert-link {
  font-weight: 700;
}

.article-content .alert-info {
  color: #0c5460;
  background-color: #d1ecf1;
  border-color: #bee5eb;
}

.article-content .alert-info .alert-link {
  color: #062c33;
}

.article-content .rounded-circle {
  border-radius: 50% !important;
}

.article-content .d-flex {
  display: -ms-flexbox !important;
  display: flex !important;
}

.article-content .embed-responsive {
  position: relative;
  display: block;
  width: 100%;
  padding: 0;
  overflow: hidden;
}

.article-content .embed-responsive::before {
  display: block;
  content: "";
}

/* All five arms. pk 134's iframe carries no `embed-responsive-item`, so the
 * element arms are not decoration -- see the note above. */
.article-content .embed-responsive .embed-responsive-item,
.article-content .embed-responsive embed,
.article-content .embed-responsive iframe,
.article-content .embed-responsive object,
.article-content .embed-responsive video {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  width: 100%;
  height: 100%;
  border: 0;
}

.article-content .embed-responsive-16by9::before {
  padding-top: 56.25%;
}

.article-content .align-items-center {
  -ms-flex-align: center !important;
  align-items: center !important;
}

/* The `.my-*` arms come along verbatim; every one of these rules is reached
 * through its `.mb-*` / `.mt-*` arm. */
.article-content .mb-0,
.article-content .my-0 {
  margin-bottom: 0 !important;
}

.article-content .mb-1,
.article-content .my-1 {
  margin-bottom: .25rem !important;
}

.article-content .mb-2,
.article-content .my-2 {
  margin-bottom: .5rem !important;
}

.article-content .mt-3,
.article-content .my-3 {
  margin-top: 1rem !important;
}

.article-content .mb-3,
.article-content .my-3 {
  margin-bottom: 1rem !important;
}

.article-content .mt-4,
.article-content .my-4 {
  margin-top: 1.5rem !important;
}

.article-content .mb-4,
.article-content .my-4 {
  margin-bottom: 1.5rem !important;
}

.article-content .text-right {
  text-align: right !important;
}

.article-content .text-center {
  text-align: center !important;
}

/* In the tag's source order, so `.text-sm-center` still wins the tie against
 * `.text-center` above it from 576px up, as it did on the tag. */
@media (min-width: 576px) {
  .article-content .text-sm-center {
    text-align: center !important;
  }
}

.article-content .text-success {
  color: #28a745 !important;
}

.article-content .text-info {
  color: #17a2b8 !important;
}

.article-content .text-danger {
  color: #dc3545 !important;
}

.article-content .text-muted {
  color: #6c757d !important;
}


/* ------------------------------------------------- magasin.css leftovers
 *
 * #1118, cluster 6 of 6 -- the last of the 61. Everything here is
 * `magasin.css`'s own vocabulary: Bootstrap 4.6.2 defines not one of these six
 * selectors, so unlike every cluster above there is no bootstrap half and no
 * override pair to fold. The counterpart of cluster 3 and 5's measured empty
 * case for magasin, with the sheets the other way round.
 *
 * CARRIED: 6 rules. Element counts / distinct objects from the parity content
 * sample, measured with lxml against `.article-content`'s two fields --
 * `blockquote-brd` (34 / 32), `fontello-icon` (34 / 32), `brd-wht` (7 / 1),
 * `brd-rgt` (7 / 1), `m-b-4` (2 / 2), `m-t-4` (1 / 1). ZERO `extra_bottom`
 * uses across all six (#1135), so nothing here is dead by field.
 *
 * THIS SECTION MUST STAY LAST IN THE FILE. `.m-b-4` and `.m-t-4` are
 * `!important` in `magasin.css`, and cluster 5 shipped `.article-content .mb-4`
 * / `.mt-4` at 1.5rem `!important` in the section above. Scoped the same way,
 * both sides are (0,2,0) AND `!important`, so source order is the only
 * tie-breaker left -- exactly as it was on the tag, where `magasin.css`
 * (`base_mag.html:33`) loaded after `bootstrap.min.css` (`:30`) and its 4rem
 * won. Three stored elements spell both names and are what moves if this
 * section is inserted above the utilities instead: `mag.Entry` pk 242 and
 * pk 277 `<div class="m-b-4 mb-4 panel-group">`, and pk 272
 * `<hr class="m-t-4 mt-4">`. They would render at 24px where the tag rendered
 * 64px, and no visual baseline can see it -- the fixture bodies carry no class
 * attributes, which is #1118's stated invariant. Gate 10 asserts it on pk
 * 272's shape, an element spelling BOTH names; an element carrying only
 * `m-b-4` passes either way and proves nothing about the order.
 *
 * THE `@font-face` SHIPS WITH `.fontello-icon`, and that is the finding of
 * this cluster. All 34 uses are `<i class="fontello-icon icon-quote">` holding
 * a single character, U+E800, inside cluster 4's
 * `.article-content .blockquote p.quote-sign` -- the big rotated orange quote
 * mark. `fontello.ttf` contains exactly one codepoint, U+E800, so the class
 * exists for no other purpose than to select that font. Carrying the class
 * rule alone leaves `font-family:"fontello"` resolving to nothing and the
 * character rendering as a fallback box: verbatim on its face, inert on the
 * page -- the same shape as cluster 4's blanked em-dash and cluster 5's
 * five-arm selector, and equally invisible to the visual baselines.
 * `mag-components.css` names the two as one unit when it lists what it
 * dropped ("`.fontello-icon` + its `@font-face`"), and the font files have
 * been sitting unreferenced in `static/fonts/fontello/` ever since. An
 * `@font-face` has no selector and cannot take the `.article-content` prefix,
 * but it declares nothing on its own: it is inert until some rule asks for
 * `font-family: fontello`, and the only rule that ever will is the scoped one
 * below it. `icon-quote`, the other token on those 34 elements, is correctly
 * absent from #1118's 61 -- the tag's `magasin.css` mentions it only inside a
 * comment, so it was inert on the tag too.
 *
 * EXCLUDED: 10 tag rules, none of them work.
 *   - `.card-default` and `.card-lightgrey` are magasin's too and are ALREADY
 *     HERE -- cluster 2 folded them into the cards section. Re-checked in
 *     selector position on master before writing this.
 *   - `.m-b-5`, `.m-b-6`, `.m-t-5`, `.m-t-6`, `.m-t-7`, `.m-t-8` and `.m-t-10`
 *     are the dead siblings of the two live spellings. The tag defines
 *     `.m-b-4`..`.m-b-6` and `.m-t-4`..`.m-t-10`; the stored bodies use none
 *     of the seven, so porting them would add CSS no page can reach -- the
 *     call cluster 2 made on `card-text` and cluster 5 made on `.mb-5,.my-5`.
 *   - `.m-t-9` is the eighth sibling and is a different case: it is on master
 *     already, in `mag-components.css`, unscoped and deliberately so, because
 *     `mag-waypoint.js` applies it to template chrome at scroll time. Leave it
 *     where it is; a scoped copy here would not reach that element.
 *
 * NO CASCADE INVERSION. Re-run of `c5_cascade_check.py` over the real bodies:
 * the six land on `<div>`, `<blockquote>`, `<i>` and `<hr>`, and the only
 * (0,1,1) rules on this surface are `.article-content p` and
 * `.article-content ul, .article-content ol`, which reach none of them. The
 * script's control still flags `.lead`, and only `.lead`, so the all-clear is
 * a measurement rather than a silence.
 *
 * Rules below in `magasin.css`'s own source order, which is also what the two
 * `brd-*` need: all 7 elements spell `class="brd-rgt brd-wht col-xs-6"`, and
 * `.brd-wht`'s `border-color: white` only reaches `.brd-rgt`'s
 * `border-right: 1px solid #efefef` shorthand by landing after it, as it did
 * at `magasin.css:409` then `:411`. (`col-xs-6` is the Bootstrap 3 spelling
 * 4.6.2 dropped -- inert on the tag, and correctly not shimmed.)
 */

.article-content .brd-rgt {
  border-right: 1px solid #efefef;
}

.article-content .brd-wht {
  border-color: white;
}

.article-content .blockquote-brd {
  border-top: 1px solid #efefef;
  border-bottom: 1px solid #efefef;
  padding-top: 1.5rem;
  padding-bottom: 3rem;
}

/* Unscopable by construction -- see THE `@font-face` SHIPS WITH
 * `.fontello-icon` above. Verbatim from magasin.css, cache-buster query and
 * all; the files it names are the ones already in static/fonts/fontello/. */
@font-face {
  font-family: 'fontello';
  src: url("../fonts/fontello/fontello.f3de25119db5.eot?55903339");
  src: url("../fonts/fontello/fontello.f3de25119db5.eot?55903339#iefix") format('embedded-opentype'),
       url("../fonts/fontello/fontello.a310d9a34c5d.woff?55903339") format('woff'),
       url("../fonts/fontello/fontello.37d5cc6d67c9.ttf?55903339") format('truetype'),
       url("../fonts/fontello/fontello.aba072f1139d.svg?55903339#fontello") format('svg');
  font-weight: normal;
  font-style: normal;
}

.article-content .fontello-icon {
  font-family: "fontello";
  font-style: normal;
  font-weight: normal;
  speak: none;

  display: inline-block;
  text-decoration: inherit;
  text-align: center;

  /* For safety - reset parent styles, that can break glyph codes*/
  font-variant: normal;
  text-transform: none;

  /* fix buttons height, for twitter bootstrap */
  line-height: 1em;

  /* Font smoothing. That was taken from TWBS */
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

.article-content .m-b-4 {
  margin-bottom: 4rem !important;
}

.article-content .m-t-4 {
  margin-top: 4rem !important;
}
