/*
 * Nuclear Resister — WordPress body-content styles (.nr-wp-content)
 * ===========================================================================
 *
 * THE ONE COPY of the editorial rules applied to WordPress `content.rendered`
 * HTML. Both templates that render a WP body link this file:
 *
 *   src/pages/[...slug].astro                    — interior pages
 *   src/pages/[year]/[month]/[day]/[slug].astro  — single posts
 *
 * Typography: Verdana throughout (device fonts, no webfonts). 16px floor,
 * non-negotiable. Navy links → Rust on hover/focus. Chronicle, not brochure.
 *
 * ---------------------------------------------------------------------------
 * WHY public/ AND NOT src/styles/
 * ---------------------------------------------------------------------------
 * These rules used to live in an Astro-scoped <style> block inside EACH of the
 * two templates. Astro scopes per component, so a rule in one template never
 * reaches the other — every shared rule had to be written twice and kept in
 * sync by hand — and it compiled the selectors to
 * `.nr-wp-content[data-astro-cid-<hash>] p`, where the hash changes whenever
 * the component changes.
 *
 * The Lowthian Editor's style bridge fetches the front end's content CSS and
 * injects it into the WordPress block-editor canvas, so what the client sees
 * while editing is what the visitor gets. That needs (a) a stable URL and
 * (b) selectors with no build hash in them. public/ is copied to dist/
 * verbatim, so this file is served at exactly /wp-content.css.
 *
 * Load ORDER for any consumer, including the bridge:
 *     /tokens.css   then   /wp-content.css
 * Every value below is a var(--nr-*); without the tokens file this stylesheet
 * renders as unstyled text. Do not inline a :root block here to avoid that —
 * the palette has one home (public/tokens.css) and this file is not it.
 *
 * ---------------------------------------------------------------------------
 * WHY EVERY SELECTOR IS `.nr-wp-content[class]` AND NOT `.nr-wp-content`
 * ---------------------------------------------------------------------------
 * `[class]` matches any element carrying a class attribute — which every
 * `.nr-wp-content` does by definition — so it selects exactly the same
 * elements. It is here for SPECIFICITY, and it is load-bearing.
 *
 * Astro's scoped output was `.nr-wp-content[data-astro-cid-x] p` = (0,2,1).
 * Written plainly, `.nr-wp-content p` is (0,1,1) — one class lighter. That
 * single step down is enough to lose a fight these rules currently win:
 * src/styles/global.css carries `.nr-wp-content .wp-caption-text` at (0,2,0),
 * which would then beat the `p` and `figcaption` rules below and change every
 * caption's margins on 1,282 pages carrying a wp-caption. `[class]` restores
 * the exact (0,2,x) the scoped selectors had, so the cascade lands where it
 * landed before the extraction. Measured, not assumed — the before/after
 * computed-style diff is what found it.
 *
 * If you add a rule here, keep the `[class]`.
 *
 * ---------------------------------------------------------------------------
 * WHAT IS DELIBERATELY *NOT* IN THIS FILE
 * ---------------------------------------------------------------------------
 * The two templates were never identical, and the difference is a decision
 * somebody made, not drift. Rules that change how content LOOKS on interior
 * pages only — chiefly the 480px image cap, which is subject to an OPEN
 * decision of Geoffrey's about whether to apply it to the ~975 posts too —
 * stay in [...slug].astro as scoped overrides on top of this file. Rules that
 * only stop content from overflowing a narrow viewport are shared and live
 * here.
 *
 * That is the test when you add a rule:
 *   changes how content LOOKS         → interior-only, and check the parked
 *                                       image-cap decision first
 *   stops content overflowing a narrow
 *   viewport / is already in both      → here
 *   is a BOX or LAYOUT property on the
 *   .nr-wp-content WRAPPER itself      → never here, see that rule's comment
 *                                       (the editor canvas owns that box)
 *
 * That third line is a hard rule, not a judgement call: the style bridge
 * rewrites the wrapper rule onto the editor canvas body, where WordPress's
 * theme.json layout already sets the column width. Box properties on
 * DESCENDANTS (p margins, the img max-width, figure spacing) are fine and
 * belong here — they space content inside the column rather than redefining
 * the column.
 *
 * Interior-only overrides currently in [...slug].astro: the image cap
 * (480px/70vh/object-fit + the sizes="auto" definite width), the container
 * padding + flow-root, the <table> rules, and the empty-page placeholder.
 * Do not "unify" any of them into this file without checking back — that
 * would ship a design change under cover of a refactor.
 *
 * Also NOT here: WordPress's alignment classes and the grey caption box
 * (.alignleft/.alignright/.aligncenter/.alignnone/.wp-caption/.wp-caption-text
 * and the float clearfix), and the wrapper's inherited font-family, weight and
 * leading. Those live in public/wp-classic.css because .nr-wp-content appears
 * on FIVE surfaces — these two templates plus contact-us.astro,
 * FutureActionsList.astro and InteriorPageLayout.astro — and WordPress core
 * classes have to work on all of them. This file is linked by the two body
 * templates ONLY; linking it anywhere else changes how those other three
 * surfaces render. (They were in src/styles/global.css until 2026-08-15, which
 * is what this paragraph used to say.)
 *
 * Revisions:
 *   2026-08-16  h1 declared, for the 125 in-content <h1> across 74 posts and
 *               pages this file previously assumed did not exist. Every value
 *               is the one the front end already computes; measured, not
 *               matched by eye. Zero front-end change verified across 9 built
 *               pages chosen for their headings x 7 widths x 51 properties —
 *               style-ab-harness/front-pages, which exists because the classic
 *               fixture's post 417 contains no heading of any level and so
 *               could only ever have reported a pass here.
 *   2026-08-15  Created. Extracted verbatim from the two templates' scoped
 *               <style> blocks — no value changed. Zero visual change
 *               verified by computed-style + bounding-box + pixel diff across
 *               40 pages at two viewports (see PKM/lena-journal.md).
 * ===========================================================================
 */

