/**
 * Theme Name: Blocksy Child
 * Theme URI: https://troutchallenge.com
 * Description: Child theme for troutchallenge.com — editorial presentation layer.
 * Author: Iverson Creative LLC
 * Template: blocksy
 * Version: 1.26.0
 * Text Domain: blocksy-child
 */

/* Your styles go here. To restyle the table of contents, override the custom
   properties rather than editing assets/toc.css — that file carries the
   accessibility rules and you want its updates, not a fork of it.

   :root {
     --tc-toc-fg:     #304673;
     --tc-toc-accent: #38648F;
     --tc-toc-rail-w: 15rem;
     --tc-bar-h:      1.5rem;

     --tc-toc-target: 32px;   (24px is the WCAG 2.2 AA floor — see toc.css)
     --tc-bar-target: 44px;   (phone control; leave it generous)
   }
*/

/* -----------------------------------------------------------------------------
   Block / layout cleanup

   Standard across Iverson Creative Blocksy child themes. The block editor and
   Blocksy each apply their own vertical rhythm and together they double up:
   spacers land under a margin that is already there, covers carry padding the
   design did not ask for, and headings arrive with a top margin fighting
   whatever spacing was set deliberately.

   The !important throughout is deliberate — these override theme and core block
   styles that are themselves specific. Softening them stops the snippet working.
----------------------------------------------------------------------------- */

.alignfull,
.wp-block-cover.alignwide {
	margin-bottom: 0 !important;
}

.wp-block-blocksy-query,
.wp-block-columns {
	margin-bottom: 0 !important;
}

.wp-block-cover {
	padding: 0 !important;
}

/* Remove bottom margin before spacer blocks to avoid double vertical rhythm. */

*:has(+ .wp-block-spacer) {
	margin-bottom: 0 !important;
}

/* Headings lose their top margin EXCEPT after a paragraph or a list, where the
   gap is doing real work: it separates the previous section's prose from the
   next section's heading. Narrowing the rule rather than zeroing and restoring,
   because `revert` would fall back to the user-agent value, not the theme's —
   we would be replacing the theme's spacing with the browser's. */

.wp-block-heading:not(:is(p, ul, ol, .wp-block-list) + .wp-block-heading) {
	margin-top: 0 !important;
	margin-block-start: 0 !important;
}

/* -----------------------------------------------------------------------------
   Accordion: a rule between items

   border-top on every item after the first, rather than border-bottom on all
   of them. Both look identical when the accordion sits alone, but only this
   version puts no line under the last item — so the accordion ends where its
   content ends instead of leaving a rule hanging above whatever follows.
----------------------------------------------------------------------------- */

.wp-block-accordion .wp-block-accordion-item + .wp-block-accordion-item {
	border-top: 1px solid var(--theme-border-color, currentColor);
}

/* -----------------------------------------------------------------------------
   Accordion: even vertical rhythm, and rules top and bottom of the group

   The unevenness came from block gap, not from the toggle: items carried a
   24px BOTTOM margin, so the divider sat 24px below one heading and flush
   against the next. Zeroing that margin and giving the toggle its own even
   padding puts each rule exactly midway between two headings.
----------------------------------------------------------------------------- */

.wp-block-accordion {
	--tc-accordion-pad: 1rem;

	border-block: 1px solid var(--theme-border-color, currentColor);
}

/* The block-gap margin is what made the spacing lopsided. */
.wp-block-accordion > .wp-block-accordion-item {
	margin-block: 0;
}

.wp-block-accordion .wp-block-accordion-heading__toggle {
	padding-block: var(--tc-accordion-pad);
}

/* Open panels need the same breathing room at the bottom, or the content sits
   hard against the next rule. */
.wp-block-accordion .wp-block-accordion-panel:not([hidden]) {
	padding-block-end: var(--tc-accordion-pad);
}

/* -----------------------------------------------------------------------------
   Share box: heading inline with the icons

   .ct-block-wrapper is a generic Blocksy wrapper used in many places, so this
   is scoped with :has() to only the one that actually contains a shares block.
   A bare .ct-block-wrapper rule would flex wrappers all over the site.

   flex-wrap is deliberate: at narrow widths the label drops above the icons
   instead of forcing horizontal overflow (SC 1.4.10 reflow).
----------------------------------------------------------------------------- */

