/* ============================================================
   BOZA v7 — WordPress adapter.

   What WordPress needs and the prototype did not. Loads after tokens.css and
   base.css, so it wins at equal specificity without reaching for !important.

   THE RULE FOR THIS FILE

   Nothing here is a design decision. A design decision is made in the library
   and syncs down. What belongs here is exactly the set of things that exist
   because the markup is now WordPress's rather than the prototype's: core's
   wrappers, core's layout engine, core's alignment model, and the plugins.

   If a rule in here would be true of the prototype as well, it is in the wrong
   file. Take it up to the library and run node tools/shared.mjs sync.
   ============================================================ */

/* ---------- core's root wrapper ---------- */

/* Everything WordPress renders lives in .wp-site-blocks, which sits between
   <body> and the page. The prototype had no such element, so the page's own
   grounds had nothing between them and the body background. It needs to be a
   plain block-level pass-through and nothing else. */
.wp-site-blocks {
  display: block;
}

/* ---------- the admin bar ---------- */

/* The sticky header sits at the top of the viewport, and so does WordPress's
   admin bar when a person is signed in, which put the bar's first 32px under
   it. The library's header reads its top edge from --hdr-top, 0 on a page.
   WordPress declares the bar's height as a custom property on the html
   element whenever the bar is drawn and never otherwise, so pointing the
   token at it is the whole fix: 32px signed in, 46px signed in on a phone, 0
   signed out and in the canvas (13.0). */
:root {
  --hdr-top: var(--wp-admin--admin-bar--height, 0px);
}

/* The search window and the menu drawer are fixed to the viewport and start at
   its top edge, where the admin bar is, so the bar covered the window's first
   32px: its close button, and the drawer's head with it. The whole window steps
   down by the same amount the header already does, rather than each control
   inside it moving on its own -- one rule, and everything a window holds clears
   the bar. Here rather than in the family, because the bar is WordPress's and
   nothing sits above a window in the prototype (14.25). */
.ov,
.pop-ov {
  top: var(--hdr-top);
}

/* The root padding is the gutter, declared in theme.json so that core can do
   the arithmetic for alignfull. A Section is alignfull and provides the gutter
   again through .container, which is deliberate: a section's ground runs to the
   screen edges and its contents stop at the container. What must not happen is
   the two padding at once, and core's own alignfull rule is what prevents it,
   so useRootPaddingAwareAlignments is on and must stay on. */

/* ---------- core's layout engine ---------- */

/* The page has three regions and they touch: header, main, footer.

   This rule used to give them core's block gap, on the reasoning that an editor
   moving blocks about expects the spacing control to mean something. That is
   true inside the content and false here. `.wp-site-blocks` has exactly three
   children on every page of this site -- the header part, main, and the footer
   part -- and 24px between them is a stripe of paper under the header and
   another one above the footer. The reviewer saw the second of those. It was my own rule.

   Doubled, for the same reason the Section rule is: core's
   `:root :where(.is-layout-flow) > *` computes to one class, a single
   `.wp-site-blocks` ties with it, and a tie goes to whichever came last in the
   head, which is core. */
.wp-site-blocks.wp-site-blocks > * {
  margin-block: 0;
}

/* A Section owns the space above and below it through the padding scale, so two
   Sections in a row must touch. Without this they take the block gap as well and
   every ground change on the site carries a stripe of paper through it: measured
   at 1440, a 24px band of paper between the tint and the warm, which reads as a
   rendering fault rather than as spacing.

   Not scoped to .wp-site-blocks. A Section is almost never a direct child of it
   -- the template puts it inside main, inside post-content -- and both of those
   are layout containers that apply the gap to their own children. The class is
   the one WordPress generates, `wp-block-boza-section`, and the rule follows the
   block wherever the template puts it.

   THE CLASS IS DOUBLED, and that is the whole fix. Core's rule is
   `:root :where(.is-layout-constrained) > *`, which computes to one class of
   specificity: `:root` is the one class, and `:where()` and `*` contribute
   nothing. A single `.wp-block-boza-section` ties with it exactly, and a tie is
   settled by source order -- core prints its global styles inline in the head,
   after an enqueued stylesheet, so core won every time.

   This shipped broken for three rounds. The rule was there, it matched, and it
   lost, which is the worst of the three ways a rule can fail: the CSS reads as
   correct, the class is right, nothing reports anything, and there is 24px of
   paper between every pair of coloured bands on the site. It was found in review, by
   looking at a page, and the screenshot I had checked it against was not precise
   enough to show 24px between two sections that were supposed to touch.

   Doubling the class is the library's own idiom for exactly this and it is in
   the house rules: when a rule must beat another at equal specificity, double
   the class, do not reach for !important. */
