/*
Theme Name:   Northampton Information Hub
Theme URI:    https://git.sr.ht/~nikkilol/nohoinfohub
Template:     mistify
Author:       Lamagna & Finkel Consulting, Inc.
Author URI:   https://lamagnafinkel.com
Description:  Child theme of Mistify for the Northampton Information Hub.
              All customization belongs here. The parent theme is a
              third-party product kept up to date by WP Engine's Smart Plugin
              Manager, so anything written into it is destroyed on the next
              update.
Version:      0.10.2
License:      Proprietary
Text Domain:  nih
Requires PHP: 8.4
*/

/*
 * Note on load order: with the Kubio page builder active, the parent enqueues
 * its own resources/theme/fse-base-style.css under the handle 'mistify-theme'
 * and does NOT enqueue this file. functions.php enqueues it, declaring
 * 'mistify-theme' as a dependency so these rules land after the parent's.
 */

/* ==========================================================================
   Brand palette — "Muted Clown"
   ==========================================================================

   Source of truth: client-assets/Muted Clown - Color Scheme .png. The hex
   values below were sampled from that file, not eyeballed.

   WHY THIS IS CSS AND NOT A DATABASE CHANGE
   -----------------------------------------
   Kubio keeps a six-colour palette in a `kubio-globals` post and emits it as
   custom properties in an inline <style> in the document head:

       :root { --kubio-color-1:3,169,244; ... }
       .has-kubio-color-1-background-color { background-color: rgb(var(--kubio-color-1)) }

   Every colour is defined in that one block and nowhere else, and blocks
   reference the properties rather than literal values — the front page holds
   147 palette references against 9 hardcoded values. Redefining the
   properties here therefore recolours the whole site, and because this
   stylesheet is enqueued long after that inline block, an equal-specificity
   :root rule wins on order alone.

   The alternative was editing the palette in Kubio's UI, which writes to the
   database. That works too, but the database is not version controlled and
   does not survive `bin/seed` — see docs/SEED.md. This does both.

   Note the unusual value format: Kubio stores each colour as a bare `R,G,B`
   triplet, not a colour value, so it can compose `rgba(var(--x), 0.5)` for
   transparency. Overrides must keep that shape or every consuming rule
   breaks.

   CONTRAST
   --------
   Measured against WCAG 2.1 on white:

       indigo  #3D3DA1   8.82   carries white text
       grey    #6F6F75   4.99   passes on white; FAILS on cream (4.16)
       red     #C9443E   4.79   carries white text
       orange  #C45214   4.60   carries white text (darkened — see below)
       sage    #819E80   2.94   large text only — needs dark text on it
       yellow  #F8D849   1.41   background only
       cream   #FCE8C6   1.20   background only
       bone    #E5E1DA   1.30   background only

   Two rules fall out of that and are easy to break by accident:
   sage never carries white text, and the muted grey must not sit on a cream
   background.

   THE ORANGE IS DARKENED FROM THE SUPPLIED BRAND VALUE
   ----------------------------------------------------
   The supplied orange is #EA7333, which measures 3.00 against white and so
   can only ever carry ink. The client asked to be able to set white on orange
   and said the hex need not be exact in every application, so slot 2 is
   #C45214 instead: the same colour taken darker until white clears AA.

   Derived by holding the brand's hue and saturation (H 21.0, S 81.3%) and
   lowering lightness 55.9% -> 42.5%, the first step that reaches 4.6. Holding
   saturation is the part that matters. The obvious alternative — scaling the
   channels toward black — also reaches 4.6, at #B85B28, but drops saturation
   to 64% and reads visibly browner. Side by side, #C45214 reads as the brand
   orange a shade deeper, which is what "stay visually very close" has to mean.

   One override covers both block systems. Kubio's own blocks consume
   rgb(var(--kubio-color-2)) directly, and WordPress emits its preset as
   --wp--preset--color--kubio-color-2: rgba(var(--kubio-color-2), 1), so core
   blocks chain back to the same property. That matters because core writes
   preset backgrounds with !important — unreachable by specificity, but
   redefining the property it reads is not a specificity fight at all.

   The palette has no dark colour, so slot 6 keeps Kubio's near-black for body
   copy. Slot 5 stays white. Neither is a brand colour; they are ink and
   paper, and their variant ramps are left alone as a result.
   ========================================================================== */

:root {
	/* ---- Named tokens -------------------------------------------------
	   The full nine swatches. Slots 1-4 below consume four of these; the
	   rest are here for component CSS, which has no Kubio slot to live in.
	   Standard hex, unlike the Kubio properties further down. */
	--nih-indigo: #3d3da1;
	/* The brand orange as supplied, kept for reference. Not used in a rule:
	   see the note on orange in the contrast section above. */
	--nih-orange-brand: #ea7333;
	--nih-orange: #c45214;
	--nih-yellow: #f8d849;
	--nih-grey: #6f6f75;
	--nih-red: #c9443e;
	--nih-cream: #fce8c6;
	--nih-sage: #819e80;
	--nih-bone: #e5e1da;
	--nih-white: #ffffff;

	/* Not from the palette. Body copy needs a real dark and the swatches
	   do not supply one; the grey manages only 4.99 on white and fails
	   outright on the cream. */
	--nih-ink: #1e1e20;

	/* Semantic aliases. Prefer these in component CSS so a future palette
	   revision is a change here rather than a search across the file. */
	--nih-text: var(--nih-ink);
	--nih-text-muted: var(--nih-grey); /* on white only — see contrast note */
	--nih-accent: var(--nih-indigo);
	--nih-action: var(--nih-orange);
	--nih-surface: var(--nih-white);
	--nih-surface-alt: var(--nih-bone);
	--nih-surface-warm: var(--nih-cream);

	/* ---- Spacing scale -------------------------------------------------
	   One place to tune the page rhythm. The client's note was that pages
	   "feel taller and more spread out than necessary" — this is the half of
	   that which lives in the core-block sections; the Kubio sections carry
	   their own padding and are tuned in the builder to match these values.

	   Sections were 4rem block / 1.5rem inline and the hero 5rem block. */
	--nih-space-section: 2.5rem;
	--nih-space-section-inline: 1.5rem;
	--nih-space-hero: 3rem;
	--nih-space-stack: 1.25rem;

	/* ---- Header clearance ----------------------------------------------
	   Kubio runs the navigation as an overlap header: `.h-navigation__outer`
	   is `position: absolute !important`, so the bar takes no height in the
	   flow and whatever follows starts at y=0 underneath it.

	   The built pages never notice, because the section beneath them begins
	   far enough down to clear it anyway. What does notice is anything
	   bringing its own wrapper — The Events Calendar — and the Kubio
	   templates whose first section carries only the 40px of global section
	   spacing: single, index and search.

	   The bar is not one height. Measured, at three widths that matter:

	     >= 768px   90px   full menu
	     441-767px  56px   menu collapsed to the hamburger
	     <= 440px   92px   collapsed, but "Northampton Information Hub"
	                       wraps to two lines and the bar grows again

	   Each step below therefore leaves about 30-40px between the bar and
	   the content, rather than one value that clears the tallest case and
	   over-pads the shortest. The old single breakpoint at 880px was the
	   one bug worth naming: it dropped the clearance to 96px while the bar
	   was still 90px tall, so 768-880px had 6px of gap. */
	--nih-header-clearance: 7.5rem;

	/* ---- Kubio palette override ---------------------------------------
	   Slot assignment follows how the slots are actually used on the built
	   pages, not their numbering:

	     1  primary accent, 63 references — links, rules, icons
	     2  action, 27 references — buttons, the Donate fill
	     3  tertiary, 3 references
	     4  highlight, 1 reference
	     5  light surface, 29 references — unchanged, white
	     6  dark, 24 references — unchanged, ink

	   Indigo takes slot 1 because it is the only swatch that holds white
	   text, and slot 1 is the one used for text-bearing elements. Orange
	   takes slot 2 so Donate reads as an action, per the content outline's
	   note that it stay visually distinct from the nav links.

	   Variant ramps are generated by lightness offsets of +32/+16/0/-17/-34,
	   matching the spacing Kubio uses for its own ramps. Variant 3 is always
	   the base colour, which is Kubio's convention. */

	/* indigo — primary accent */
	--kubio-color-1: 61, 61, 161;
	--kubio-color-1-variant-1: 164, 164, 221;
	--kubio-color-1-variant-2: 105, 105, 198;
	--kubio-color-1-variant-3: 61, 61, 161;
	--kubio-color-1-variant-4: 37, 37, 98;
	--kubio-color-1-variant-5: 13, 13, 35;

	/* orange — action. Darkened from the supplied brand value; see the
	   contrast section above for the derivation. */
	--kubio-color-2: 196, 82, 20;
	--kubio-color-2-variant-1: 243, 174, 137;
	--kubio-color-2-variant-2: 235, 123, 63;
	--kubio-color-2-variant-3: 196, 82, 20;
	--kubio-color-2-variant-4: 118, 49, 12;
	--kubio-color-2-variant-5: 39, 16, 4;

	/* sage — tertiary */
	--kubio-color-3: 129, 158, 128;
	--kubio-color-3-variant-1: 221, 229, 221;
	--kubio-color-3-variant-2: 175, 193, 174;
	--kubio-color-3-variant-3: 129, 158, 128;
	--kubio-color-3-variant-4: 87, 113, 86;
	--kubio-color-3-variant-5: 49, 64, 49;

	/* yellow — highlight */
	--kubio-color-4: 248, 216, 73;
	--kubio-color-4-variant-1: 254, 249, 226;
	--kubio-color-4-variant-2: 251, 233, 152;
	--kubio-color-4-variant-3: 248, 216, 73;
	--kubio-color-4-variant-4: 226, 186, 9;
	--kubio-color-4-variant-5: 142, 117, 5;
}