/* Container.
 *
 * ===========================================================================
 * NO BOX OR LAYOUT PROPERTIES ON THIS RULE. EVER. Not max-width, margin,
 * padding, width, display, float or position. Typography, colour and
 * inherited properties only.
 * ===========================================================================
 * Two independent reasons, either one sufficient:
 *
 *   1. THE EDITOR CANVAS (Wade, 2026-08-15). The style bridge rewrites this
 *      wrapper rule onto the block editor's canvas BODY, and WordPress's
 *      theme.json layout already owns the column width there (1092/1140). A
 *      box property here constrains that canvas a second time and the
 *      editor's column stops matching the live one — which defeats the whole
 *      point of the client editing against the front end's own CSS.
 *
 *   2. THE TWO TEMPLATES DISAGREE ABOUT THE BOX ANYWAY. Interior pages put
 *      padding + display:flow-root on this div; posts take their padding from
 *      the .nr-post wrapper instead. Anything box-shaped put here would
 *      double it on every post.
 *
 * If the front end genuinely needs a box property on this wrapper, it goes in
 * the template as a scoped rule and gets raised with whoever owns the editor
 * bridge — it does not come here and it does not get silently dropped.
 * Currently scoped in [...slug].astro for exactly this reason:
 * `padding: var(--nr-space-8) 0 var(--nr-space-10)` and `display: flow-root`.
 *
 * overflow-wrap is fine and belongs here: it is an INHERITED text property,
 * not a box property, it constrains nothing about the column, and it is here
 * for a measured a11y reason —
 *
 * Two decades of pasted body copy contain strings with no soft wrap
 * opportunity — bare URLs printed as link text, and runs of &nbsp; from
 * Outlook-pasted copy. Either one sets a line box wider than a 320px viewport
 * and scrolls the whole page sideways. The rendered a11y gate measured this in
 * POSTS: one post's bare URL reached 458px against a 320px viewport, and an
 * Outlook &nbsp; run produced an 845px line box. overflow-wrap is INHERITED,
 * so declaring it on the container covers every descendant without repeating
 * it per element; break-word rather than anywhere, so ordinary words still
 * wrap at ordinary places and only an otherwise-unbreakable run gets split.
 * Added to both templates 2026-08-06 alongside the .wp-caption rule below —
 * same defect class. */
.nr-wp-content[class] {
  overflow-wrap: break-word;
}

