/* ==========================================================================
   WyoHS single post ("WHS Blog Entries" Themer layout)

   Two jobs:
   1. The framed Featured Image (markup from [wyohs_post_photo]) straddles the
      bottom edge of the hero: pinned to the right on desktop, full width and
      above the body copy on phones, always lapping over the edge.
   2. The post body reads at the site's body size (16px / 1.6, ink) instead of
      the BB theme's 14px grey default.

   Where the module lives matters. The HTML module holding the shortcode sits
   in its own one-column group at the BOTTOM of the HERO row, not in the
   content row below it. That is what makes the overlap easy: the hero's
   .fl-row-content is already position:relative, so the frame can be pinned to
   it and pushed down past the hero's 150px of bottom padding.

   Classes are set in Beaver Builder under Advanced > Class:
     .wyohs-post           the content row
     .wyohs-post__photo    the HTML module holding the shortcode (in the hero)
     .wyohs-post__content  the Post Content module

   Sizes are px on purpose: the BB theme sets html font-size to 62.5%.
   ========================================================================== */

/* ---------- the framed photo -------------------------------------------- */

.wyohs-postphoto {
	/* Ratio and artwork URL are set inline by the shortcode; the fallbacks keep
	   the frame usable if the art is renamed or the markup is hand-written. */
	--postphoto-ratio: 1160 / 860;
	--postphoto-frame: none;

	/* The frame's transparent window, measured off the artwork (1160x860):
	   the hole runs x 43-1106, y 37-805 and leans 0.79deg clockwise. The box
	   below is a little larger than the hole on every side so the photo tucks
	   under the paper and its rotated corners stay hidden. */
	--postphoto-window-x: 2.82%;
	--postphoto-window-y: 3.20%;
	--postphoto-window-w: 93.5%;
	--postphoto-window-h: 91.5%;
	--postphoto-tilt: 0.79deg;

	position: relative;
	aspect-ratio: var(--postphoto-ratio);
	margin: 0;
	padding: 0;
}

/* The photo sits underneath, tilted to sit square in the paper; the frame is
   painted over the top. */
.wyohs-postphoto__window {
	position: absolute;
	left: var(--postphoto-window-x);
	top: var(--postphoto-window-y);
	width: var(--postphoto-window-w);
	height: var(--postphoto-window-h);
	display: block;
	overflow: hidden;
	transform: rotate(var(--postphoto-tilt));
	transform-origin: 50% 50%;
	background: var(--wyohs-navy, #1b3a5c);
}

.wyohs-postphoto__window img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
	object-position: center center;
}

.wyohs-postphoto::after {
	content: "";
	position: absolute;
	inset: 0;
	background-image: var(--postphoto-frame);
	background-size: 100% 100%;
	background-repeat: no-repeat;
	pointer-events: none;
	z-index: 1;
}

/* ---------- how it laps the hero ---------------------------------------- */

/* These live on :root because the mobile rules below need them on the content
   row as well as on the frame, and custom properties inherit down rather than
   across. */
:root {
	/* The hero row's own bottom padding, as set in Beaver Builder
	   (Row Settings > Style > Spacing). The desktop lap is measured from the
	   hero's .fl-row-content box, which stops where this padding begins, so
	   this number has to match the layout. If the frame ever drifts down the
	   page, check here first — it was 150px until the row was re-spaced. */
	--hero-pad: 40px;

	/* How far the frame hangs BELOW the hero's bottom edge on desktop. */
	--postphoto-lap: 290px;

	/* Phones and tablets: a small, deliberate overlap, and the clear air below
	   the frame before the first line of copy. Both are honoured exactly,
	   because the mobile block owns the two paddings involved rather than
	   trying to predict them. */
	--postphoto-lap-mobile: 24px;
	--postphoto-clear-mobile: 32px;

	--postphoto-width: 460px;

	/* Minimum air between the body copy and the frame's left edge. */
	--postphoto-gutter: 34px;

	/* A short post can run out of words before the rail runs out of rail. The
	   frame is anchored to the hero and hangs --postphoto-lap down into the
	   content row; the info card hangs below that again. The post navigation,
	   meanwhile, just follows the copy — so on a five-paragraph entry the two
	   land on top of each other.

	   This is the floor under the copy that keeps them apart: 270px from the
	   top of the body to the foot of the frame, 30px of gap, then room for a
	   three-line card and some air. Where post.js runs it measures the card in
	   front of it and writes the exact figure instead, so this one only has to
	   cover the case where the script never does. */
	--postphoto-rail-floor: 560px;
}