/* Kubio collapses the menu at 768px and the bar drops to 56px. */
@media (max-width: 767px) {
	:root {
		--nih-header-clearance: 6rem;
	}
}

/* Below this the logo wraps to two lines and the collapsed bar is 92px —
   taller than the full-width one. Back to the desktop value. */
@media (max-width: 440px) {
	:root {
		--nih-header-clearance: 7.5rem;
	}
}

/* ==========================================================================
   Typography
   ==========================================================================

   The brand fonts are Breul Grotesk Bold for headings and Codec Pro for body.
   Both are commercial and neither is licensed for this site, so these are the
   agreed stand-ins: Archivo for headings, Figtree for body. Both are SIL Open
   Font License 1.1, which permits self-hosting and redistribution — see
   fonts/LICENSE.txt. Swapping in the real fonts later is a change to these two
   custom properties and the @font-face blocks, not a redesign.

   WHY THESE ARE SELF-HOSTED AND NOT LOADED FROM GOOGLE
   ---------------------------------------------------
   The site was loading five families — Open Sans, Mulish, Roboto, Carter One,
   and Poppins — inherited from the Mistify demo content, of which only Poppins
   was ever used. That is the "fonts appear inconsistent across pages/modules"
   report: not a styling mistake so much as five typefaces available for blocks
   to pick from. functions.php now dequeues that stylesheet outright.

   Self-hosting rather than swapping one Google request for another keeps the
   font files under version control with the code that references them, removes
   a third-party request from every page load, and means the fonts cannot
   change underneath us when Google revs a version.

   These are variable fonts covering 400-700 in a single file per subset, so
   the whole typographic range costs two requests per family rather than one
   per weight. Total is 98KB against the five families they replace.

   The unicode-range splits are Google's own and are kept as-is: a visitor
   whose page has no latin-ext characters never downloads that file.
   ========================================================================== */