/* IN-CONTENT h1 — the level this file used to assume was not here.
 * ===========================================================================
 * The comment that stood here until 2026-08-16 said "h1 is OUTSIDE this div:
 * WP body content starts at h2." The page h1 is indeed outside — interior
 * pages get theirs from InteriorPageLayout, posts from .nr-post__title — but
 * the assumption that no SECOND one appears inside the body was never true.
 * Counted from the content snapshot: 125 in-content <h1> across 74 posts and
 * pages, 116 of them in classic markup. Fourteen years of contributors pasting
 * in a headline.
 *
 * Because nothing declared them, they were the one heading level being styled
 * entirely by the browser's own defaults plus global.css's `* { margin: 0 }`
 * reset. That works on the front end and cannot work in the editor canvas,
 * which has core's stylesheet where the front end has a UA default and does not
 * have the reset at all. Measured in the real editor on post 15315: 36px
 * instead of 32px, weight 400 instead of 700, leading 40.5px instead of 52.8px.
 *
 * EVERY VALUE BELOW IS THE ONE THE FRONT END ALREADY COMPUTES, and each was
 * read off the built pages rather than reasoned about — the whole point is that
 * nothing moves on the 74 live pages. Which is also why this rule does NOT
 * simply join the h2-h6 rule underneath it, tempting as that looks: on the
 * front end today an in-content h1 differs from its siblings in three ways.
 *
 *   font-size  2rem, flat. The UA default is 2em, and the wrapper sits at the
 *              1rem root size, so both are 32px — measured at all seven
 *              viewport widths, unchanged at each. rem rather than em because
 *              the canvas is precisely the surface where the wrapper's own
 *              size is set by somebody else's stylesheet, and an em here would
 *              follow it.
 *   line-height --nr-leading-body (1.65), NOT the --nr-leading-headline (1.3)
 *              that h2-h6 use. An undeclared h1 inherits the body's leading, so
 *              1.65 is what 52.8px comes from. Stated as the ratio, not as
 *              52.8px, so it stays correct if the size ever moves.
 *   color      --nr-news-body (black), NOT the --nr-news-headline (blue) that
 *              h2-h6 use, for the same reason: it inherits.
 *
 * Those three differences are not a design anybody chose — they are what an
 * undeclared element does. Making an in-content h1 look like its siblings is a
 * real change to 74 live pages and therefore Willa's call, not this refactor's.
 * This rule freezes today's behaviour so the editor can show it; it is the
 * right place to make that change WHEN it is made.
 *
 * margin: 0 is the global.css `* { margin: 0 }` reset, restated. That reset is
 * in the Astro bundle and so is not bridged; without this the canvas gives an
 * in-content h1 the UA's 0.67em block margins and the spacing stops matching.
 * It does NOT flatten the one measured h1 that has real margins — post 15315's
 * block heading carries `style="margin-top:var(--wp--preset--spacing--40)"`
 * inline, and an inline style beats a stylesheet rule on both surfaces. The
 * front-end diff is what established that, not the reasoning.
 *
 * Verified no-op: 9 built pages x 7 widths x 51 properties, 0 differing values
 * (style-ab-harness/front-pages). */
.nr-wp-content[class] h1 {
  font-family: var(--nr-font-body);
  font-size: 2rem; /* 32px */
  font-weight: var(--nr-weight-bold);
  line-height: var(--nr-leading-body);
  color: var(--nr-news-body);
  margin: 0;
}

/* Headings within WP content — h2 down to h6.
 * Left exactly as they were, deliberately. All six of the properties an
 * undeclared heading would have to get from a UA default or from global.css's
 * reset — family, weight, size, leading, colour, margin — are stated here, so
 * these five levels carry nothing into the canvas that the canvas has to
 * supply. That is what made h1 the only gap. Front-end values measured across
 * the same nine-page set as h1. The canvas side has to be confirmed by a probe
 * against the real editor, not by style-ab-harness/canvas-fixture: that
 * fixture's canvas arm carries a model of core's LAYOUT contribution only
 * (core-model-A/B.css) and not core's actual editor stylesheet, so it reports
 * LESS divergence than the editor really has. It is the instrument that missed
 * the wrapper's font-weight. */
.nr-wp-content[class] h2,
.nr-wp-content[class] h3,
.nr-wp-content[class] h4,
.nr-wp-content[class] h5,
.nr-wp-content[class] h6 {
  font-family: var(--nr-font-body);
  font-weight: var(--nr-weight-bold);
  color: var(--nr-news-headline);
  line-height: var(--nr-leading-headline);
  margin: var(--nr-space-8) 0 var(--nr-space-4);
}

.nr-wp-content[class] h2 {
  font-size: clamp(1.25rem, 2.5vw, 1.5rem); /* ≥20px */
}

.nr-wp-content[class] h3 {
  font-size: clamp(1.125rem, 2vw, 1.25rem); /* ≥18px */
}

.nr-wp-content[class] h4,
.nr-wp-content[class] h5,
.nr-wp-content[class] h6 {
  font-size: 1rem; /* 16px — at the floor */
}