/* Above the row's 1440px cap the geometry changes: the row stops growing, and
   the copy's containing block ends up sitting about 23px inside the hero's. The
   token has to come down by that much or the gap visibly opens up on a large
   monitor — which is what left 94px of dead air there before. Measured gap with
   these two values: 28px at 1000px wide, 38px at 1440, 36px at 1600. */
@media (min-width: 1480px) {
	:root { --postphoto-gutter: 11px; }
}

/* Every rule below is guarded with :has(.wyohs-postphoto). A post with no
   featured image prints an empty module, and an empty module carrying the
   mobile negative margin would drag the content row up into the hero. */
@media (min-width: 993px) {
	.wyohs-post__photo.fl-module:has(.wyohs-postphoto) {
		position: absolute;
		top: auto;
		/* Bottom is measured from the hero's .fl-row-content, which stops where
		   the wrap padding begins. Clear that, then hang by the lap. */
		bottom: calc(-1 * (var(--hero-pad) + var(--postphoto-lap)));
		right: 20px;
		width: var(--postphoto-width);
		max-width: 40%;
		margin: 0 !important;
		z-index: 3;
	}

	/* Reserve exactly the frame plus the gutter, so the copy runs as close to
	   the frame as it is allowed to and no closer — at every desktop width.
	   A flat percentage cannot do this: it read as 94px of dead air at 1600px
	   and as a 26px OVERLAP at 1100px, because the frame is capped in pixels
	   while the copy was capped in percent. min(460px, 40%) is the frame's own
	   width expression, so the two track each other as the window changes. */
	.wyohs-post__content {
		max-width: calc(100% - min(var(--postphoto-width), 40%) - var(--postphoto-gutter));
	}

	/* Guarded, because a post with no featured image has no rail to clear and
	   should be allowed to be as short as it likes. */
	body:has(.wyohs-postphoto) .wyohs-post__content {
		min-height: var(--postphoto-rail-floor);
	}
}

/* Phones and tablets: back in the flow, full width, and only just lapping the
   hero edge — the copy has to clear the frame completely.

   The two paddings that decide this are set here rather than read off the row,
   so the overlap and the gap are exactly the two tokens above. With the hero's
   bottom padding zeroed, a negative margin of -lap puts the hero edge that far
   above the frame's bottom; the content row's top padding then carries both the
   lap and the clear air. Leave the paddings to Beaver Builder and the result
   depends on whatever the row spacing happens to be — which is how the frame
   ended up sitting on top of the first two paragraphs. */
@media (max-width: 992px) {
	.fl-row:has(.wyohs-post__photo .wyohs-postphoto) > .fl-row-content-wrap {
		padding-bottom: 0 !important;
	}

	.wyohs-post__photo.fl-module:has(.wyohs-postphoto) {
		position: static;
		float: none;
		width: auto;
		max-width: none;
		/* No side margin: layout.css puts a 20px gutter on the row itself below
		   993px, so the paper edge already lines up with the body copy. Adding
		   any here would stack on top of it. */
		margin: 28px 0 calc(-1 * var(--postphoto-lap-mobile)) !important;
		z-index: 3;
	}

	body:has(.wyohs-postphoto) .wyohs-post > .fl-row-content-wrap {
		padding-top: calc(var(--postphoto-lap-mobile) + var(--postphoto-clear-mobile)) !important;
	}

	.wyohs-post__content { max-width: none; }
}

@media (max-width: 600px) {
	:root {
		--postphoto-lap-mobile: 18px;
		--postphoto-clear-mobile: 26px;
	}
	.wyohs-post__photo.fl-module:has(.wyohs-postphoto) { margin-top: 22px !important; }
}

/* ---------- post body copy ---------------------------------------------- */

/* The BB theme's default is 14px in grey; the rest of the site reads at 16px
   in ink (see .wyohs-prose in home.css). Match it. */