@font-face {
	font-family: 'Archivo';
	font-style: normal;
	font-weight: 400 700;
	font-display: swap;
	src: url('fonts/archivo-latin.woff2') format('woff2-variations');
	unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
	font-family: 'Archivo';
	font-style: normal;
	font-weight: 400 700;
	font-display: swap;
	src: url('fonts/archivo-latin-ext.woff2') format('woff2-variations');
	unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
	font-family: 'Figtree';
	font-style: normal;
	font-weight: 400 700;
	font-display: swap;
	src: url('fonts/figtree-latin.woff2') format('woff2-variations');
	unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
	font-family: 'Figtree';
	font-style: normal;
	font-weight: 400 700;
	font-display: swap;
	src: url('fonts/figtree-latin-ext.woff2') format('woff2-variations');
	unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

:root {
	--nih-font-heading: 'Archivo', 'Helvetica Neue', Helvetica, Arial, sans-serif;
	--nih-font-body: 'Figtree', 'Helvetica Neue', Helvetica, Arial, sans-serif;
}

/*
 * The families are set in Kubio's global typography rather than overridden
 * here, and that is deliberate.
 *
 * Kubio emits colour as custom properties, which is why the palette above can
 * be redefined in CSS and have the whole site follow. Typography is not the
 * same: Kubio writes the family as a literal into every rule it generates,
 * including per-block rules like `#kubio .style-XPjHw7z7Xik-text` at (1,1,0).
 * There is no property to redefine, and out-specifying every generated rule
 * would mean either !important or depending on those styleRef classes — which
 * are regenerated whenever a block is edited, so a rule keyed to one stops
 * applying without warning.
 *
 * Setting the family at the source instead makes Kubio generate Archivo and
 * Figtree everywhere itself, per-block rules included. The cost is that the
 * assignment is database state; the fonts, the @font-face blocks and the
 * dequeue all live here, so the half that must not drift is in git.
 *
 * The rules below cover what Kubio's globals do not reach: the pages built
 * from core blocks, and anything rendered outside a Kubio wrapper.
 */
body {
	font-family: var(--nih-font-body);
}

h1, h2, h3, h4, h5, h6 {
	font-family: var(--nih-font-heading);
}

/* ==========================================================================
   Page components
   ==========================================================================

   The five pages in the content outline are built from core blocks rather
   than Kubio blocks. Two reasons: core block markup is stable and readable in
   a diff, and the client can edit these pages in the standard editor without
   learning the builder. Kubio still owns the header, footer, and the existing
   Home layout, which is why its palette drives the colours above.

   Mistify is a classic theme with no theme.json, so core's "constrained"
   layout has no content width to constrain to and would run full-bleed. The
   width is therefore set here rather than inherited.
   ========================================================================== */

/*
 * Content width.
 *
 * Mistify ships no theme.json, so WordPress falls back to core's default and
 * caps constrained content at 620px. That is a fine measure for prose and far
 * too narrow for the team grid and the summary list, which were rendering
 * three columns inside 620px.
 *
 * Rather than fight the layout system with negative margins, this feeds it
 * the two sizes it expects. Blocks marked `alignwide` then get the wider
 * value automatically, and the behaviour stays responsive on small screens
 * because core's own media handling still applies.
 */
.nih-hero,
.nih-section,
.nih-footer {
	--wp--style--global--content-size: 46rem;
	--wp--style--global--wide-size: 64rem;
}

.nih-hero,
.nih-section {
	padding: var(--nih-space-section) var(--nih-space-section-inline);
}

.nih-hero {
	padding-block: var(--nih-space-hero);
}

/*
 * A page header runs into the section beneath it, so its own bottom padding
 * and that section's top padding stack into one oversized gap. On Meeting
 * Summaries that measured 104px between the intro line and the filter bar,
 * which is most of what the client meant by wanting the heading, filters and
 * summaries tightened up.
 */
.nih-hero {
	padding-bottom: var(--nih-space-stack);
}

/*
 * Headings arrive with generous top margin from the block editor's defaults,
 * which compounds with section padding at every boundary — the gap between two
 * modules is the first one's padding plus the second's padding plus the
 * heading's margin. Collapsing the leading margin on a section's first child
 * takes one of those three out without touching rhythm inside a section.
 */
.nih-section > :first-child,
.nih-hero > :first-child {
	margin-top: 0;
}

.nih-section > * + * {
	margin-top: var(--nih-space-stack);
}

.nih-hero h1 {
	margin-bottom: 0.5rem;
}

/*
 * A note on the doubled-up selectors below.
 *
 * Mistify and Kubio between them set colour and size on p, a, and headings at
 * two-class specificity. A single class here loses to that regardless of load
 * order, which showed up as an invisible footer and a subhead that rendered as
 * plain body text. Everything that sets colour or type on those elements is
 * therefore qualified with its section class and its tag, putting it at
 * (0,2,1) — measured, not guessed: `.nih-footer-legal p` at that weight was
 * already winning while the single-class rules beside it were not.
 *
 * Structural properties like padding and borders are left at one class; those
 * were never contested.
 */
.nih-hero p.nih-subhead,
.nih-home-intro p.nih-subhead {
	font-size: 1.25rem;
	font-weight: 600;
	color: var(--nih-accent);
	margin-top: 0;
}

/* Principles read as a list of claims, not prose — give each one room. */
.nih-principles li {
	margin-bottom: 0.75rem;
}

/* --- Team ---------------------------------------------------------------- */

.nih-team {
	margin-top: 2rem;
	gap: 2rem;
}

/*
 * Squares, filling the column, not circles floating in it.
 *
 * The client's report was that the padding "is sort of off, or maybe the
 * alignment". Both readings describe the same thing: a 220px circle centred in
 * a column whose caption text runs the full width, so the image's visual left
 * edge sits inboard of the name beneath it and the two never line up. Filling
 * the column squares that off — the image's left edge and the text's left edge
 * become the same line.
 *
 * A small radius rather than none: the client asked for "squares or
 * rectangles", and 4px reads as square while matching the rounding used
 * elsewhere on the site.
 */
.nih-headshot {
	/* The figure, not just the image. Left rather than centred: the caption
	   text below is left-aligned, and the mismatch between a centred portrait
	   and left-aligned text under it is what the client was seeing as "the
	   padding is off". */
	margin-inline: 0;
	max-width: 260px;
}

.nih-headshot img {
	width: 100%;
	height: auto;
	/* Capped, because the columns these sit in are not all the same width.
	   Abby's row holds one person and is therefore full width, while the board
	   row holds three; without a cap the same rule produces a 700px portrait in
	   one and a 220px one in the other. */
	max-width: 260px;
	aspect-ratio: 4 / 5;
	object-fit: cover;
	border-radius: 4px;
	display: block;
}

.nih-team h3,
.nih-team h4 {
	margin-bottom: 0.15rem;
}

.nih-team p.nih-role {
	margin-top: 0;
	font-weight: 600;
	/* Muted grey is safe here: this sits on white or on the near-white
	   surface, never on the cream. See the contrast table above. */
	color: var(--nih-text-muted);
}

/* --- Disclosure panels --------------------------------------------------- */

.nih-details {
	border: 1px solid var(--nih-bone);
	border-radius: 4px;
	padding: 1rem 1.25rem;
	margin-bottom: 1rem;
	background: var(--nih-white);
}

.nih-details > summary {
	font-weight: 700;
	cursor: pointer;
	color: var(--nih-accent);
}

/* --- Placeholder and empty states ---------------------------------------- */

/* Deliberately conspicuous. These mark work that is blocked on someone else
   and should be impossible to mistake for finished design. */
.nih-placeholder,
.nih-doclist-empty {
	border: 2px dashed var(--nih-orange);
	background: var(--nih-cream);
	padding: 1.25rem 1.5rem;
	border-radius: 4px;
}

/* Ink, not the muted grey — grey on cream measures 4.16 and fails AA. */
.nih-section .nih-placeholder p,
.nih-section p.nih-doclist-empty {
	color: var(--nih-ink);
}

/* --- Meeting summaries --------------------------------------------------- */

/*
 * The filter bar.
 *
 * Rendered by [nihub_body_filter]; the note there says why the chips are
 * generated from the taxonomy rather than typed into the page.
 *
 * It was a bold paragraph above three full-size buttons, which read as three
 * calls to action rather than as a control: same size and weight as the
 * Donate button, and nothing tying them to the list underneath. What makes it
 * a bar instead is the label demoted to a small uppercase field label, the
 * buttons shrunk to chips, and a hairline under the row so the filters sit
 * visibly above the results they filter.
 *
 * The label stays on its own line. It could sit inline now that the shortcode
 * emits one wrapper around both — that was impossible when they were two
 * sibling blocks — but a label above its control is the more ordinary shape
 * and moving it would be a change nobody asked for.
 */
.nih-filterbar {
	display: block;
	margin-bottom: 2rem;
	padding-bottom: 1.1rem;
	border-bottom: 1px solid var(--nih-bone);
}

.nih-filterbar__label {
	display: block;
	font-size: 0.8rem;
	letter-spacing: 0.04em;
	text-transform: uppercase;
	font-weight: 700;
	color: var(--nih-text-muted);
	margin-bottom: 0.6rem;
}

.nih-filterbar__list {
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem;
	margin: 0;
	padding-left: 0;
	list-style: none;
}

.nih-filterbar__item {
	margin: 0;
}

/*
 * Chips.
 *
 * The border is on every chip and transparent on the selected one, so picking
 * a filter does not change its width by two pixels and shuffle the row.
 *
 * Selector weight: Kubio colours links with
 * `[data-kubio] a:not([class*="wp-block-button"]):not([class*="wp-element-button"])`,
 * which counts as (0,3,1) once both :not() arguments are included. This is
 * (0,3,1) too and would only tie — so the list element is in there as well,
 * putting it at (0,4,1) and settling it on weight rather than on load order.
 * The same bet on order is what lost on the Donate button.
 */
.nih-section .nih-filterbar ul.nih-filterbar__list a.nih-filterbar__chip {
	display: inline-flex;
	align-items: center;
	padding: 0.35rem 0.95rem;
	font-size: 0.85rem;
	font-weight: 600;
	line-height: 1.5;
	border: 1px solid var(--nih-bone);
	border-radius: 999px;
	text-decoration: none;
	color: var(--nih-accent);
}

.nih-section .nih-filterbar ul.nih-filterbar__list a.nih-filterbar__chip:hover {
	background: var(--nih-surface-alt);
}

/*
 * The list you are looking at.
 *
 * Hung off aria-current rather than a class of its own, so the thing that
 * makes it look selected and the thing that says it is selected cannot come
 * apart — there is only one of them.
 */
.nih-section .nih-filterbar ul.nih-filterbar__list a.nih-filterbar__chip[aria-current] {
	background: var(--nih-accent);
	border-color: transparent;
	color: var(--nih-white);
}

.nih-section .nih-filterbar ul.nih-filterbar__list a.nih-filterbar__chip:focus-visible {
	outline: 3px solid var(--nih-accent);
	outline-offset: 2px;
}

/*
 * Pagination.
 *
 * Core renders a <nav> holding a numbers group and, either side of it,
 * previous/next links — all of them plain text, which at ten summaries a page
 * meant the list ended in "1 2 Next Page" run together in link blue.
 *
 * The numbers are chips, deliberately the same chips as the filter bar at the
 * top of this page: both are "pick one of these", and a reader who has used
 * one recognises the other. The rule above them closes the list the way the
 * rule under the filters opens it.
 *
 * Left-aligned rather than centred, which is the more usual choice for
 * pagination, because everything else on this page is ranged left and a
 * centred row under a left-aligned list reads as a stray element.
 */
.nih-summary-list .wp-block-query-pagination {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 0.75rem;
	margin-top: 0.5rem;
	padding-top: 1.5rem;
	border-top: 1px solid var(--nih-bone);
}

.wp-block-query-pagination-numbers {
	display: flex;
	flex-wrap: wrap;
	gap: 0.35rem;
}

/*
 * The tag is in the selector because Mistify and Kubio both colour links at
 * two-class specificity, the same as everywhere else on this page. `.current`
 * is a span rather than a link, so it is matched separately.
 */
.nih-summary-list .wp-block-query-pagination a.page-numbers,
.nih-summary-list .wp-block-query-pagination span.page-numbers {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-width: 2.25rem;
	height: 2.25rem;
	padding: 0 0.5rem;
	border: 1px solid var(--nih-bone);
	border-radius: 999px;
	font-size: 0.85rem;
	font-weight: 600;
	text-decoration: none;
	color: var(--nih-accent);
}

.nih-summary-list .wp-block-query-pagination a.page-numbers:hover {
	background: var(--nih-surface-alt);
}

/*
 * The page you are on. Filled, like the selected filter chip, and not a link —
 * core renders it as a span, so there is nothing here to make unclickable.
 */
.nih-summary-list .wp-block-query-pagination span.page-numbers.current {
	background: var(--nih-accent);
	border-color: transparent;
	color: var(--nih-white);
}

/*
 * Previous and next are text, not chips: they are a different kind of control
 * from "go to page 2", and making all five look identical would flatten that.
 */
.nih-summary-list a.wp-block-query-pagination-previous,
.nih-summary-list a.wp-block-query-pagination-next {
	font-size: 0.85rem;
	font-weight: 700;
	color: var(--nih-accent);
	text-decoration: none;
}

.nih-summary-list a.wp-block-query-pagination-previous:hover,
.nih-summary-list a.wp-block-query-pagination-next:hover {
	text-decoration: underline;
}

/* Next sits at the far end of the row, so the numbers are not squeezed
   between two labels. Previous keeps its place at the start. */
.nih-summary-list a.wp-block-query-pagination-next {
	margin-left: auto;
}

/* --- Summary thumbnails --------------------------------------------------- */

/*
 * Secondary to the summary, as the client asked — a still that distinguishes
 * one meeting from another at a glance, not an embedded player. Capped rather
 * than full-width for the same reason.
 *
 * aria-hidden with tabindex="-1" on the link (see nihub_video_thumb): the
 * title immediately below is the same link to the same place, so exposing this
 * one would make every summary announce itself twice to a screen reader and
 * add a second tab stop that goes nowhere new.
 */
.nihub-summary-thumb {
	/* inline-block for the same reason as .nih-readmore above: core's
	   constrained layout centres block-level children with auto margins and
	   !important, and auto resolves to zero on an inline-level box. The
	   listing overrides this — see the grid below, where the picture is a
	   grid item and the question does not arise. */
	display: inline-block;
	max-width: 220px;
	margin-bottom: 0.75rem;
}

.nihub-summary-thumb img {
	display: block;
	width: 100%;
	height: auto;
	aspect-ratio: 16 / 9;
	/* YouTube's hqdefault is 4:3 with the frame letterboxed inside it; cropping
	   to 16:9 trims the bars rather than showing them. */
	object-fit: cover;
	border-radius: 4px;
}

/*
 * The stand-in, for a summary with neither a recording nor a featured image.
 * Rendered by nihub_meeting_glyph(); the note there says why it is drawn
 * rather than uploaded.
 *
 * Same 16:9 box as a real still, so a row with no picture is the same height
 * as a row with one and the list does not step in and out.
 *
 * Muted on a light surface rather than in the accent colour: it is a stand-in
 * for a missing picture, and at full strength it pulls harder than the
 * photographs it sits between.
 */
.nihub-summary-thumb--glyph {
	display: flex;
	align-items: center;
	justify-content: center;
	aspect-ratio: 16 / 9;
	background: var(--nih-surface-alt);
	border-radius: 4px;
}

/*
 * The colour goes on the svg, not on the link around it.
 *
 * The obvious place is the anchor, and it does not work: Kubio colours links
 * with `[data-kubio] a:not([class*="wp-block-button"]):not([class*="wp-element-button"])`,
 * which is (0,3,1) once both :not() arguments are counted, so the figures
 * came out in full-strength indigo however the anchor rule was written. The
 * svg is not a link and nothing is competing for it, and the shapes are
 * `fill="currentColor"`, so setting colour one level down settles it without
 * an escalation.
 *
 * Muted rather than the accent: it stands in for a missing picture and should
 * not pull harder than the photographs it sits between.
 */
.nihub-meeting-glyph {
	width: 42%;
	height: auto;
	color: var(--nih-text-muted);
	opacity: 0.85;
}

/*
 * The same stand-in on the /meeting-body/ archive cards, where it fills
 * Kubio's image slot instead of the flat grey panel. Absolute against the
 * <figure> for the same reason as the video still above it.
 */
.nihub-card-glyph {
	position: absolute;
	inset: 0;
	display: flex;
	align-items: center;
	justify-content: center;
	border-radius: inherit;
}

.nihub-card-glyph .nihub-meeting-glyph {
	width: 34%;
}

.nih-summary-item {
	border-bottom: 1px solid var(--nih-bone);
	padding-bottom: 1.75rem;
	margin-bottom: 1.75rem;
}

/*
 * The rules go between summaries, not after the last one.
 *
 * Without this the list ends in two hairlines a few pixels apart: the last
 * item's own, and the one over the pagination. On a single page of results,
 * where there is no pagination, it instead left the list closed by a rule
 * with nothing under it.
 */
.nih-summary-list li:last-child .nih-summary-item {
	border-bottom: 0;
	padding-bottom: 0;
}

/*
 * Picture left, summary right.
 *
 * A grid rather than a flex row because of the markup this has to work with.
 * The picture, title, body tag, excerpt and read-more link are five siblings
 * in one container — the picture is prepended to the title block's output by
 * nihub_prepend_summary_thumb() — and there is no wrapper around the four
 * text blocks to float against the picture. Grid can place the picture in a
 * column of its own and push everything else into the second column without
 * any of that structure existing.
 *
 * `span 20` is "as many rows as there are": the picture has to span whatever
 * the text column happens to produce, and CSS has no way to say that. `1 /
 * -1` is the obvious spelling and does not work — with no explicit rows
 * declared, -1 resolves to the first line and the picture spans nothing. Any
 * number comfortably above the four blocks a summary has does the job; rows
 * that never get content are zero-height and cost nothing.
 */
.nih-summary-list .nih-summary-item > .wp-block-group__inner-container {
	display: grid;
	grid-template-columns: 220px minmax(0, 1fr);
	column-gap: 1.5rem;
	align-items: start;
}

/*
 * The `width: 100%` on both columns is load-bearing, and not obviously so.
 *
 * Core's constrained layout sets `margin-left: auto` and `margin-right: auto`
 * on every child of this container, with !important. In normal flow that does
 * nothing to a full-width block and the rules have sat here harmlessly all
 * along. In a grid it is different: a grid item with both margins auto is
 * sized to its content and centred in its area, so every title, body tag and
 * read-more link came out shrink-wrapped and centred in the text column, and
 * the stand-in came out as a 48px box in a 220px one.
 *
 * !important cannot be out-specified, so it is not fought. Giving the item a
 * width leaves no free space for the auto margins to distribute, and they
 * resolve to zero on their own — the same move the read-more link makes with
 * display below, and for the same reason.
 */
.nih-summary-item .nihub-summary-thumb {
	grid-column: 1;
	grid-row: 1 / span 20;
	display: block;
	width: 100%;
	max-width: none;
	margin-bottom: 0;
}

.nih-summary-item .nihub-summary-thumb--glyph {
	display: flex;
}

.nih-summary-list .nih-summary-item > .wp-block-group__inner-container > :not(.nihub-summary-thumb) {
	grid-column: 2;
	width: 100%;
}

/*
 * One column once there is no room for two. 220px of picture plus the gap
 * leaves under 150px of measure on a phone, which is three or four words a
 * line.
 */
@media (max-width: 600px) {
	.nih-summary-list .nih-summary-item > .wp-block-group__inner-container {
		grid-template-columns: minmax(0, 1fr);
	}

	/*
	 * Full width, not capped back to 220px. The cap would leave free space in
	 * the row, which is exactly what the auto margins described above need in
	 * order to centre it — and a picture centred over left-aligned text is
	 * the thing this layout was changed to stop doing.
	 */
	.nih-summary-item .nihub-summary-thumb {
		grid-row: auto;
		margin-bottom: 0.9rem;
	}

	.nih-summary-list .nih-summary-item > .wp-block-group__inner-container > :not(.nihub-summary-thumb) {
		grid-column: 1;
	}
}

.nih-summary-item h2,
.nih-summary-item h3 {
	font-size: 1.5rem;
	/* Flush with the top of the picture beside it. Headings carry a generous
	   top margin from the editor's defaults, which in normal flow collapsed
	   into the gap above the card and in the grid does not — it just pushed
	   the title 24px below the picture it is supposed to line up with. */
	margin-top: 0;
	margin-bottom: 0.35rem;
}

/* Same specificity problem as the footer links — see the note there. */
.nih-summary-list .nih-summary-item :is(h2, h3) a:not([class*="wp-element-button"]) {
	text-decoration: none;
	color: var(--nih-ink);
}

.nih-summary-list .nih-summary-item :is(h2, h3) a:not([class*="wp-element-button"]):hover,
.nih-summary-list .nih-summary-item :is(h2, h3) a:not([class*="wp-element-button"]):focus {
	color: var(--nih-accent);
	text-decoration: underline;
}

/* The body tag is a label, so it gets label treatment rather than link
   treatment even though it is a link. */
.nih-summary-body {
	display: inline-block;
	font-size: 0.8rem;
	letter-spacing: 0.04em;
	text-transform: uppercase;
	font-weight: 700;
}

/*
 * No margin either side of it.
 *
 * The tag belongs to the title above it, and it was sitting 29px below the
 * title and 37px above the excerpt — further from the thing it labels than
 * from the thing it does not. Two separate sources, which is why it looked
 * so loose: 24px of `margin-block-start` from core's constrained-layout rule,
 * and 12px of our own underneath.
 *
 * Nothing here collapses, which is what makes this worth stating. These are
 * grid items now, and grid does not collapse adjacent margins the way normal
 * flow does — every margin is added to its neighbour's rather than merged
 * with it. The gaps that remain are the title's 5.6px above and the
 * excerpt's 24px below, both of which are their own.
 *
 * Two classes, at (0,2,0), because core's rule is `:root :where(...) > *` at
 * (0,1,0) — `:where()` contributes nothing but `:root` does. A lone class
 * only ties with it and wins on load order, which is the bet that lost on the
 * Donate button.
 */
.nih-summary-list .nih-summary-body {
	margin-top: 0;
	margin-block-start: 0;
	margin-bottom: 0;
	margin-block-end: 0;
}

.nih-summary-body a {
	color: var(--nih-accent);
	text-decoration: none;
}

/*
 * Left, with the rest of the card.
 *
 * The read-more is a block-level element narrower than its container, and
 * WordPress's constrained layout gives such children margin-inline: auto — so
 * it centres itself under left-aligned text without anything setting
 * text-align: center. That is the "align page text left rather than centered"
 * note: the page was already left-aligned apart from this.
 */
.nih-summary-item .nih-readmore {
	/*
	 * inline-block, not `margin-inline: 0`.
	 *
	 * The centring comes from core's constrained-layout rule, which sets
	 * margin-left/right to auto with !important — so setting the margins here
	 * loses no matter the specificity. But `auto` only centres a block-level
	 * box: on an inline-level one it computes to zero. Changing the display
	 * type makes core's own declaration resolve to what we want instead of
	 * fighting it, and needs no !important of our own.
	 */
	display: inline-block;
}

.nih-readmore a {
	font-weight: 700;
	color: var(--nih-accent);
}

/* --- Call to action ------------------------------------------------------ */

.nih-cta {
	text-align: center;
}

/*
 * White, explicitly. The band's background is indigo and the block's own text
 * colour class does not reach headings, so without this the heading inherits
 * ink and lands at 1.89 against indigo — unreadable, and the worst contrast
 * failure on the site if it shipped.
 */
.nih-section.nih-cta h2 {
	color: var(--nih-white);
	margin-bottom: 1.5rem;
}

/*
 * And the body copy in the band, for the same reason.
 *
 * The heading rule above was written when the CTA bands held nothing but a
 * heading and buttons. The Donate page puts a line of copy between them, which
 * inherits ink and lands at 2.09 on the indigo ground — the same failure the
 * heading rule exists to prevent, one element along. Covering paragraphs and
 * list items here means the next band that grows a line of text is right by
 * default rather than by someone remembering.
 */
.nih-section.nih-cta p,
.nih-section.nih-cta li {
	color: var(--nih-white);
}

.nih-cta .wp-block-buttons {
	justify-content: center;
}

/* --- Buttons ------------------------------------------------------------- */

/*
 * Contrast enforcement, not decoration.
 *
 * Sage measures 2.94 against white and yellow 1.41 — both fail AA for normal
 * text. Core's button default is white text, so a button using either as a
 * fill would ship a failing ratio unless the text colour is forced back to
 * ink here.
 */
.wp-block-button__link.has-kubio-color-3-background-color,
.wp-block-button__link.has-kubio-color-4-background-color {
	color: var(--nih-ink);
}

/*
 * The orange button keeps core's white label rather than being forced back
 * to ink, because slot 2 is now dark enough to carry it. The background needs
 * no rule here: it comes from the palette override above, through the preset
 * property.
 */
.wp-block-button__link.has-kubio-color-2-background-color {
	color: var(--nih-white);
}

.wp-block-button__link.has-kubio-color-1-background-color {
	color: var(--nih-white);
}

/* Outline buttons sitting on the indigo CTA band need light strokes. */
.nih-cta .is-style-outline .wp-block-button__link {
	color: var(--nih-white);
	border-color: var(--nih-white);
}

.nih-social-row {
	gap: 0.75rem;
}

/* --- Contact form -------------------------------------------------------- */

.nih-formwrap form.frm-fluent-form {
	max-width: 40rem;
}

/* --- Global footer ------------------------------------------------------- */

/*
 * Replaces Kubio's demo footer, which was a single copyright line carrying a
 * "Created with Kubio" credit. Built from core blocks for the same reason the
 * pages are: it is markup a person can read.
 *
 * Ink ground rather than indigo. The footer sits under every page including
 * the indigo call-to-action bands, and indigo-on-indigo loses the boundary.
 */
.nih-footer {
	background: var(--nih-ink);
	color: var(--nih-white);
	padding: 4rem 1.5rem 2rem;
}

.nih-footer > * {
	max-width: 68rem;
	margin-inline: auto;
}

.nih-footer h2.nih-footer-name {
	font-size: 1.35rem;
	margin: 0 0 0.5rem;
	color: var(--nih-white);
}

.nih-footer p.nih-footer-tagline {
	/* Bone rather than the muted grey: grey on ink measures 3.33 and fails
	   AA for body text, while bone clears it comfortably. */
	color: var(--nih-bone);
	margin-bottom: 1.5rem;
}

.nih-footer h3.nih-footer-head {
	font-size: 0.85rem;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: var(--nih-bone);
	margin-bottom: 0.75rem;
}

.nih-footer-links {
	list-style: none;
	padding-left: 0;
	margin: 0;
}

.nih-footer-links li {
	margin-bottom: 0.4rem;
}

/*
 * Link colour has to outrank Kubio's global rule, which is
 *
 *     [data-kubio] a:not([class*=wp-block-button]):not([class*=wp-element-button])
 *
 * at (0,3,1) — the two :not() clauses are where most of that weight comes
 * from. Left alone it paints these links indigo, which on the ink footer
 * measures 1.89 and is effectively invisible.
 *
 * Rather than reach for !important or borrow Kubio's [data-kubio] hook (which
 * sits on block wrappers, not the body, so it is not a stable ancestor), these
 * take the weight from their own classes plus one :not(). That exclusion is
 * doing real work as well as carrying specificity: button links inside the
 * footer keep their own colour instead of being repainted white.
 */
.nih-footer .nih-footer-links li a:not([class*="wp-element-button"]),
.nih-footer .nih-footer-legal p a:not([class*="wp-element-button"]) {
	color: var(--nih-white);
	text-decoration: none;
}

.nih-footer .nih-footer-links li a:not([class*="wp-element-button"]):hover,
.nih-footer .nih-footer-links li a:not([class*="wp-element-button"]):focus,
.nih-footer .nih-footer-legal p a:not([class*="wp-element-button"]):hover,
.nih-footer .nih-footer-legal p a:not([class*="wp-element-button"]):focus {
	color: var(--nih-yellow);
	text-decoration: underline;
}

.nih-footer-legal {
	border-top: 1px solid rgb(255 255 255 / 0.15);
	margin-top: 2.5rem;
	padding-top: 1.5rem;
	max-width: var(--wp--style--global--wide-size);
}

.nih-footer .nih-footer-legal p {
	color: var(--nih-bone);
	font-size: 0.85rem;
	margin-bottom: 0.4rem;
	max-width: var(--wp--style--global--wide-size);
}

/* Donate stays orange on the ink ground; the deepened value and its white
   label are inherited from the button rule above, so nothing is needed here
   beyond making sure the footer does not repaint the label along with the
   other footer links. */
.nih-footer .wp-block-button__link.has-kubio-color-2-background-color {
	color: var(--nih-white);
}

/* Home's intro block sits below the mural banner rather than over it, so it
   is a section rather than a hero, but it carries the same lead typography. */
.nih-home-intro {
	text-align: center;
	padding-bottom: 1rem;
}

.nih-home-intro .wp-block-buttons {
	justify-content: center;
}

/* --- Upcoming meetings (nih-meeting-summaries shortcode) ----------------- */

.nihub-upcoming {
	list-style: none;
	padding-left: 0;
	margin: 0 0 1.5rem;
}

.nihub-upcoming-item {
	display: flex;
	flex-wrap: wrap;
	gap: 0.25rem 1rem;
	justify-content: space-between;
	align-items: baseline;
	border-bottom: 1px solid var(--nih-bone);
	padding: 0.85rem 0;
}

.nih-section .nihub-upcoming-item a:not([class*="wp-element-button"]) {
	font-weight: 700;
	color: var(--nih-accent);
	text-decoration: none;
}

.nih-section .nihub-upcoming-item a:not([class*="wp-element-button"]):hover,
.nih-section .nihub-upcoming-item a:not([class*="wp-element-button"]):focus {
	text-decoration: underline;
}

.nihub-upcoming-when {
	color: var(--nih-text-muted);
	font-size: 0.9rem;
}

.nihub-upcoming-empty {
	color: var(--nih-text-muted);
}

/* --- Contact form -------------------------------------------------------- */

/*
 * Fluent Forms colours its submit button with
 *
 *     form.fluent_form_N .ff-btn-submit:not(.ff_btn_no_style)
 *
 * at (0,3,1), and hardcodes `color:#ffffff` rather than deriving it. Note the
 * form's class is `frm-fluent-form`, not `fluentform` — the latter matches
 * nothing and is an easy wrong guess. Setting
 * --fluentform-primary alone is therefore not enough: the white would stay,
 * and white on orange measures 3.00, below AA. This matches the plugin's own
 * selector shape and adds one class to clear it, setting both properties.
 *
 * Hover moves to red rather than a darker orange because red carries white
 * text at 4.79, so the state change does not have to flip the text colour.
 */
.nih-formwrap form.frm-fluent-form .ff-btn-submit:not(.ff_btn_no_style) {
	background-color: var(--nih-orange);
	border-color: var(--nih-orange);
	color: var(--nih-white);
	font-weight: 700;
	padding: 0.7rem 1.75rem;
	border-radius: 999px;
}

.nih-formwrap form.frm-fluent-form .ff-btn-submit:not(.ff_btn_no_style):hover,
.nih-formwrap form.frm-fluent-form .ff-btn-submit:not(.ff_btn_no_style):focus {
	background-color: var(--nih-red);
	border-color: var(--nih-red);
	color: var(--nih-white);
}

/* Everything else the plugin derives from its primary — focus rings, active
   states — can follow the palette without a specificity fight. */
.nih-formwrap form.frm-fluent-form {
	--fluentform-primary: var(--nih-indigo);
}

.nih-formwrap form.frm-fluent-form .ff-el-input--label label {
	font-weight: 700;
}

/* --- Interior page header ------------------------------------------------ */

/*
 * The front page header sits over the crosswalk mural, so Kubio styles its
 * title, menu, and hamburger white. Interior pages use a second header
 * template part with no background image behind it, so that same white text
 * lands on white and the entire bar reads as empty on first load.
 *
 * Measured at the top of an interior page: title rgb(255,255,255), menu links
 * rgba(255,255,255,0.8), bar background transparent. Scroll down and Kubio's
 * sticky state gives the bar a white ground and switches the text to ink, so
 * the bar reappears — which is why this only looks broken before you scroll.
 *
 * Only the initial state needs correcting. These rules deliberately sit below
 * the sticky rules (which are (1,4,3) and already resolve to ink), so the
 * scrolled behaviour is left exactly as it is.
 *
 * Scoped with body:not(.home): WordPress adds `home` to the front page alone,
 * and the front page is precisely the one with the mural behind its header.
 *
 * The #kubio id is here to clear Kubio's own (1,2,3) rule. Note that #kubio
 * is the <html> element, not a wrapper inside the document — so it has to lead
 * the selector. Written the natural way round, `body:not(.home) #kubio ...`
 * asks for an element that is an ancestor of body to also be its descendant,
 * matches nothing, and fails silently.
 *
 * Kubio's per-block styleRef classes — .style--e3LlvGfB2r-outer and friends —
 * are deliberately avoided: those are regenerated whenever the header is
 * touched in the builder, so a rule depending on one stops applying without
 * warning.
 */
#kubio body:not(.home) .kubio-menu > ul > li:not(.nih-nav-donate) > a {
	color: var(--nih-ink);
}