.ct-block-wrapper:has(> .ct-shares-block) {
	--tc-share-gap: 0.75rem;

	display: flex;
	align-items: center;
	flex-wrap: wrap;
	gap: var(--tc-share-gap);

	/* Label and icons sit against the right edge of the column. The wrapper
	   already fills its parent column, so flex-end has room to work against —
	   if the block is ever moved into a shrink-to-fit container this becomes a
	   no-op rather than a bug, and the fix would be there, not here. */
	justify-content: flex-end;
}

/* The heading's block margin is what would otherwise offset it from the icons
   even once the wrapper is flexed. */
.ct-block-wrapper:has(> .ct-shares-block) > .wp-block-heading {
	margin-block: 0;
}

/* The icons sit on the text BASELINE of a 26.4px line box, which leaves them
   ~2px above optical centre. .ct-share-box holds exactly one inline-flex child
   (the icon row), so flexing the box re-centres it without touching the spacing
   between icons — those are laid out inside that child, not here. */

.ct-block-wrapper:has(> .ct-shares-block) .ct-share-box {
	display: flex;
	align-items: center;
}

/* -----------------------------------------------------------------------------
   Editorial callouts

   These come from the content migration carrying a semantic variant class:
   --rules (what the law requires), --caution (will cost a fish or a citation),
   --trap (a specific, named misreading), --source-caveat (a sourcing limit).
   Until now nothing styled them, so a callout title rendered identically to a
   section heading — which is what made the heading spacing look inconsistent.
   It was not the spacing; it was two different things looking the same.

   Treatment matches the blockquote deliberately: 4px inline-start border,
   24px inset. Both read as "set apart from the argument, not part of it".
----------------------------------------------------------------------------- */

/* One token for the large editorial gap, so the callout and the blockquote
   cannot drift apart. 2.625rem is 42px: the gap Blocksy gives an h3 after a
   paragraph, which is what everything here is being matched to. */

:root {
	--tc-block-gap-lg: 2.625rem;
}

/* ⚠ SPECIFICITY, not !important, and the reason is worth keeping: Blocksy's
   main.min.css is enqueued AFTER the child stylesheet and carries
     :is(.is-layout-flow, .is-layout-constrained) > :where(:not(h1..h6))
       { margin-block-start: 0; margin-block-end: var(--theme-content-spacing); }
   which is also (0,1,0). Equal specificity, later source order, so a bare
   `.tc-callout` loses.

   The fix is a DOUBLED CLASS — `.tc-callout.tc-callout` is (0,2,0) and matches
   the same single element. Not `.entry-content .tc-callout`, which is also
   (0,2,0) but only exists on the front end: the block editor canvas has no
   `.entry-content` wrapper, so an editor stylesheet using it would silently do
   nothing and the callout would look unstyled while writing. Doubled classes
   are context-free and work in both. */

.tc-callout.tc-callout {
	/* Matches the gap an h3 gets after a paragraph, so a callout and a section
	   heading sit on the same rhythm rather than at two different distances. */
	--tc-callout-gap: var(--tc-block-gap-lg);

	/* river-700 — the same value the theme gives blockquotes. */
	--tc-callout-accent: #38648F;

	/* Both sides, from one token. Blocksy sets margin-block-end to
	   --theme-content-spacing (24px) on non-heading flow children, which is what
	   made the bottom smaller than the top. */
	margin-block: var(--tc-callout-gap);
	border-inline-start: 4px solid var(--tc-callout-accent);
	padding-inline-start: 24px;
}

/* A callout that opens a section does not need the gap twice. */
.tc-callout.tc-callout:first-child {
	margin-block-start: 0;
}

/* VARIANT HOOKS — all four intentionally share the blockquote colour for now.
   Distinguishing them is a design decision, not a technical one: set an accent
   per variant and they separate at a glance without any other change.
   ⚠ A border is a non-text UI component: WCAG 2.2 SC 1.4.11 wants 3:1 against
   the surface it sits on, so check any colour you pick rather than eyeballing it. */