.wyohs-post__content,
.wyohs-post__content p,
.wyohs-post__content li {
	font-size: 16px;
	line-height: 1.6;
	color: var(--wyohs-ink, #1a1a1a);
}

.wyohs-post__content p { margin: 0 0 1.15em; }
.wyohs-post__content p:last-child { margin-bottom: 0; }

.wyohs-post__content h2,
.wyohs-post__content h3,
.wyohs-post__content h4 { color: var(--wyohs-navy, #1b3a5c); }

.wyohs-post__content h2 { font-size: 30px; line-height: 1.2; margin: 1.4em 0 .5em; }
.wyohs-post__content h3 { font-size: 24px; line-height: 1.25; margin: 1.3em 0 .5em; }

.wyohs-post__content blockquote {
	margin: 1.6em 0;
	padding: 4px 0 4px 22px;
	border-left: 3px solid var(--wyohs-sand, #d2a56c);
	font-family: var(--wyohs-serif, 'Young Serif', Georgia, serif);
	font-size: 20px;
	line-height: 1.4;
	color: var(--wyohs-navy, #1b3a5c);
}

.wyohs-post__content a {
	color: var(--wyohs-navy, #1b3a5c);
	text-decoration: underline;
	text-decoration-color: var(--wyohs-sand, #d2a56c);
	text-underline-offset: 3px;
	text-decoration-thickness: 2px;
}

.wyohs-post__content a:hover { color: var(--wyohs-green, #4e9553); text-decoration-color: currentColor; }

.wyohs-post__content ul,
.wyohs-post__content ol { margin: 0 0 1.15em 1.3em; }
.wyohs-post__content li { margin-bottom: .4em; }

/* ---------- the typewritten info card ----------------------------------- */

/* Markup from [wyohs_post_meta]; the module carrying it sits in the CONTENT
   row after the post body, which is the phone arrangement and the one you get
   with no JavaScript. On a desktop post.js lifts it into .wyohs-post__photo
   and the rules further down take over. */

.wyohs-postmeta {
	/* Two faces: the labels are set like every other small header on the site,
	   and only the copy beside them is typewritten. */
	--postmeta-label-face: var(--wyohs-display, 'Special Gothic Condensed One', 'Arial Narrow', sans-serif);
	--postmeta-face: 'Special Elite', 'Courier New', Courier, monospace;
	--postmeta-line: 28px;
	--postmeta-label: 15px;
	--postmeta-value: 16px;
	--postmeta-gutter: 14px;
	--postmeta-row-gap: 18px;

	/* How far the card sits below the frame, and how much air it keeps from
	   the top of the window once it is pinned. The second is a floor: post.js
	   adds the live height of the sticky header to it. */
	--postmeta-gap: 30px;
	--postmeta-stick-top: 24px;

	/* The paper does not fill its own artwork. In the 1160x860 frame the sheet
	   runs from x 4 to x 1128 across its lower half, so the card is pulled in
	   by the same fractions and its dashed rules stop exactly where the photo
	   does. Percentages, not pixels, so it holds as the frame scales. */
	--postmeta-inset-left: 0.34%;
	--postmeta-inset-right: 2.67%;

	margin: 44px 0 0;
}

.wyohs-postmeta__list {
	display: grid;
	grid-template-columns: auto minmax(0, 1fr);
	align-items: baseline;
	column-gap: var(--postmeta-gutter);
	row-gap: var(--postmeta-row-gap);
	margin: 0;
}

.wyohs-postmeta__label {
	margin: 0;
	font-family: var(--postmeta-label-face);
	font-weight: 400;
	font-size: var(--postmeta-label);
	line-height: var(--postmeta-line);
	letter-spacing: 2px;
	text-transform: uppercase;
	text-align: right;
	white-space: nowrap;
	color: var(--wyohs-ink, #1a1a1a);
}

/* The rule under the copy has to run the full width of the column on EVERY
   line, not just under the words, which rules out text-decoration. So the
   value paints a tile: 6px wide, one line tall, carrying a 2px dash in its
   last pixel row. Tiling it gives a dashed rule at the foot of every line box,
   edge to edge, however the text happens to wrap.

   The tile is an inline SVG rather than a gradient because a gradient can only
   stripe in one axis at a time — the alternative is masking, which would also
   mask the words. The dash colour is baked into the data URI and has to be
   changed there; it is --wyohs-sand, #d2a56c. */
.wyohs-postmeta__value {
	margin: 0;
	font-family: var(--postmeta-face);
	font-size: var(--postmeta-value);
	line-height: var(--postmeta-line);
	color: var(--wyohs-navy, #1b3a5c);
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='6' height='28'%3E%3Crect x='0' y='27' width='2' height='1' fill='%23d2a56c'/%3E%3C/svg%3E");
	background-size: 6px var(--postmeta-line);
	background-repeat: repeat;
	background-position: 0 0;
}

/* A link typed into the caption gets a rule of its own. The series link below
   does not: it already sits on the dashed rule, and the arrow is the tell. */
.wyohs-postmeta__value a:not(.wyohs-postmeta__link) {
	color: inherit;
	text-decoration: none;
	border-bottom: 1px solid var(--wyohs-navy, #1b3a5c);
}

/* ---------- the series link and its arrow -------------------------------- */

/* A named colour rather than `inherit`, because inheriting is exactly what
   goes wrong once the card is docked in the hero. See the docked block below. */
.wyohs-postmeta .wyohs-postmeta__link {
	color: var(--wyohs-navy, #1b3a5c);
	text-decoration: none;
	transition: color .15s ease;
}

.wyohs-postmeta .wyohs-postmeta__link:hover,
.wyohs-postmeta .wyohs-postmeta__link:focus-visible {
	color: var(--wyohs-green, #4e9553);
}

/* Drawn rather than fetched: an empty span, a rotated bar for the shaft and a
   two-sided box for the head. It has to be CSS — the host's firewall refuses
   to save a PHP file with an svg tag in it, so the markup carries a span and
   the picture lives here. currentColor means it follows the link. */
.wyohs-postmeta__arrow {
	position: relative;
	display: inline-block;
	width: .68em;
	height: .68em;
	margin-left: .34em;
	vertical-align: -.04em;
	transition: transform .15s ease;
}

/* The shaft runs corner to corner, so it is the diagonal of the box: root 2. */
.wyohs-postmeta__arrow::before {
	content: "";
	position: absolute;
	left: 0;
	bottom: 0;
	width: 141%;
	height: 2px;
	background: currentColor;
	border-radius: 1px;
	transform-origin: 0 100%;
	transform: rotate(-45deg);
}

.wyohs-postmeta__arrow::after {
	content: "";
	position: absolute;
	right: 0;
	top: 0;
	width: 60%;
	height: 60%;
	border-top: 2px solid currentColor;
	border-right: 2px solid currentColor;
}

/* The arrow leans out of the link on hover, the way a signpost would. */
.wyohs-postmeta .wyohs-postmeta__link:hover .wyohs-postmeta__arrow,
.wyohs-postmeta .wyohs-postmeta__link:focus-visible .wyohs-postmeta__arrow {
	transform: translate(1px, -1px);
}

@media (prefers-reduced-motion: reduce) {
	.wyohs-postmeta .wyohs-postmeta__link,
	.wyohs-postmeta__arrow { transition: none; }
}

@media (max-width: 600px) {
	.wyohs-postmeta {
		--postmeta-label: 14px;
		--postmeta-value: 15px;
		--postmeta-gutter: 10px;
		margin-top: 36px;
	}
}

/* ---------- the card on a desktop --------------------------------------- */

@media (min-width: 993px) {

	/* Before post.js runs, and if it never does, the card still reads as part
	   of the article rather than sprawling across the full measure. */
	.wyohs-post__meta.fl-module {
		width: var(--postphoto-width);
		max-width: 40%;
		margin-left: auto;
	}

	/* Docked under the frame. The module it joins is itself absolutely
	   positioned and anchored by its BOTTOM edge, so the card has to be taken
	   out of the flow — otherwise its height would push the frame upwards and
	   undo the overlap. */
	.wyohs-post__photo .wyohs-postmeta.is-docked {
		position: absolute;
		top: calc(100% + var(--postmeta-gap));
		left: var(--postmeta-inset-left);
		width: calc(100% - var(--postmeta-inset-left) - var(--postmeta-inset-right));
		margin: 0;
	}

	/* Pinned to the window. left, width and top are written by post.js, which
	   measures where these rules put the card and then holds it there. */
	.wyohs-post__photo .wyohs-postmeta.is-docked.is-stuck {
		position: fixed;
		top: 0;
		left: 0;
		width: auto;
	}

	/* Beaver Builder paints the hero row's text itself, with two rules:

	     .fl-builder-content .fl-node-XXXX :not(input)…:not(.fl-menu-mobile-toggle)
	     .fl-builder-content .fl-node-XXXX a

	   Once the card is docked it is inside that row and gets both. Rather than
	   shout !important over them, these repeat the card's own colours at a
	   weight the row cannot reach. The first of BB's two is worth counting:
	   three classes and ten element names, because every :not() contributes
	   whatever is inside it. Four classes clears it; three would tie on classes
	   and then lose on the element count.

	   The other way out is to clear Text Color on the hero row itself (Row
	   Settings > Style > Text Color) and set white on the title, byline and
	   date modules instead. Tidier cascade, four more places to remember. */
	.fl-builder-content .wyohs-post__photo .wyohs-postmeta .wyohs-postmeta__label {
		color: var(--wyohs-ink, #1a1a1a);
	}

	.fl-builder-content .wyohs-post__photo .wyohs-postmeta .wyohs-postmeta__value,
	.fl-builder-content .wyohs-post__photo .wyohs-postmeta .wyohs-postmeta__link {
		color: var(--wyohs-navy, #1b3a5c);
	}

	.fl-builder-content .wyohs-post__photo .wyohs-postmeta .wyohs-postmeta__link:hover,
	.fl-builder-content .wyohs-post__photo .wyohs-postmeta .wyohs-postmeta__link:focus-visible {
		color: var(--wyohs-green, #4e9553);
	}
}

/* --------------------------------------------------------------------------
   Phone refinements — 28 Aug 2026
   The desktop arrangement (docked info card, floated in-article pictures) is
   built above. Below 993px there is one column, so the card belongs under the
   photograph rather than after the article, and a floated picture leaves a
   column of type too narrow to read.
   -------------------------------------------------------------------------- */

/* Info card rides up to just under the featured image. 992px matches the
   boundary post.js uses to dock the card on desktop. */
@media (max-width: 992px) {
  .fl-col:has(> .fl-col-content > .wyohs-post__content) > .fl-col-content {
    display: flex;
    flex-direction: column;
  }

  .wyohs-post__meta.fl-module {
    order: -1;
    margin-bottom: 28px;
  }
}

@media (max-width: 767px) {
  /* Title: 10% off the desktop 50px, and leading pulled in to match. */
  .fl-row:has(.wyohs-post__photo) h1.fl-heading {
    font-size: 45px;
    line-height: 1.08;
  }

  /* Byline stacks and reads from the left margin. The separator between the
     two lines has nothing left to separate, so it goes. */
  .fl-row:has(.wyohs-post__photo) .fl-module-box {
    flex-direction: column;
    align-items: flex-start;
    justify-content: flex-start;
    row-gap: 2px;
  }

  .fl-row:has(.wyohs-post__photo) .fl-module-box .fl-module-rich-text {
    display: none;
  }

  .fl-row:has(.wyohs-post__photo) .fl-module-box .fl-module,
  .fl-row:has(.wyohs-post__photo) .fl-module-box .fl-heading,
  .fl-row:has(.wyohs-post__photo) .fl-module-box .fl-post-info {
    text-align: left;
  }

  /* Every in-article picture takes the full measure. The editor's own
     alignment and pixel width are set for the desktop column and have to be
     overridden outright, hence the !important. */
  .wyohs-post__content .alignleft,
  .wyohs-post__content .alignright,
  .wyohs-post__content .aligncenter,
  .wyohs-post__content figure {
    float: none !important;
    width: 100% !important;
    max-width: 100% !important;
    margin-left: 0 !important;
    margin-right: 0 !important;
  }

  .wyohs-post__content figure img,
  .wyohs-post__content figure > a > img {
    width: 100% !important;
    height: auto !important;
  }
}