/*
 * ...but not the ones inside the offscreen panel.
 *
 * There are two .kubio-menu elements in the document, not one: the header bar
 * and the slide-out mobile panel. The rule above was written for the bar and
 * matches both, which is what made the mobile menu unusable on interior pages.
 *
 * The panel's ground is Kubio color-6, and Kubio emits that as rgb(30,30,32).
 * --nih-ink is #1E1E20. They are the same colour, so every item was painted
 * exactly its own background: measured contrast 1.00, which is invisible
 * rather than merely poor. It looked correct on the front page only because
 * body.home excludes it there and the items keep their inherited white.
 *
 * Three symptoms, one cause: the plain items vanished at 1.00, the current
 * item sat at 1.89 on its indigo highlight, and the search glyph went with
 * them because that item paints itself with background-color:currentColor
 * (see the Search section below) — so ink text meant an ink-coloured icon.
 *
 * SCOPE THIS WITH .kubio-offscreen, NOT THE BLOCK WRAPPER
 * ------------------------------------------------------
 * The obvious hook is .wp-block-kubio-menu-offscreen, the block's own
 * container. It does not work. Kubio's script *moves* the panel out of that
 * container and reparents it to <body> when the menu opens, so at the moment
 * the rule is needed the wrapper is no longer an ancestor —
 * a.closest('.wp-block-kubio-menu-offscreen') is null on an open menu. A rule
 * written that way matches nothing and fails silently in exactly the state it
 * was meant to cover.
 *
 * .kubio-offscreen is on the panel element itself rather than an ancestor, so
 * it survives the move and holds in both the closed and open states.
 *
 * CSS cannot say "not a descendant of", so rather than rewrite the rule above
 * to name the bar, this restores the panel's own colour at a higher weight:
 * (1,4,4) against its (1,3,4). White measures 16.64 on the panel and 8.82 on
 * the indigo current-item highlight, so both states clear AA comfortably.
 *
 * Donate is excluded for the same reason it is excluded above — it carries its
 * own orange fill and ink label in both menus, and measures 5.55.
 */