.tc-callout--rules         { --tc-callout-accent: #38648F; }
.tc-callout--caution       { --tc-callout-accent: #38648F; }
.tc-callout--trap          { --tc-callout-accent: #38648F; }
.tc-callout--source-caveat { --tc-callout-accent: #38648F; }

/* Blockquotes take the same large gap beneath them. Needs the same specificity
   bump as the callout — Blocksy's later main.min.css sets margin-block-end to
   --theme-content-spacing on every non-heading flow child, at (0,1,0). */

blockquote.wp-block-quote.wp-block-quote {
	margin-block: var(--tc-block-gap-lg);
}

/* -----------------------------------------------------------------------------
   Boundless featured image — ARTICLES ONLY

   Bleeds the featured image to the top and side edges of the boxed card while
   keeping its bottom margin, and keeps the card's rounded top corners.

   Scoped to .single-tc_conservation deliberately: species and challenge singles
   are excluded, so a featured image added to one of those keeps the theme's
   normal inset. Widening this later is a matter of adding a body class to the
   selector, not of rewriting the rule.

   Both numbers come from the theme rather than being hardcoded:
     · the bleed uses --theme-boxed-content-spacing, which IS the card padding,
       so changing the padding in the Customizer keeps the bleed exact;
     · `border-radius: inherit` takes the card's own computed radius, so the
       image corners follow it without anyone restating the value.

   :first-child is load-bearing. The negative top margin is only correct when
   the image is the first thing in the card — anywhere else it would pull the
   image up over whatever precedes it.
----------------------------------------------------------------------------- */

.single-tc_conservation .site-main article > .ct-featured-image:first-child {
	--bleed: var(--theme-boxed-content-spacing, 20px);

	margin-block-start: calc(var(--bleed) * -1);
	margin-inline: calc(var(--bleed) * -1);
	margin-block-end: var(--theme-content-spacing, 1.5em);

	/* Required, or the image's square corners overhang the rounded card. */
	overflow: hidden;

	border-radius: inherit;
	border-end-start-radius: 0;
	border-end-end-radius: 0;
}

.single-tc_conservation .site-main article > .ct-featured-image:first-child img {
	display: block;
	width: 100%;
}

/* The caption is inside the bled figure, so it inherits the bleed and would run
   to the card edge. Put the card's padding back on it — and only on it, so the
   image itself stays boundless. --bleed is inherited from the figure above. */

.single-tc_conservation .site-main article > .ct-featured-image:first-child figcaption,
.single-tc_conservation .site-main article > .ct-featured-image:first-child .wp-element-caption {
	padding-inline: var(--bleed);
}

/* -----------------------------------------------------------------------------
   Breadcrumb + share row — desktop only

   Hides the WHOLE columns row (breadcrumbs, spacer and share block) below the
   narrow breakpoint, not just the share column.

   Selected with :has() on the row that contains the share block, so it only
   affects this row and keeps working if the columns are reordered in the
   editor. A :nth-child or a bare .wp-block-columns rule would reach every
   columns block on the site.

   689.98px is the canonical narrow breakpoint used across this project and it
   pairs with Blocksy's own min-width: 690px. A round 690px would leave a
   hairline band where neither rule applies.

   Note: display:none hides it visually and removes it from the accessibility
   tree, but the markup stays in the DOM — so the breadcrumb's schema.org
   ListItem data is still there for crawlers. This costs presentation, not
   structured data.
----------------------------------------------------------------------------- */

@media (max-width: 689.98px) {
	.wp-block-columns:has(.ct-shares-block) {
		display: none;
	}

	/* The 40px spacer that follows it goes too — otherwise hiding the row
	   leaves its breathing room behind as an unexplained gap. Adjacent-sibling
	   selector rather than a class, so it tracks the row it belongs to instead
	   of matching every spacer on the site. */
	.wp-block-columns:has(.ct-shares-block) + .wp-block-spacer {
		display: none;
	}
}

/* -----------------------------------------------------------------------------
   Header — two rows, even 30px rhythm, logo centred across both (desktop only)

   Target: 30px above the menu, 30px between the menu and the search/CTA row,
   30px below the search/CTA row, with the logo centred in that whole space.

   Three things this has to fight, each learned by measuring:

   1. Blocksy sets row MIN-HEIGHTS (50px top, 120px middle) from the Customizer
      row-height control. Those inflate the gaps and made the menu's own margin
      overflow its row. They are zeroed here, so ⚠ THE CUSTOMIZER'S ROW-HEIGHT
      CONTROL NO LONGER DOES ANYTHING above 1000px — spacing comes from
      --tc-hdr-gap instead. Change it here, not there.

   2. Spacing is driven by ROW PADDING, not element margins. The menu's own
      margin was being swallowed by the flex centring, so it could not be relied
      on. Any margin set on the menu in the Customizer is zeroed for the same
      reason — one source for the rhythm.

   3. The logo is ABSOLUTELY POSITIONED AGAINST THE HEADER. It must not
      contribute height: an in-flow logo tall enough to span both rows becomes
      the tallest thing in the middle row and pushes the row open, which is the
      opposite of spanning. Stretching it top-to-bottom of the header centres it
      across both rows and cannot overflow them — see the rule below.

   Its left inset is derived in CSS from Blocksy's own container variables, not
   measured. assets/header.js publishes only the logo's HEIGHT, and nothing that
   affects where the logo sits.
----------------------------------------------------------------------------- */

@media (min-width: 1000px) {
	#header {
		--tc-hdr-gap: 30px;

		/* The logo is absolutely positioned and contributes NO height, so the
		   header would otherwise be sized only by the menu and search rows — and
		   a logo taller than those overflows and gets clipped with no warning.
		   --tc-logo-height is measured by assets/header.js; this guarantees the
		   header always has room for the logo plus its gap above and below,
		   whatever size the logo is set to in the Customizer. */
		min-height: calc( var(--tc-logo-height, 0px) + (2 * var(--tc-hdr-gap)) );
	}

	#header [data-row="top"] .ct-container,
	#header [data-row="top"] .ct-container > *,
	#header [data-row="middle"] .ct-container,
	#header [data-row="middle"] .ct-container > * {
		min-height: 0;
	}

	#header [data-row="top"] {
		padding-block: var(--tc-hdr-gap) 0;
	}

	#header [data-row="middle"] {
		padding-block: var(--tc-hdr-gap);
	}

	#header [data-row="top"] nav.menu-container {
		margin-block: 0;
	}

	/* ⚠ POSITIONED AGAINST THE HEADER, not against its grid cell.
	   Two earlier versions failed the same way. A transform nudge, and then a
	   span measured from the cell, both derived the logo's position from
	   --tc-header-top-row — so a wrong value put the logo ABOVE the header's top
	   edge, where it is cut off with nothing to stop it. I claimed the second
	   was bounded; it was not, and a stress test with a deliberately wrong
	   value moved the logo to -93px.

	   Stretching top-to-bottom of the HEADER is bounded by construction: the box
	   IS the header, so a centred logo smaller than the header cannot leave it,
	   whatever any measurement says. The cost is the container's left inset,
	   which the grid cell used to provide for free — recomputed from Blocksy's
	   own container variables below. */
	#header {
		position: relative;
	}

	/* ⚠ Blocksy sets `position: relative` on the row itself, which makes the ROW
	   the containing block and silently defeats positioning against the header —
	   the logo then centres in the 102px row instead of the 160px header. Making
	   the row static hands the containing block back to #header above. Verified
	   as the actual offsetParent, not assumed.

	   The selector is deliberately over-qualified. `#header [data-row="middle"]`
	   is the same specificity as Blocksy's own rule and main.min.css loads AFTER
	   the child stylesheet, so it lost silently — the recorded load-order gotcha,
	   in a new place. Adding the element and a second attribute wins on merit. */
	#header div[data-row="middle"][data-column-set] {
		position: static;
	}

	#header [data-row="middle"] .site-branding {
		position: absolute;
		top: 0;
		bottom: 0;
		/* ⚠ DERIVED IN CSS, NEVER MEASURED. This was `var(--tc-container-inset)`,
		   published by assets/header.js — so on every load the logo painted at
		   left:0 (the fallback), flush to the viewport edge, then jumped inward
		   once the script ran. A fallback that is a *valid position* hides the
		   dependency: nothing looks broken, it just flashes.

		   Blocksy already exposes both halves of the container's own arithmetic,
		   so the inset is knowable at first paint. Using its variables rather
		   than literals means a Customizer change to either the edge spacing or
		   the container width still tracks. */
		left: max( 0px, ( 100% - min(
			var(--theme-container-width-base, 100%),
			var(--theme-normal-container-max-width, 1200px)
		) ) / 2 );
		margin: 0;
		padding: 0;
		height: auto;

		display: flex;
		align-items: center;

		/* Blocksy gives [data-row="top"] z-index:3 AND an opaque white
		   background. The branding spans both rows at z-index:auto, so the
		   menu row painted over the logo's top 28px — it read as "cut off"
		   while every geometry measurement came back correct, because the
		   box was never wrong. Paint order was. */
		z-index: 4;
	}

	/* Blocksy clips the logo wrapper (overflow: clip). Keep it free to be as
	   tall as the image it holds, so a taller logo is never trimmed by it. */
	#header [data-row="middle"] .site-branding .default-logo {
		overflow: visible;
	}
}