.wp-block-boza-section.wp-block-boza-section {
  margin-block: 0;
}
/* A cover's crumb bar is a sibling the cover's own block draws before its
   section, paper above the picture (12.3a, B8). It sits in the same layout
   container and core gives it the same gap; the same doubled class takes it
   away, so the two sections touch through the bar, which is what the
   invariant measures. */
.crumb-bar.crumb-bar {
  margin-block: 0;
}

/* ---------- loose blocks in a BOZA container ---------- */

/* Two paragraphs in a column were touching. Measured on the Columns demo: every
   stacked pair inside a column, heading to paragraph and paragraph to
   paragraph, at exactly 0px.

   The cause is that the prototype never has loose prose. Its markup always wraps
   running text in a `.rich`, which carries both the measure and the rhythm --
   `.rich p{margin-bottom:1.1em}`, `.rich>h3{margin:2rem 0 .45rem}` -- so nothing
   in base.css gives two siblings a gap on their own, and `*{margin:0}` at the
   top of the file means they get none. WordPress lets an editor drop blocks
   straight into a container, so the case exists here and did not there.

   The gap is core's `--wp--style--block-gap` and not `.rich`'s rhythm, because
   these are two different things and each should keep one home. `.rich` is
   typographic: an article body, where the space under a paragraph is measured in
   ems of its own type and a heading takes more air above it than below. This is
   editorial: an editor stacked two blocks and expects the spacing control to
   mean something. The theme emits `.rich` for a real article body, and that
   keeps its own rhythm untouched.

   `:where()` holds the specificity at zero, so any component with an opinion
   wins. A card's own rhythm is `.card h3{margin-bottom:9px}` and a tile's is
   `.tile-basic p+p{margin-top:.8em}`; both beat this and both should, which is
   why neither container is named here. */
:where(.boza-section__inner, .wp-block-boza-column, .wp-block-boza-tab) > * + * {
  margin-block-start: var(--wp--style--block-gap, 1.5rem);
}

/* A tab's panel is the same kind of place (14.56): anything can be put in it,
   and a paragraph, a list and a link in one sat at 0px, which the Patterns
   session met building sections and worked round with a column.

   Three smaller places take loose blocks too, and each has its own rhythm for
   paragraphs, which stays: a tile's .8em between them, a notice's and a
   popup's own. What none of them said is what a list is to the paragraph
   either side of it, so a list sat flush against both. It takes the tile's
   .8em, the tightest of the three; the popup's paragraphs already keep 1em
   under themselves, which the list's space collapses into. Found by putting the
   same three blocks in every container that takes them and measuring. */
:is(.tile-basic, .tile-img .body, .alert > div, .pop) > * + :is(ul, ol),
:is(.tile-basic, .tile-img .body, .alert > div, .pop) > :is(ul, ol) + * {
  margin-block-start: .8em;
}