#kubio body:not(.home) .kubio-offscreen .kubio-menu > ul > li:not(.nih-nav-donate) > a {
	color: var(--nih-white);
}

#kubio body:not(.home) .wp-block-kubio-logo__text {
	color: var(--nih-ink);
}

/* The offscreen menu trigger is white for the same reason, and goes invisible
   on interior pages below the menu breakpoint. */
#kubio body:not(.home) .wp-block-kubio-menu-offscreen__icon,
#kubio body:not(.home) .wp-block-kubio-menu-offscreen__icon svg {
	color: var(--nih-ink);
	fill: currentColor;
}

#kubio .h-navigation_sticky:not(.extra-1) .style-c6BbujDIAOY-outer > .kubio-menu > ul > li.nih-nav-donate > a {
	color: var(--nih-white) !important;
}
#kubio .h-navigation_sticky:not(.extra-1) .style--e3LlvGfB2r-outer > .kubio-menu > ul > li.nih-nav-donate > a[href="/donate/"] {
	color: var(--nih-white) !important;
}

/*
 * Donate as a solid pill, on every page.
 *
 * The content outline asks for it to stay visually distinct from the nav
 * links so it reads as an action rather than a page. Filling it also sidesteps
 * the problem above entirely — one treatment works over the mural and over
 * white, so this needs no per-page variant.
 *
 * Orange takes ink text, never white; see the contrast table at the top. Kubio
 * sets colour but never background on menu links, so the fill survives the
 * sticky state, where Kubio switches the label to ink on its own.
 */