/* -----------------------------------------------------------------------------
   Cookie consent banner vs the Shortcuts bar (WCAG 2.2 SC 2.4.11)

   Blocksy pins BOTH of these to the bottom edge of the viewport:

     .cookie-notification  position: fixed; bottom: var(--theme-frame-size, 0px);
                           z-index: 999999
     .ct-drawer-inner      position: fixed; bottom: var(--theme-frame-size, 0px);
                           z-index: 100          (this is what holds the bar)

   Below 1000px the Shortcuts bar IS the site's only navigation, so on a first
   visit the banner painted over all four links. Measured 2026-09-07 at 320, 390
   and 768 in Chromium and WebKit: every link rect fell entirely inside the
   banner rect and elementFromPoint at each link's centre returned banner
   content, not the link. The banner is dismissible, so this is a first-visit
   condition — but it is every visitor's first visit, and the only way out is a
   control sitting on top of the navigation.

   ⚠ NOT FIXED BY RAISING THE BAR ABOVE THE BANNER. That reverses the
   obstruction rather than removing it: the nav would then cover Accept and
   Decline, trading an accessibility failure for a consent failure. It would
   also lift the bar over the off-canvas menu panel and the popup layer, which
   sit in the same stacking order. Nothing here changes any z-index. The banner
   is moved UP by the bar's height instead, so the two stop overlapping at all.

   BREAKPOINT. The bar carries .ct-hidden-lg, hidden at (min-width: 1000px), and
   Blocksy's dynamic CSS sets --shortcuts-bar-height inside
   (max-width: 999.98px). This rule uses the same boundary, so desktop is
   untouched and there is no 1px window where one applies and the other does not.

   SPECIFICITY, not !important. The base rule is `.cookie-notification` (0,1,0)
   and it arrives in a stylesheet Blocksy injects LAZILY, i.e. after this file in
   document order, so an equal-specificity override would lose. The descendant
   selector makes this (0,2,0) and takes order out of it.

   ⚠ 70px IS BLOCKSY'S OWN --shortcuts-bar-height, BUT IT CANNOT BE INHERITED
   HERE. Blocksy declares that property on .ct-drawer-canvas[data-shortcuts-bar]
   — the data-location="end" canvas — and the banner is injected into the
   data-location="start" canvas, a different subtree. The var() is kept in front
   of the literal so that if a future Blocksy ever publishes the value higher up
   the tree, the real height wins automatically and this literal stops mattering.
   Until then: change the Shortcuts bar height in the Customizer and this number
   has to change with it.

   NO DEAD SPACE AFTER CONSENT. Blocksy removes the banner from the DOM on
   Accept/Decline. This rule only ever positions the banner, so once it is gone
   there is nothing left behind — the page bottom is identical to a return visit.
----------------------------------------------------------------------------- */

@media (max-width: 999.98px) {
	.ct-drawer-canvas .cookie-notification {
		bottom: calc(
			var(--theme-frame-size, 0px) + var(--shortcuts-bar-height, 70px)
		);
	}
}