/* A tile's closing action sits at its foot, level with its neighbours' (14.73).
   Two things had stopped it. The rule above spaces whatever follows a list, so
   a button row under a list took .8em and followed the words instead of the
   card's `margin-top:auto`; and a picture tile's own rule pushed a bare
   `.link-more`, which since the Buttons block sits inside a button row, so it
   pushed nothing. Found on a row of three tiles whose links stood at three
   heights. Where there is room, the auto margin takes it and the action stays
   where its neighbours' are.

   The padding is the least air above the action when a tile is full: 18px, the
   library's own figure for a card's closing link and a picture tile's. 14.73
   gave a word tile .8em, about 13px, and a picture tile nothing at all, so in
   the fuller of two picture tiles the button stood on the list above it, 0px
   under its last line, where its neighbour had room to spare. Found in review
   on the services page (14.97). */
.card > .btn-row:last-child,
.tile-img .body > .btn-row:last-child {
  margin-block-start: auto;
  padding-block-start: 18px;
}
/* a one-line form keeps the library's own distance from what precedes it, the
   16px of .nl-form, rather than the rhythm's (13.2d) */
:where(.wp-block-boza-column) > .form-line {
  margin-block-start: 0;
}

/* ---------- the measure, inside a column ---------- */

/* Running text stops at the measure wherever it is, and a column is not an
   exception. The thirds layout's wide middle column measures 812px, which is
   about a hundred and thirty characters a line, and the measure exists because
   that is hard to read. The column's width is still the column's: the text sits
   at the start of it rather than centred in it, so the column edge a reader
   follows down the page is where it always was.

   The review's condition, and it is the right one: an editor can overrule it. The way out
   is the same one a Section already offers and the same word the theme already
   uses everywhere else for this idea -- Wide means fill the box you are in. A
   paragraph set Wide inside a column takes the whole column. */
:where(.wp-block-boza-column) > :where(p, h1, h2, h3, h4, h5, h6, ul, ol, dl, blockquote) {
  max-width: 46rem;
}
/* One paragraph style carries a cap of its own, and a wider one: small print
   stops at 54rem in the library, and a class outranks the zero-specificity cap
   above. So in a column as wide as the split layout first column, 755px at 1440,
   the footer line under the newsletter heading ran past the measure (13.2d,
   found by the invariant). Small print is held to the measure by name, in a
   column and in a Section alike, and Wide still takes the whole box. */
:where(.wp-block-boza-column, .boza-section__inner) > .note:not(.alignwide) {
  max-width: 46rem;
}
:where(.wp-block-boza-column) > .alignwide {
  max-width: none;
}
/* and the centred measure, the third declared width (13.1) */
:where(.wp-block-boza-column) > .aligncenter {
  margin-inline: auto;
}

/* ---------- text centred means the box is centred too (14.42) ----------

   A block capped at the measure sits at the start of its box, which is the
   rule above and is right for running text: the edge a reader follows down the
   page stays where it was. It is wrong for a block whose words are centred. The reviewer
   built a page with every block's text centred and met two centre lines on one
   page: the words on 510 and the button row on 720 at 1440, because the words
   were centred inside a 736px box hugging the left of a 1156px section. The
   starter pattern drawn from that page carried it.

   So a block that says its words are centred is centred in its box as well.
   The two ways of saying it agree, which is what a person expects when they
   press the button; a section set to the middle line does this already for
   everything in it, and this is the same thing said for one block. */
:is(.boza-section__inner, .wp-block-boza-column) > .has-text-align-center {
  margin-inline: auto;
}

/* ---------- a section on the middle line (14.7) ---------- */

/* The library centres what stands in the container, `.sec-center>.container>*`,
   and a Section's blocks stand one wrapper deeper, in `.boza-section__inner`, so
   the rule is said again for them: anything with a measure of its own, a lead or
   a line of small print, keeps it on the middle line. The rhythm between them is
   the library's own and needs nothing here, because it is written between
   neighbours. */
.sec-center .boza-section__inner > * {
  margin-inline: auto;
}

/* A row of large links is a row, not running text. The Section caps a `ul` at
   the measure, as a column does, and the 404's six links wrapped into two rows
   of a 736px column at 1440 where the library draws them in one line across the
   page (14.7, measured). The row says so, at a class, which outranks both caps. */
:is(.boza-section__inner, .wp-block-boza-column) > .e-big {
  max-width: none;
}