/*
 * Note the [href], which is load-bearing rather than decorative.
 *
 * Kubio emits a per-block rule for the header at
 *
 *     #kubio .style--e3LlvGfB2r-outer > .kubio-menu > ul > li > a
 *
 * which zeroes the inline padding and sets the label to 80% white. That is
 * (1,2,3) — exactly the weight this rule had without the attribute selector.
 * On most pages the child stylesheet is emitted after it and wins on order,
 * but The Events Calendar reorders the head and puts Kubio's inline block
 * after it, so on /events/ the same rule lost: the pill kept its fill and its
 * radius while the padding collapsed and the label went translucent, which is
 * exactly the "Donate button doesn't look the same" report.
 *
 * [href] adds a class-level unit for a condition every menu link already
 * satisfies, taking this to (1,3,3) so it no longer depends on source order.
 * The styleRef class in Kubio's selector is regenerated whenever the header is
 * edited in the builder, so matching its shape is not an option — the rule
 * would silently stop applying.
 *
 * `#kubio body ...` would also have worked on most of the site and would have
 * been wrong here: on Events pages the id is duplicated onto <body> as well as
 * <html>, so that selector asks for a body inside a body and matches nothing.
 */
#kubio .kubio-menu > ul > li.nih-nav-donate > a[href] {
	background-color: var(--nih-orange);
	color: var(--nih-white);
	border-radius: 999px;
	padding-inline: 1.15rem;
}

#kubio .kubio-menu > ul > li.nih-nav-donate > a:hover,
#kubio .kubio-menu > ul > li.nih-nav-donate > a:focus {
	background-color: var(--nih-red);
	color: var(--nih-white);
}

/*
 * In the offscreen panel the same pill needs different geometry.
 *
 * The header bar lays its items out in a row, so the fill wraps the label. The
 * panel stacks them, where an anchor is full-width by default and the pill
 * stretches the width of the panel and past its padding — it reads as a bar
 * rather than a button and clips at the right edge.
 *
 * This was invisible until the items above became legible, so it is not a
 * regression: it is the rest of the bug, only visible now there is something
 * to see.
 */
#kubio .kubio-offscreen .kubio-menu > ul > li.nih-nav-donate {
	padding: 0.5rem 1rem;
}

#kubio .kubio-offscreen .kubio-menu > ul > li.nih-nav-donate > a {
	padding-block: 0.5rem;
	text-align: center;
}

/* --- Front page header scrim --------------------------------------------- */

/*
 * The mural sits behind the header on the front page, and the header's title
 * and menu are white so they read against it. Kubio was making that work with
 * a 60% dark overlay across the whole image, which the client found too heavy
 * — it flattened the mural into a grey wash.
 *
 * Their first preference was to drop that overlay and put a gradient behind
 * the navigation instead, which is what this is. The overlay is now at zero
 * opacity, so the photograph shows at full strength everywhere except the top
 * strip, where a short gradient keeps enough density under the white text.
 *
 * The gradient is on ::before rather than on the element's own background,
 * because the element's background is the mural — setting a gradient there
 * would replace the image rather than sit over it.
 *
 * Front page only. Interior headers have no image behind them and their text
 * is already ink on white; a scrim there would be a dark band over nothing.
 *
 * Kubio's sticky state gives the bar its own solid background as you scroll
 * and switches the text to ink. The scrim is pinned to the top of the hero
 * rather than to the bar, so it stays with the image and does not follow the
 * bar down the page.
 */
#kubio body.home .wp-block-kubio-hero__outer {
	position: relative;
}

#kubio body.home .wp-block-kubio-hero__outer::before {
	content: "";
	position: absolute;
	inset: 0 0 auto 0;
	height: 190px;
	background: linear-gradient(
		to bottom,
		rgb(0 0 0 / 0.64) 0%,
		rgb(0 0 0 / 0.54) 42%,
		rgb(0 0 0 / 0.24) 74%,
		rgb(0 0 0 / 0) 100%
	);
	pointer-events: none;
	z-index: 1;
}

/* The header itself has to sit above the scrim, or the gradient paints over
   the very text it exists to support. */
#kubio body.home .wp-block-kubio-navigation__outer {
	position: relative;
	z-index: 2;
}

/*
 * Full-strength white for the front-page menu, which Kubio sets to 80%.
 *
 * Against a flat colour that softening is a stylistic choice; against a
 * photograph it is a contrast cost — the 20% of the mural showing through
 * lands in the text itself. Measured, it is worth about a full step: the
 * brightest point behind the menu gives 7.0 with pure white and 5.2 with 80%.
 * Taking the text to full white buys that back and lets the scrim above stay
 * lighter than it would otherwise need to be, which is what the client asked
 * for.
 */
#kubio body.home .kubio-menu > ul > li:not(.nih-nav-donate) > a {
	color: var(--nih-white);
}

/* ==========================================================================
   Single post — the meeting summary detail page
   ==========================================================================

   Kubio's "Single Post" template renders /meeting-summaries/<slug>/. It is
   database state and is stock apart from the palette, which means it arrived
   with a set of problems that only show once real content is in it: no title
   block at all, and a first element that began 55px from the top of the page
   underneath a 90px overlap header. The reasoning behind the markup half of
   the fix is beside nihub_single_title() in functions.php.

   This section is the layout half: the clearance, the h1's spacing and
   alignment, and the measure of the article beneath it.
   ========================================================================== */

/*
 * Clear the overlap header.
 *
 * The section is the right place for this rather than the title, because the
 * sidebar column beside it — the search box — starts at the same y and was
 * sitting behind the bar too.
 *
 * The 40px it already carries comes from `div.h-section-global-spacing`, at
 * (0,1,1). Two classes and the element puts this at (0,2,1) so it wins on
 * weight rather than on load order; #blog-layout would also do it, but that
 * anchor is written by the builder and does not survive the block being
 * rebuilt, while the block's own class does.
 *
 * Kubio's row gutter adds a further 15px inside the column, so the title
 * lands at 135px rather than the 118px an interior page puts its h1 at. That
 * 15px is a builder setting on the row and is deliberately not subtracted
 * back out here: pinning a rule to it would break silently the first time
 * someone changes the row's spacing.
 *
 * The same block, with the same 40px, opens the `index` and `search`
 * templates — which is what /meeting-body/<body>/ and the search results
 * render through — so they are listed here too. Measured, all three put
 * their first card at y=55 under a 90px bar. The 404 template is not
 * included: it sets 120px of its own already.
 */
body.single .wp-block-kubio-query-layout__outer,
body.archive .wp-block-kubio-query-layout__outer,
body.search .wp-block-kubio-query-layout__outer {
	padding-top: var(--nih-header-clearance);
}

/*
 * The title.
 *
 * Kubio styles headings from its global typography, which reaches any h1
 * inside its wrapper, so the family, size and weight arrive on their own and
 * match the h1 on every interior page. Only the spacing and the alignment are
 * set here.
 *
 * The alignment has to be stated. The column this sits in was centred for the
 * featured image it used to open with, and text-align inherits — so the title
 * arrived centred above a left-aligned date and a left-aligned article. The
 * rule is on the title rather than on the column so that anything else the
 * template puts in there keeps the alignment the builder gave it.
 */
.nih-single-title {
	margin-top: 0;
	margin-bottom: var(--nih-space-stack);
	text-align: left;
}

/*
 * The body measure.
 *
 * Two problems, one cause. The post-content block is `is-layout-flow`, so its
 * children are not constrained and run the full 894px of the column — about
 * 125 characters a line, against the 46rem every other article on the site
 * uses (see the note on the calendar's widths below, which cites the same
 * measure). Meanwhile any block that *is* constrained — a group, a columns
 * block — falls back to core's 620px default, because Mistify ships no
 * theme.json, and lands inset 137px from the paragraphs above and below it.
 * That is the indented panel at the top of every seeded summary.
 *
 * Setting both to the same value fixes the line length and the alignment
 * together: the column caps at the site's prose measure, and a nested
 * container measures itself against that rather than against 620px, so its
 * left edge is the same left edge.
 *
 * margin-inline:0 because a max-width alone would centre the text in the
 * column and leave it starting 79px inboard of the title above it.
 */
body.single .entry-content {
	max-width: 46rem;
	margin-inline: 0;
	--wp--style--global--content-size: 46rem;
}


/* --- The recording ------------------------------------------------------- */

/*
 * Rendered by nihub_video_markup() in the meeting-summaries plugin, at the
 * end of the write-up. It is a poster and a link until someone clicks it, at
 * which point assets/video.js replaces the contents with the iframe — see the
 * note there for why the embed is not shipped up front.
 *
 * The container owns the 16:9 box so that both states are the same size and
 * the page does not jump when the player arrives. 8px radius to match the
 * rounding the rest of the page uses.
 *
 * It sits inside .entry-content, so it takes the article's measure rather
 * than the full column — the recording lines up with the text it belongs to.
 * The top margin is the section gap rather than the stack gap: this is the
 * end of the summary and the start of something else, not another paragraph.
 */
.nihub-video {
	position: relative;
	aspect-ratio: 16 / 9;
	overflow: hidden;
	border-radius: 8px;
	background: var(--nih-ink);
}

/*
 * The link-only form, for a summary the client chose not to embed.
 *
 * Sized and spaced like the player it replaces so that switching between the
 * two does not move everything below it, and given the same top gap for the
 * same reason: it is the end of the summary.
 *
 * Qualified with the tag because Mistify and Kubio set link colour at
 * two-class specificity — the same reason the section rules further up are
 * written this way. Measured, not guessed.
 */