/* Body text */
.nr-wp-content[class] p {
  font-family: var(--nr-font-body);
  font-size: var(--nr-text-body); /* 16px */
  line-height: var(--nr-leading-body);
  color: var(--nr-news-body);
  margin: 0 0 var(--nr-space-5);
}

/* Links — Navy default, Rust on hover/focus, underline always. */
.nr-wp-content[class] a {
  color: var(--nr-news-headline);
  text-decoration: underline;
  text-underline-offset: 2px;
}

/* text-decoration is restated here only because the interior template's copy
   restated it. It is the same value the base rule above already sets, so it
   changes nothing either way — kept so the two originals collapse to one file
   with no value dropped. */
.nr-wp-content[class] a:hover,
.nr-wp-content[class] a:focus {
  color: var(--nr-rust);
  text-decoration: underline;
}

/* Focus ring — WCAG 2.4.7 visible focus indicator. 3px Rust on white is
   5.14:1, past the 3:1 floor for a focus indicator. */
.nr-wp-content[class] a:focus-visible {
  outline: 3px solid var(--nr-rust);
  outline-offset: 2px;
  border-radius: 2px;
}

/* Lists */
.nr-wp-content[class] ul,
.nr-wp-content[class] ol {
  font-family: var(--nr-font-body);
  font-size: var(--nr-text-body);
  color: var(--nr-news-body);
  line-height: var(--nr-leading-body);
  margin: 0 0 var(--nr-space-5);
  padding-left: var(--nr-space-8);
}

.nr-wp-content[class] li {
  margin-bottom: var(--nr-space-2);
}

/* Images — the SHARED baseline: fit the column, keep the aspect ratio, centre
 * a standalone photo. This is the post template's rule, which is the
 * uncapped behaviour every .nr-wp-content surface had before 2026-08-06.
 * [...slug].astro overrides max-width/max-height/object-fit on top of it for
 * interior pages only; that cap is a parked decision (see this file's header
 * and the img block in that template).
 *
 * :not([class*="align"]) is load-bearing, not tidiness. This selector is
 * (0,2,1) and outranks the (0,2,0) alignment rules in global.css, so without
 * the exclusion the `margin: ... auto` below silently zeroes the float gutter
 * and body text sits flush against the photo. 622 bare <img class="alignleft">
 * in the built site hit this. Alignment margins are global.css's job. */
.nr-wp-content[class] img:not([class*='align']) {
  max-width: 100%;
  height: auto;
  display: block;
  margin: var(--nr-space-6) auto;
}

.nr-wp-content[class] img[class*='align'] {
  max-width: 100%;
  height: auto;
}

/* Same exclusion, same reason — 1,178 aligned <figure> elements. */
.nr-wp-content[class] figure:not([class*='align']) {
  margin: var(--nr-space-6) 0;
}

/* WP caption divs — WordPress writes a hard inline `style="width: 310px"` on
 * every one of them (1,173 of the 1,174 in the content snapshot carry an
 * inline width; 813 of those are the 310px case). Nothing overrode it, so 21
 * of 40 sampled POSTS scrolled horizontally at a 320px viewport. A stylesheet
 * max-width beats an inline width with no !important needed: inline style wins
 * on `width`, but `max-width` is a different property and clamps the used
 * value whatever set `width`.
 *
 * This rule was ALREADY mirrored into both templates on purpose, while the
 * image cap directly above deliberately was not. That was never an
 * inconsistency to tidy up: this one is pure overflow containment — no visual
 * size change above ~330px, wanted everywhere — whereas the cap changes how
 * big a photo LOOKS, which is the open decision. Its being shared is not
 * licence to share the cap. */
.nr-wp-content[class] .wp-caption {
  max-width: 100%;
}

.nr-wp-content[class] figcaption {
  font-family: var(--nr-font-body);
  font-size: var(--nr-text-body);
  color: var(--nr-news-date);
  text-align: center;
  margin-top: var(--nr-space-2);
}

/* Blockquotes */
.nr-wp-content[class] blockquote {
  border-left: 4px solid var(--nr-rust);
  margin: var(--nr-space-6) 0;
  padding: var(--nr-space-3) var(--nr-space-6);
  font-style: italic;
  color: var(--nr-news-body);
}

/* Horizontal rule */
.nr-wp-content[class] hr {
  border: none;
  border-top: 1px solid #ccc;
  margin: var(--nr-space-8) 0;
}