/* ---------- headings ---------- */

/* Core writes heading levels as .wp-block-heading rather than as h1..h6 alone,
   and a heading inside a block gets no element selector at all. base.css styles
   h1 to h4, which covers every heading core emits, and this covers the one it
   emits that base.css does not: a heading at level 5 or 6, which the library
   never needed and an editor can still choose. */
h5, h6, .wp-block-heading:is(h5, h6) {
  font-family: var(--serif);
  font-weight: 520;
  letter-spacing: -.008em;
  line-height: 1.14;
  font-size: 1.06rem;
}

/* ---------- what core adds to an image ---------- */

/* An image inherits its slot's corners. In the prototype that is written on the
   media frame; core wraps its image in a figure and puts the caption inside it,
   so the rule needs the figure as well or the caption sits against a square
   corner under a rounded picture.

   And the figure's own corner is the house's (14.31). Every picture this theme
   draws is rounded -- the gallery's tiles, a tile's photograph, a card's, a
   cover's -- and core's Image block was the one that came out square, because
   it inherited a corner from a figure that had none. The reviewer found it looking for a
   rounded corner and then trying core's Rounded style, which is a circle and is
   for a portrait; it still is, and it still wins, because core's own rule names
   the style and this one does not. */
.wp-block-image {
  border-radius: var(--r-tile);
}
.wp-block-image img {
  border-radius: inherit;
  display: block;
}
/* The article's own column keeps the Section's gutter and not a second one
   (14.31).

   The three single templates give their post-content a constrained layout,
   which is what makes Wide a width an editor can pick rather than one only a
   pattern can write. Core's constrained layout brings the root padding with it,
   and inside a Section that is the gutter said twice: the article moved 32px in
   from both sides and its wide picture lost 64 of its 940. So the column gives
   the padding back, and only the column: a page's content is constrained too,
   it stands in `main` with no Section around it, and there the padding is the
   only thing between a bare paragraph and the screen's edge. `rich` is what
   tells them apart, since it is the class the article's block style writes. */
.wp-block-post-content.rich.has-global-padding {
  padding-inline: 0;
}

/* A picture beside the words, in a Section (14.31).

   base.css draws this for the article body, where `--col` is how a child says
   how wide it is. A Section has no such column: its children are as wide as the
   container and a float with no width floats nothing. So the width is said here,
   in the one place that knows what a Section is, and the two rules agree on the
   same numbers: a little under half, never past 360px, and nothing at all below
   700px, where half a phone is a thumbnail. */
:where(.boza-section__inner) > :is(.alignleft, .alignright) {
  max-width: min(46%, 360px);
  margin-block: .5rem 1.3rem;
}
.boza-section__inner > .alignleft {
  float: left;
  margin-inline: 0 1.9rem;
}
.boza-section__inner > .alignright {
  float: right;
  margin-inline: 1.9rem 0;
}
@media (max-width: 700px) {
  .boza-section__inner > :is(.alignleft, .alignright) {
    float: none;
    max-width: none;
    margin-inline: auto;
  }
}
/* A list in running text, in a Section (14.31). base.css gives a prose list its
   indent back inside `.rich`; a page's list is not inside one, because a Section
   holds its blocks directly. The same two numbers, said for that structure. */
:where(.boza-section__inner) > :is(ul, ol):not([class]),
:where(.boza-section__inner) > :is(ul, ol).wp-block-list {
  padding-inline-start: 1.45em;
}
:where(.boza-section__inner) > :is(ul, ol):not([class]) > li,
:where(.boza-section__inner) > :is(ul, ol).wp-block-list > li {
  margin-bottom: .35em;
}
.wp-block-image figcaption {
  color: var(--ink-faint);
  font-size: var(--fs-small);
  margin-top: 10px;
}

/* And on a dark ground (14.62, D189). The grounds dress a heading and a paragraph
   by descent and say nothing about a caption, so an image's credit on a section
   turned to the accent kept the faint ink it has on paper and read at 1.55 to 1.
   base.css says the same for the captions the library draws, and in the same tier;
   this is core's own
   image block, which the library has no name for. A caption on a light surface
   standing on a dark ground is not this: that is base.css's list, and it wins by
   being the more particular rule. */