.entry-content p.nihub-video-link a {
	display: inline-flex;
	align-items: center;
	gap: 0.6rem;
	font-weight: 600;
	color: var(--nih-accent);
}

/*
 * YouTube red on the glyph only, the same exception the play badge makes: it
 * is a mark of where the link goes, not a brand colour choice. The label
 * stays the site's link colour so it reads as a link first.
 */
.nihub-video-link__glyph {
	color: #f00;
	flex: none;
}

/*
 * The gap above the recording, in both of its forms.
 *
 * The section gap rather than the paragraph gap: this is the end of the
 * summary and the start of the thing it was written from, not another
 * paragraph of it.
 *
 * The tag is in the selector because Mistify spaces every child of the
 * article with `.entry-content:not(.wc-tab) > *` — (0,2,0), since :not()
 * carries the specificity of what is inside it — which a lone class ties with
 * and loses to on order. This is (0,2,1). Both forms are listed together so
 * switching one summary from embedded to linked does not move anything else
 * on the page.
 */
.entry-content > div.nihub-video,
.entry-content > p.nihub-video-link {
	margin-top: var(--nih-space-section);
	margin-bottom: var(--nih-space-stack);
}

.nihub-video__link {
	display: block;
	width: 100%;
	height: 100%;
}

/*
 * object-fit because the two poster sources are different shapes: a featured
 * image is whatever was uploaded, and YouTube's hqdefault is a 4:3 frame with
 * the 16:9 picture letterboxed inside it. Cropping to the box gives the same
 * result from either, and drops hqdefault's black bars.
 *
 * The tag is in the selector because Kubio sets `[data-kubio] img { height:
 * auto }` at (0,1,1), which a lone class loses to — the poster rendered at
 * its natural 671px inside a 503px box and was clipped to the top of the
 * frame, black bars and all. This is (0,2,1). Same for the iframe, which is
 * not covered by that rule today but is one Kubio release away from being.
 */
.nihub-video img.nihub-video__poster {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

.nihub-video iframe.nihub-video__frame {
	display: block;
	width: 100%;
	height: 100%;
	border: 0;
}

/*
 * The still that fills a listing card's image slot on the /meeting-body/
 * archives — where the "City Council" and "School Committee" filter buttons
 * lead — rendered by nihub_listing_video_still().
 *
 * Absolute against the <figure>, which is the element Kubio gives the aspect
 * ratio and `position-relative` to, so this covers the slot whatever shape
 * the builder gives it.
 *
 * The 133.334% is hqdefault's letterbox, cropped: the file is a 4:3 canvas
 * with a 16:9 frame inside it, 360 units tall carrying 270 of picture, and
 * 360/270 is what makes the picture fill the height with the bars pushed past
 * the top and bottom edges. A background clips to its own box, so nothing
 * overflows and no rule is needed on the figure.
 *
 * Deliberately expressed against the file's proportions rather than the
 * slot's. It is correct in a 4:3 card, in the 16:9 the Meeting Summaries page
 * uses, and in whatever someone sets next.
 */
.nihub-card-still {
	position: absolute;
	inset: 0;
	background-size: auto 133.334%;
	background-position: center;
	background-repeat: no-repeat;
	border-radius: inherit;
}

.nihub-video__play {
	position: absolute;
	top: 50%;
	left: 50%;
	transform: translate(-50%, -50%);
	/* The click target is the whole poster; this is the picture of one. */
	pointer-events: none;
}

/*
 * YouTube's own chrome red, not the site's orange.
 *
 * This is the one place the brand palette is deliberately not used: a play
 * badge is a convention people recognise before they read anything, and an
 * orange one on a page whose buttons are already orange reads as another
 * button. It is also honest about where the video is about to come from.
 *
 * 80% until hover for the same reason a poster is dimmer than a photograph —
 * the badge should not compete with the frame behind it.
 */
.nihub-video__play-bg {
	fill: #212121;
	fill-opacity: 0.8;
	transition: fill 0.15s ease, fill-opacity 0.15s ease;
}

.nihub-video__link:hover .nihub-video__play-bg,
.nihub-video__link:focus-visible .nihub-video__play-bg {
	fill: #f00;
	fill-opacity: 1;
}

/*
 * Inset rather than outset: the link fills a container with overflow:hidden,
 * so an outline drawn outside its edge is clipped away and the control has no
 * visible focus state at all.
 */
.nihub-video__link:focus-visible {
	outline: 3px solid var(--nih-accent);
	outline-offset: -3px;
}

/* ==========================================================================
   The Events Calendar
   ==========================================================================

   TEC does not render through the theme's page template. It brings its own
   wrapper, its own reset, and its own colour tokens, so its pages arrive
   full-bleed, in TEC blue, and tucked underneath the header. Everything here
   is about making /events/ and a single event look like the rest of the site.
   ========================================================================== */

/*
 * Brand colours for the calendar.
 *
 * TEC derives almost everything from --tec-color-accent-primary: the Find
 * Events button, links, the datepicker, the week-view event tints. Redefining
 * the token recolours all of it, the same trick the Kubio palette above uses,
 * rather than chasing individual components.
 *
 * Indigo rather than orange because these are text-bearing surfaces — indigo
 * carries white at 8.82 — and because indigo is the site's primary accent.
 * TEC composes its own translucent variants by appending an alpha channel to
 * the hex, so these have to stay 6-digit hex values; a var() or an rgb() here
 * breaks the concatenation and the tints come out transparent.
 */
:root {
	--tec-color-accent-primary: #3d3da1;
	--tec-color-accent-primary-hover: #3d3da1cc;
	--tec-color-accent-primary-active: #3d3da1e6;
	--tec-color-accent-primary-background: #3d3da112;
	--tec-color-link-accent-hover: #3d3da1cc;
	--tec-color-accent-primary-week-event: #3d3da11a;
	--tec-color-accent-primary-week-event-hover: #3d3da133;
	--tec-color-accent-primary-week-event-featured: #3d3da10a;
	--tec-color-accent-primary-week-event-featured-hover: #3d3da124;
}

/*
 * Width, to the site's own scale rather than TEC's.
 *
 * Two different constraints because the pages are two different things, and
 * both values are the site's: a single event is prose and takes the text
 * column every other article uses, while the calendar views are grids — a
 * month view is seven columns — and take the wide column the team row and the
 * summaries listing already use.
 *
 * The max-width adds the inline padding back on so the *content* lands on
 * 46rem and 64rem exactly, matching the rest of the site rather than
 * approximately.
 *
 * The top padding is the shared header clearance — TEC's wrapper starts at
 * y=0 and the navigation is an overlap header, so without it "« All Events"
 * sits inside the header's band. See the token's note in the palette section.
 */
.tribe-events-view,
#tribe-events-pg-template {
	box-sizing: border-box;
	margin-inline: auto;
	padding-inline: var(--nih-space-section-inline);
	padding-top: var(--nih-header-clearance);
}

.tribe-events-view {
	max-width: calc(64rem + 2 * var(--nih-space-section-inline));
}

#tribe-events-pg-template {
	max-width: calc(46rem + 2 * var(--nih-space-section-inline));
}

/*
 * The archive view nests a second container that carries 96px of its own top
 * padding, which stacks on the clearance above and leaves a blank screen
 * before the search bar. The clearance is now handled one level up, so this
 * one has nothing left to do. Scoped to the view so the single event, which
 * has no such wrapper, is untouched.
 */
.tribe-common.tribe-events.tribe-events-view .tribe-events-l-container {
	/*
	 * Three classes off one element, to clear
	 *   .tribe-common--breakpoint-medium.tribe-events .tribe-events-l-container
	 * at (0,3,0). Two would only tie and win on order, which is the same bet
	 * that lost on the Donate button — and TEC adds and removes that
	 * breakpoint class from JS as the container resizes, so the rule that
	 * applies here is not even fixed for the life of the page.
	 */
	padding-top: 0;
}

/* The back link is the first thing on a single event, so it carries the gap
   to the content beneath it rather than sitting flush against the title. */
#tribe-events-pg-template .tribe-events-back {
	margin-bottom: 1.5rem;
}

/* --- Share row ------------------------------------------------------------ */

/*
 * Rendered by nihub_share_row(). See the long note there for why these are
 * this theme's own inline SVGs rather than AddToAny's — the short version is
 * that AddToAny draws its icons from a third-party script, and when that does
 * not load the buttons are 0x0 rather than merely unstyled.
 *
 * A list because it is one: three links to three places. list-style and the
 * padding go because Mistify puts both on every ul.
 *
 * WHY EVERY SELECTOR NAMES TWO WRAPPERS
 * -------------------------------------
 * nihub_share_row() hooks the_content and guards on is_singular(), so the row
 * appears on single events as well as on pages and summaries — but a single
 * event is not rendered by the block template. The Events Calendar has its own
 * one, and it wraps the content in
 *
 *     .tribe-events-single-event-description.tribe-events-content
 *
 * where the block templates wrap it in .entry-content. Scoped to the latter
 * alone, the whole section missed on events: the row fell back to Mistify's
 * default ul, which is bullets, indent, and the site's link colour on all
 * three icons.
 *
 * :is() rather than a second comma-separated selector per rule, because :is()
 * takes the specificity of its most specific argument — both are a single
 * class — so each rule below weighs exactly what it weighed before. That
 * matters here more than it usually would: the notes further down explain
 * which parent rules these were measured to beat, and a comma-separated list
 * would have been just as correct while making that arithmetic harder to
 * check.
 */
:is(.entry-content, .tribe-events-content) ul.nih-share {
	display: flex;
	gap: 0.25rem;
	align-items: center;
	margin-top: var(--nih-space-stack);
	/*
	 * A bottom margin as well as a top one. On a summary the row is followed
	 * by the tags panel, and on a page it is the last thing before the
	 * footer — where without this it sits about 15px off a black band. It
	 * never had to be said while AddToAny owned the row, because its icons
	 * were 0x0 and the container collapsed to nothing.
	 */
	margin-bottom: var(--nih-space-stack) !important;
	padding-left: 0;
	list-style: none;
}

.nih-share__item {
	margin: 0;
}

/*
 * 40px box around a 32px glyph, which is AddToAny's own size-32 metric and
 * the size the client configured. It also clears the 24px minimum for a
 * pointer target with room to spare.
 *
 * Qualified with the tag: Mistify and Kubio both colour `.entry-content a` at
 * two-class specificity, which a lone class ties with and loses to on order —
 * the same reason the section rules further up are written this way. The
 * Events Calendar colours `.tribe-events-content a` the same way, so the same
 * qualification is what carries the row on events too.
 */
:is(.entry-content, .tribe-events-content) .nih-share a.nih-share__link {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 40px;
	height: 40px;
	border-radius: 4px;
	/*
	 * text-decoration is not enough on an event. The Events Calendar
	 * underlines content links with a border rather than a decoration —
	 *
	 *     .tribe-events-content a  ->  border-bottom: 1px solid ...
	 *
	 * — so each icon drew a 1px line beneath it that the border-radius above
	 * then rounded off at both ends. It never showed on pages or summaries,
	 * where Mistify underlines with text-decoration and there was no border
	 * to clear.
	 *
	 * `border: 0` rather than `border-bottom: 0` so a future TEC or Mistify
	 * release putting a line on any other side is covered too. It also holds
	 * through hover without a rule of its own: TEC re-asserts the border on
	 * `.tribe-events-content a:hover` at (0,2,1), and this rule is (0,3,1).
	 */
	border: 0;
	text-decoration: none;
}

/*
 * Brand colours, which is the one place on this site they are used.
 *
 * A share icon is recognised before it is read, and recolouring these to the
 * palette would cost that for no gain — nobody is confused about whose logo
 * is whose. It is also what AddToAny's "original" icon setting, which the
 * client chose, would have drawn.
 *
 * Instagram's is flat #e1306c rather than its gradient: a single-colour mark
 * matches the other two, and the gradient needs a defs block per icon.
 *
 * Carrying the full selector weight of the rule above rather than a lone
 * class, because these are competing with the theme's link colour and a
 * one-class rule loses to it — measured: all three rendered in the site's
 * indigo before this.
 */
:is(.entry-content, .tribe-events-content) .nih-share a.nih-share__link--facebook {
	color: #1877f2;
}

:is(.entry-content, .tribe-events-content) .nih-share a.nih-share__link--instagram {
	color: #e1306c;
}

:is(.entry-content, .tribe-events-content) .nih-share a.nih-share__link--reddit {
	color: #ff4500;
}

/*
 * Hover and focus lift the whole badge rather than shifting the glyph colour,
 * so the feedback is the same for all three regardless of how light or dark
 * the brand colour is.
 */
:is(.entry-content, .tribe-events-content) .nih-share a.nih-share__link:hover {
	background: var(--nih-surface-alt);
}

:is(.entry-content, .tribe-events-content) .nih-share a.nih-share__link:focus-visible {
	outline: 3px solid var(--nih-accent);
	outline-offset: 2px;
}

/* --- Offscreen menu close button ----------------------------------------- */

/*
 * Rendered by nihub_offscreen_close_button; Kubio binds it by the `close`
 * class and needs no script from us. See the note there for why the class has
 * to be exactly that, and why the glyph must not take pointer events.
 *
 * Hidden by default and shown only inside the panel: the same block renders
 * the offscreen content on every header, and outside an open panel this button
 * has nothing to close.
 */
.nih-offscreen-close {
	display: none;
}

/*
 * Qualified with the element as well as the panel, because Kubio styles every
 * button on the site from its global data — 8px/24px padding and a 2px border,
 * which turned a 40px round button into a 53px lozenge. That rule is (0,1,1),
 * so a lone class here loses to it; this is (0,2,1).
 *
 * Positioned against the panel rather than placed in its flow: the panel's
 * first row is the logo, and a close button belongs in the corner rather than
 * stacked above it. The offscreen content container is position-relative and
 * exactly coincides with the panel, so it is the containing block.
 */
.kubio-offscreen button.nih-offscreen-close {
	display: flex;
	position: absolute;
	top: 0.85rem;
	right: 0.85rem;
	z-index: 2;
	align-items: center;
	justify-content: center;
	/* 40px square: comfortably past the 24px minimum for a touch target, on
	   the one control someone reaches for in a hurry. */
	width: 2.5rem;
	height: 2.5rem;
	min-width: 0;
	padding: 0;
	border: 0;
	border-radius: 999px;
	background: transparent;
	color: var(--nih-white);
	cursor: pointer;
}

/*
 * The glyph is inert, deliberately.
 *
 * Kubio's close handler inspects event.target and bails out for anything
 * inside the panel that is not itself .close. Without this the SVG would be
 * the target on most taps, the guard would match, and the button would appear
 * bound while doing nothing at all.
 */
.kubio-offscreen button.nih-offscreen-close svg {
	pointer-events: none;
}

.kubio-offscreen button.nih-offscreen-close:hover,
.kubio-offscreen button.nih-offscreen-close:focus-visible {
	background: rgb(255 255 255 / 0.12);
}

.kubio-offscreen button.nih-offscreen-close:focus-visible {
	outline: 2px solid var(--nih-white);
	outline-offset: 2px;
}

/* --- Search ------------------------------------------------------------- */

/*
 * The nav item is a magnifying glass, but the word "Search" stays in the
 * document.
 *
 * This is the classic image-replacement technique — the text is pushed out of
 * an overflow-hidden box rather than removed or set to font-size:0 — so a
 * screen reader still announces a link called "Search" while sighted visitors
 * see only the icon. An icon with no accessible name is one of the more common
 * WCAG failures, and it would be an odd one to ship on the same site where we
 * have just made a point of the contrast work.
 *
 * The glyph is a mask rather than a background image so it paints in
 * currentColor. That matters here: the header text colour already differs
 * between the front page (white, over the mural) and interior pages (ink, on
 * white), and this inherits both without a second rule.
 */
#kubio .kubio-menu > ul > li.nih-nav-search > a {
	display: inline-block;
	width: 1.15rem;
	height: 1.15rem;
	overflow: hidden;
	white-space: nowrap;
	text-indent: 110%;
	vertical-align: middle;
	background-color: currentColor;
	-webkit-mask: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="2.2" stroke-linecap="round"><circle cx="11" cy="11" r="7"/><line x1="16.2" y1="16.2" x2="21" y2="21"/></svg>') no-repeat center / contain;
	mask: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="2.2" stroke-linecap="round"><circle cx="11" cy="11" r="7"/><line x1="16.2" y1="16.2" x2="21" y2="21"/></svg>') no-repeat center / contain;
}

/* Keyboard users need to see where they are, and the icon has no text to
   underline. */
#kubio .kubio-menu > ul > li.nih-nav-search > a:focus-visible {
	outline: 2px solid currentColor;
	outline-offset: 4px;
}

/*
 * In the offscreen panel, the word rather than the glyph.
 *
 * The icon treatment above is built for a horizontal bar, where an 1.15rem box
 * sits comfortably between text labels. The panel stacks its items and makes
 * each anchor a flex item, so `flex: 1 1 auto` from Kubio overrides that box
 * and the mask scales with it — the glyph rendered at 40x40 beside 14px
 * labels, which is where "much too large" comes from. It was also the one item
 * in the list with no word next to it, in a menu that is otherwise all words.
 *
 * So this undoes the image replacement rather than resizing it: the real text
 * has been in the document all along, pushed out of an overflow-hidden box, and
 * this simply lets it back in.
 *
 * Every property the rule above sets is reset, and the order matters most for
 * background-color — that is the glyph's paint, not a background, so leaving it
 * would put a solid block of currentColor behind the label.
 *
 * Scoped on .kubio-offscreen rather than a breakpoint. A media query would work
 * today, since the bar and the panel are never shown at the same width, but it
 * would silently desync the moment Kubio's menu breakpoint is changed in the
 * builder. The class is on the panel itself and cannot drift.
 */
#kubio .kubio-offscreen .kubio-menu > ul > li.nih-nav-search > a {
	/* flex to match its siblings in the panel, which Kubio lays out that way */
	display: flex;
	width: auto;
	height: auto;
	overflow: visible;
	white-space: normal;
	text-indent: 0;
	vertical-align: baseline;
	background-color: transparent;
	-webkit-mask: none;
	mask: none;
}

/* The label carries its own focus ring in the panel, so the offset tuned for a
   small glyph would sit oddly wide around a full-width row. */
#kubio .kubio-offscreen .kubio-menu > ul > li.nih-nav-search > a:focus-visible {
	outline-offset: 0;
}

.nih-hero .nih-searchbox {
	margin-top: 1.5rem;
	max-width: 34rem;
}

.nih-hero .nih-searchbox .wp-block-search__input {
	border: 1px solid var(--nih-bone);
	border-radius: 4px;
	padding: 0.7rem 0.9rem;
	font-size: 1rem;
}

.nih-hero .nih-searchbox .wp-block-search__button {
	background-color: var(--nih-accent);
	color: var(--nih-white);
	border: 0;
	font-weight: 700;
	padding-inline: 1.1rem;
}

.tribe-events-single .tribe-events-sub-nav {
    padding: 0;
}

[data-kubio], .with-kubio-global-style, [data-kubio] p, .with-kubio-global-style p, p[data-kubio], .wp-block-woocommerce-mini-cart-contents {
	font-size: 16px !important;
}