:is(.sec-green, .sec-ink, .on-ink) .wp-block-image figcaption {
  color: var(--on-ink-dim);
}

/* ---------- the skip link ---------- */

/* Core prints its own skip link with inline styles and a colour scheme of its
   own. It is the first thing a keyboard user meets on every page, so it is
   dressed like the rest of the site rather than like a default. */
.skip-link.screen-reader-text:focus {
  background: var(--ink);
  color: var(--on-ink-fg);
  font-family: var(--sans);
  font-size: var(--fs-small);
  border-radius: var(--r-sm);
  padding: 12px 20px;
  left: var(--gutter);
  top: 12px;
  text-decoration: none;
}

/* ---------- the template part that ate the sticky header ---------- */

/*
 * WordPress wraps every template part in a div of its own. That div is the
 * header's containing block, and it is exactly as tall as the header -- so
 * `position: sticky` had nowhere to travel and the bar scrolled away with the
 * page, silently, while every computed style said "sticky".
 *
 * `display: contents` takes the wrapper out of the box tree without taking the
 * header out of the document, so the containing block becomes the page. Scoped
 * to the part that actually holds the bar, because a wrapper with no box is the
 * right answer only where the wrapper was doing nothing but wrapping.
 */
.wp-block-template-part:has( > .hdr ) {
	display: contents;
}

/* ---------- the article row's third child ----------
   The library's article row holds two things, the prose and the rail, and its
   70px gap was written for the space between them. In WordPress the foot of
   the article is a block of its own and comes third, landing under the prose
   in a row of the grid's own making, and the same 70px opened up above it. The
   foot carries its own space, as the specimen's does; the row keeps its column
   gap and gives up the row gap it never needed. */
.article-row {
  row-gap: 0;
}

/* ---------- a wide block in the reading column ----------
   The column lets a child break its measure by setting --col, and the
   specimen's figures and notices carry the family's own art-wide for it. A
   block an editor sets to Wide carries WordPress's alignwide instead, and it
   means the same thing here: the whole 940px block, and nothing past it. */
.rich.art-column > .alignwide {
  --col: 100%;
}

/* ---------- an uploaded logo keeps its proportions ----------
   The library's mark is a square drawing, and the compact bar sets both its
   width and its height. An uploaded logo is rarely square: its height follows
   the bar and its width follows the file (inc/header-markup.php writes the
   measured width, so nothing moves while it loads). */
.brand img.mk {
	width: auto;
	height: 36px;
	max-width: 40vw;
}

.compact-on.scrolled .hdr .brand img.mk {
	width: auto;
	height: 30px;
}

/* ---------- a second line under the name ----------
   Drawn only where a site answers the boza_brand_tagline filter: the name
   keeps its size and the line under it is the small caps of a kicker. */
.brand .wm-sub {
	display: block;
	margin-top: 5px;
	font-family: var(--sans);
	font-size: .62rem;
	font-weight: 600;
	letter-spacing: .2em;
	line-height: 1;
	text-transform: uppercase;
	color: var(--amber-ink);
	transition: opacity var(--t-fast) linear;
}

.place-over-dark:not(.scrolled) .hdr .brand .wm-sub,
.site-foot .brand .wm-sub,
.bg-ink .brand .wm-sub {
	color: var(--amber-soft);
}

/* A media card's picture follows the card's focus point too (Dorthe Broeng migration, 2026-10-14). */
.tile-img .media > .plate {
	object-position: var(--tile-focal, 50% 50%);
}

/* A List block inside a Questions answer keeps only its own marks: the answer's dot for plain list items
   (.acc-body .rich li::before) was drawn in front of the List block's ticks as well (Dorthe Broeng migration, 2026-10-15). */
.acc-body .rich .wp-block-boza-list li::before {
	content: none;
}
