/* Announcement bar — thin full-width strip above the header, centered
   uppercase link. A Block Style on core/group (see functions.php
   section 5b) rather than a hardcoded class — select "Announcement Bar"
   from any Group's Styles panel to reuse this look elsewhere. */
.is-style-announcement-bar {
	background-color: var(--wp--preset--color--heart-red);
	text-align: center;
	padding: 0.6rem 1rem;
}

.is-style-announcement-bar a {
	color: var(--wp--preset--color--white);
	text-decoration: none;
	font-size: var(--wp--preset--font-size--small);
	font-weight: 700;
	text-transform: uppercase;
	letter-spacing: 0.04em;
}

.is-style-announcement-bar a:hover {
	color: var(--wp--preset--color--washed-blue);
}

/* ---------- Sticky header: bar fixed, nav hides on scroll down ----------
   Two different behaviors on purpose, not one "sticky header" unit:
   the announcement bar (above) stays permanently pinned at the very top
   of the viewport regardless of scroll direction — genuinely fixed, not
   the conditional CSS position:sticky (which would behave identically
   here anyway, since this bar starts at the very top of the document
   with nothing above it to scroll past). The nav row below it
   (.rd-site-header — logo, links, bookmark icon, Log In/Sign Up) is
   ALSO fixed, but assets/js/sticky-header.js toggles
   .rd-site-header--hidden based on scroll direction: hidden scrolling
   down, shown scrolling up. Two independent behaviors sharing the top
   of the screen, not one combined sticky unit.

   Both custom properties below get a same-guess fallback (44px / 92px)
   for the instant of first paint before JS can measure the real
   heights — sticky-header.js corrects them immediately on load and on
   resize (announcement bar text can wrap to two lines on a narrow
   screen, changing its real height), so the fallback only has to be
   "close enough to avoid a visible jump," not exact.

   --rd-admin-bar-height exists ONLY to position the two fixed bars
   correctly while logged into wp-admin previewing the front end — see
   the body.admin-bar rule below for why body's own padding-top does
   NOT also include it. */
:root {
	--rd-announcement-height: 44px;
	--rd-header-height: 92px;
	--rd-admin-bar-height: 0px;
}

/* WordPress's own admin bar is fixed at top:0 with a very high z-index,
   and (per spec) an ancestor's margin — which is how core normally
   pushes normal page content below the admin bar — does NOT shift
   position:fixed elements, since fixed positioning resolves against
   the viewport, not the document flow. Without this, our fixed
   announcement bar would render partially hidden behind the real admin
   bar rather than stacking cleanly beneath it. Only relevant while
   logged in previewing the site; irrelevant to actual visitors, who
   never see an admin bar at all. */
body.admin-bar {
	--rd-admin-bar-height: 32px;
}

@media screen and (max-width: 782px) {
	body.admin-bar {
		--rd-admin-bar-height: 46px;
	}
}

.is-style-announcement-bar {
	position: fixed;
	top: var(--rd-admin-bar-height);
	left: 0;
	right: 0;
	z-index: 999;
}

.rd-site-header {
	position: fixed;
	top: calc(var(--rd-admin-bar-height) + var(--rd-announcement-height));
	left: 0;
	right: 0;
	z-index: 998;
	background-color: var(--wp--preset--color--white);
	box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
	transition: transform 0.3s ease;
}

.rd-site-header--hidden {
	transform: translateY(-100%);
}

/* While the mobile nav overlay is open, the header (and everything
   inside it, including the overlay dialog) needs to render above the
   announcement bar — otherwise .rd-site-header's own z-index (998, one
   below the announcement bar's 999) caps every descendant's stacking
   order too, since position:fixed + an explicit z-index makes an
   element a stacking context: no descendant's z-index, however high
   (including .rd-nav-overlay-extras's 999999 below), can lift it above
   where its ANCESTOR sits in the ancestor's own stacking context. That
   was the actual cause of the overlay's close button rendering partly
   behind the "Join the Recipe Club" bar — .rd-menu-open (added to this
   element by assets/js/nav-mobile.js, see that file for why it reads
   .wp-block-navigation__responsive-container's own is-menu-open class
   rather than anything on .wp-block-navigation itself) only needs to
   beat 999, not any of the arbitrarily high values used elsewhere in
   this file for different reasons. */
.rd-site-header.rd-menu-open {
	z-index: 1000;
}

/* Both bars leave normal document flow (position:fixed), so the actual
   page content needs to be pushed down by their combined height or it
   would render underneath them on load. This does NOT also add
   --rd-admin-bar-height: WordPress core already pushes body down for
   the real admin bar on its own (via a margin-top on <html> when
   logged in) — adding it again here would double that offset. */
body {
	padding-top: calc(var(--rd-announcement-height) + var(--rd-header-height));
}

/* Hero slider — a native Cover block with the optional "Rotating Images"
   field (see functions.php section 6b + assets/js/cover-slider*.js). Only
   the background image swaps; Cover's own heading/tag/button blocks
   inside it never re-render. */
.rd-cover-slider {
	position: relative;
	/* Clips the incoming slide (see cover-slider.js's slideIn()) to the
	   Cover's own bounds while it's translated off to one side — without
	   this, the image would visibly spill past the hero's edges for the
	   instant before it slides into place. */
	overflow: hidden;
}

/* Fallback for "Fixed background" Covers: cover-slider.js can't slide a
   background-image the way it slides the <img> (translating a
   background-position doesn't give the same "next photo enters, this
   one doesn't" look without a second layer), so that path gets this
   quick dip-and-recover instead — see slideIn()'s own comment in
   cover-slider.js for why the plain <img> path no longer uses it. An
   *animation*, not a *transition*, specifically so cover-slider.js can
   restart it on every swap (including two landing close together, e.g.
   rapid arrow clicks) by toggling the class off and back on — re-adding
   a class an element already has doesn't restart a running transition,
   but it does restart an animation once removal has actually reflowed. */
@keyframes rd-cover-slider-flash {
	0% { opacity: 1; }
	40% { opacity: 0.2; }
	100% { opacity: 1; }
}

.rd-cover-slider__flash {
	animation: rd-cover-slider-flash 0.3s ease;
}

/* Eyebrow Label — a Block Style on core/paragraph (see functions.php
   section 5b). Select "Eyebrow Label" from any Paragraph's Styles panel. */
.is-style-eyebrow {
	text-transform: uppercase;
	letter-spacing: 0.08em;
}

.rd-cover-slider__arrows {
	position: absolute;
	top: 1.5rem;
	right: 1.5rem;
	display: flex;
	gap: 0.5rem;
	z-index: 2;
}

.rd-cover-slider__arrow {
	width: 2.5rem;
	height: 2.5rem;
	border-radius: 999px;
	border: none;
	background-color: var(--wp--preset--color--white);
	color: var(--wp--preset--color--plant-green);
	cursor: pointer;
	font-size: 1rem;
	display: flex;
	align-items: center;
	justify-content: center;
}

.rd-cover-slider__arrow:hover {
	background-color: var(--wp--preset--color--carrot);
}

/* Recipe Card — a Block Style on core/group (see functions.php section
   5b). Flat cream cards, no border, soft shadow, generous corner radius
   (matches the rounder card style from the brand reference). Select
   "Recipe Card" from any Group's Styles panel. */
.is-style-recipe-card {
	border-radius: 14px;
	overflow: hidden;
	background: var(--wp--preset--color--cream);
	box-shadow: 0 1px 3px rgba(48, 66, 24, 0.08);
	transition: transform 0.15s ease, box-shadow 0.15s ease;
}

.is-style-recipe-card:hover {
	transform: translateY(-3px);
	box-shadow: 0 10px 24px rgba(48, 66, 24, 0.16);
}

.is-style-recipe-card .wp-block-post-featured-image {
	margin: 0;
}

.is-style-recipe-card .wp-block-post-featured-image img {
	aspect-ratio: 4 / 3;
	object-fit: cover;
}

.rd-recipe-card__body {
	padding: 1rem;
}

/* Section Heading Row — a Block Style on core/group (see functions.php
   section 5b). The heading + optional "See all" link row used at the
   top of every dashboard grid section. Select "Section Heading Row"
   from any Group's Styles panel. */
.is-style-section-heading {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	gap: 1rem;
	border-bottom: 2px solid var(--wp--preset--color--carrot);
	padding-bottom: 0.5rem;
	margin-bottom: 1.5rem;
}

/* Small colored-circle accent in front of dashboard section headings,
   echoing the icon-in-a-circle labels from the brand reference (e.g.
   "Food Access", "Health Access"). Purely decorative — a plain color
   dot rather than a real icon, since there's no icon set in the theme. */
.is-style-section-heading h2 {
	display: flex;
	align-items: center;
	gap: 0.65rem;
}

.is-style-section-heading h2::before {
	content: "";
	display: inline-block;
	width: 1.75rem;
	height: 1.75rem;
	border-radius: 999px;
	background-color: var(--wp--preset--color--fresh-green);
	flex-shrink: 0;
}

/* Recipe meta row (bound via block bindings to postmeta) */
.rd-recipe-meta {
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem 1.5rem;
	font-size: var(--wp--preset--font-size--small);
	color: var(--wp--preset--color--beet-red);
}

/* Editable per-recipe details (Servings/Prep/Cook/Difficulty/Badge) are
   now the Recipe Details block (blocks/recipe-details/) — see its own
   style.css for that box's styling. Replaces what used to be a hand-
   typed Paragraph + block-bindings row; block bindings' editable text
   didn't work cleanly for recipe_servings (an integer field), which is
   exactly what prompted the dedicated block. */

/* Label prefixes are pure CSS so the underlying bound value stays clean
   (no label text baked into meta or a formatting function's output).
   Prep's and Cook's own VALUES come pre-formatted from the
   recipe-dashboard/formatted-minutes binding source in functions.php
   (section 5) — "20 min" or "1 hr 30 min" as appropriate — rather than
   a raw number with a blindly-appended " min" here, which broke for
   any time an hour or longer. */
.rd-meta-prep::before { content: "Prep: "; color: var(--wp--preset--color--beet-red); font-weight: 400; }
.rd-meta-cook::before { content: "Cook: "; color: var(--wp--preset--color--beet-red); font-weight: 400; }

/* Infinite scroll — "All Recipes" archive (templates/archive-recipe.html,
   assets/js/infinite-scroll.js). The Query Pagination block still renders
   from core so a no-JS visitor gets working Prev/Next/numbered links;
   .rd-infinite-scroll-active is only added by the script once it has
   confirmed it can drive paging itself, so this rule never hides the
   fallback out from under someone who needs it. */
.rd-infinite-scroll-active .wp-block-query-pagination {
	display: none;
}

.rd-infinite-scroll__sentinel {
	height: 1px;
}

.rd-infinite-scroll__status {
	margin-top: 1.5rem;
	text-align: center;
	font-size: var(--wp--preset--font-size--small);
	color: var(--wp--preset--color--beet-red);
}

/* Category filter pills — "All Recipes" archive
   (templates/archive-recipe.html + patterns/recipe-category-filter.php).
   Plain <a> links, not buttons — filtering happens via a URL query
   string and a page load (pre_get_posts in functions.php, section 8b),
   not JS, so these need to be real, bookmarkable, crawlable links.
   Same active/hover color language as the servings multiplier
   (blocks/recipe-ingredients/style.css) and the bookmark toggle
   (frontend.css's .rd-bookmark__btn rules): heart-red fill means
   "this is the current selection" everywhere on the site, not a color
   specific to any one of these three components. */
.rd-category-filter {
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem;
	margin-top: 1.25rem;
}

.rd-category-filter__btn {
	display: inline-flex;
	align-items: center;
	font-size: var(--wp--preset--font-size--small);
	background: var(--wp--preset--color--white);
	color: var(--wp--preset--color--plant-green);
	border: 1px solid var(--wp--preset--color--beet-red);
	border-radius: 999px;
	padding: 0.35em 1em;
	text-decoration: none;
	transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease, box-shadow 0.15s ease;
}

.rd-category-filter__btn.is-active {
	background: var(--wp--preset--color--heart-red);
	border-color: var(--wp--preset--color--heart-red);
	color: var(--wp--preset--color--white);
}

/* Not the active filter, hovering: same heart-red fill + translucent-
   white lighten overlay the servings buttons and bookmark toggle both
   use — it previews what clicking turns it into, rather than a fourth
   unrelated hover color entering the palette. */
.rd-category-filter__btn:not(.is-active):hover {
	background: var(--wp--preset--color--heart-red);
	border-color: var(--wp--preset--color--heart-red);
	color: var(--wp--preset--color--white);
	box-shadow: inset 0 0 0 999px rgba(255, 255, 255, 0.18);
}

/* Already the active filter, hovering: darken slightly instead of
   lightening further — signals "this stays selected" rather than
   reading identically to the resting active state. */
.rd-category-filter__btn.is-active:hover {
	box-shadow: inset 0 0 0 999px rgba(0, 0, 0, 0.15);
}

/* Taxonomy pills on single-recipe.html — the three core/post-terms
   blocks (Category, Cuisine, Diet) next to the Keep Screen On toggle.
   These were plain underlined text links by default (core's own
   post-terms styling); every "className":"rd-term-pills" block below
   gets the exact same resting/hover treatment as
   .rd-category-filter__btn above, so a term here and the same term as
   an archive filter pill look identical — one pill language site-wide,
   not two similar-but-different ones. Unlike the filter pills, these
   are read-only tags rather than a togglable "current selection," so
   there's no .is-active state to skip — every pill here is always at
   rest until hovered.

   Each block's own "separator":"" attribute (set in
   templates/single-recipe.html) drops the default ", " text between
   multiple terms in the same taxonomy — flex-wrap + gap below spaces
   them out instead, the same way .rd-category-filter already does.
   A "prefix" string (e.g. "Cuisine: ") still renders as plain text
   ahead of the pills, not inside one — it's a label for the group, not
   part of any single term. */
.rd-term-pills {
	display: inline-flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 0.4rem;
}

.rd-term-pills a {
	display: inline-flex;
	align-items: center;
	font-size: var(--wp--preset--font-size--small);
	background: var(--wp--preset--color--white);
	color: var(--wp--preset--color--plant-green);
	border: 1px solid var(--wp--preset--color--beet-red);
	border-radius: 999px;
	padding: 0.35em 1em;
	text-decoration: none;
	transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease, box-shadow 0.15s ease;
}

.rd-term-pills a:hover {
	background: var(--wp--preset--color--heart-red);
	border-color: var(--wp--preset--color--heart-red);
	color: var(--wp--preset--color--white);
	box-shadow: inset 0 0 0 999px rgba(255, 255, 255, 0.18);
}

/* Footer — logo/blurb column plus link columns, ATK-style density */
.rd-footer-columns {
	gap: 2rem;
	align-items: flex-start;
}

.rd-footer-col {
	min-width: 8rem;
}

.rd-footer-col p {
	margin: 0 0 0.5rem;
}

/* Header: flat row — Site Logo, Navigation, Log In, Sign Up, in that order.
   Navigation grows to fill the middle so .rd-nav-auth (Log In/Sign Up,
   wrapped together as one group — see the mobile rules further down)
   lands flush right regardless of how many nav links there are. */
.wp-block-group.rd-nav-grid {
	display: flex;
	align-items: center;
	gap: 1.5rem;
}

.rd-nav-grid .wp-block-navigation {
	flex: 1 1 auto;
}

/* Wrapper around the bookmark icon + Log In/Sign Up (parts/header.html).
   It exists purely so the mobile overlay (see the "Mobile nav" rules
   further down) has a single element to reveal, instead of two separate
   sibling selectors — deliberately given NO layout attribute in the
   editor so its default behavior is a plain block-stacked column;
   that default is exactly what the mobile overlay wants, so this rule
   only needs to override it back to a row for the desktop header. */
.rd-nav-overlay-extras {
	display: flex;
	align-items: center;
	gap: 1.5rem;
}

/* .rd-nav-overlay-extras was deliberately given no layout attribute in
   the editor (see the comment above), which means it still carries
   core's default "flow" layout classes even though we override its
   display to flex here — and core's flow-layout CSS adds a top margin
   to any child after the first, for vertical rhythm in the stacked
   layout it assumes it's in. That margin doesn't go away just because
   we changed display: it still pushes the group down within a flex row,
   which is what was making Log In/Sign Up sit visibly lower than the
   rest of the header on desktop. Resetting margin on all direct
   children is a blanket fix for this and anything similar coming from
   the same source. */
.rd-nav-overlay-extras > * {
	margin: 0;
}

/* Log In / Sign Up, grouped. This is the desktop/header-row appearance
   only — see the "Mobile nav: hamburger right, Log In/Sign Up in the
   overlay" rules further down for the mobile version of this same
   group. */
.rd-nav-auth {
	display: flex;
	align-items: center;
	gap: 0.75rem;
	flex-shrink: 0;
}

/* Nav bookmark icon (parts/header.html, via
   patterns/nav-bookmark-link.php): reuses .rd-bookmark__btn's visual
   language as-is (outline circle, hover border/icon color shifts to
   heart-red — see blocks/recipe-bookmark/style.css) so it reads as the
   same "bookmark" affordance as the per-recipe toggle, just sized down
   slightly to sit comfortably next to the small Log In/Sign Up pills
   rather than the larger card-image context it's normally in. */
.rd-nav-bookmark {
	width: 2rem;
	height: 2rem;
	flex-shrink: 0;
}

/* Nav search icon (parts/header.html, core/search block with
   buttonPosition:"button-only" + isSearchFieldHidden:true — WP core's
   own "icon that expands to a field on click" behavior, no custom JS
   needed). Sits directly left of the bookmark icon, so it borrows the
   same circular-button shape and sizing as .rd-bookmark__btn for visual
   consistency, but in the nav's plant-green/spinach-green pairing
   instead of bookmark's beet-red/heart-red — search isn't a "saved"
   state, so it shouldn't read as one.

   .rd-nav-search itself is a normal flex item in .rd-nav-grid, sized to
   exactly the icon's footprint and never anything else — its width
   never changes. .wp-block-search__inside-wrapper is pulled out of
   flow (absolute, anchored to that fixed box's right edge, auto-width)
   so IT is what grows when the field opens. Without this, the input
   growing was changing the width of a normal flex item, which pushed
   every sibling after it (bookmark, Log In, Sign Up) to the right —
   reading as the whole cluster sliding from the center rather than the
   field opening in place. Right-anchored + no `left` means the box
   grows leftward, out over whatever's already there, while the icon's
   own position — pinned at that same right edge — never moves. */
.rd-nav-search.wp-block-search {
	position: relative;
	width: 2.25rem;
	height: 2.25rem;
	flex-shrink: 0;
}

.rd-nav-search .wp-block-search__inside-wrapper {
	position: absolute;
	top: 0;
	right: 0;
	max-width: none; /* core's own rule caps this at 100% of its containing block, which is now the fixed 2.25rem box above — override, or the field could never grow past the icon's own width */
	z-index: 20;
}

.rd-nav-search .wp-block-search__button {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 2.25rem;
	height: 2.25rem;
	min-width: 0;
	flex-shrink: 0;
	border-radius: 999px;
	border: 2px solid var(--wp--preset--color--plant-green);
	background: var(--wp--preset--color--white);
	color: var(--wp--preset--color--plant-green);
	padding: 0;
	margin: 0;
	transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease, border-radius 0.15s ease;
}

.rd-nav-search .wp-block-search__button svg {
	width: 1.1rem;
	height: 1.1rem;
	display: block;
}

.rd-nav-search .wp-block-search__button:hover {
	background: var(--wp--preset--color--spinach-green);
	border-color: var(--wp--preset--color--spinach-green);
	color: var(--wp--preset--color--white);
}

.rd-nav-search .wp-block-search__input {
	width: 16rem; /* explicit expanded width — core's own button-only sizing uses flex-basis:100% of the inside-wrapper, which is meaningless now that the wrapper is an auto-width absolutely-positioned box rather than a constrained flex child */
	max-width: calc(100vw - 2rem); /* safety net for narrow phones — without this the fixed 16rem (256px) field can overshoot the viewport or crowd the logo/hamburger on ~320-360px screens, since it grows leftward from a right-anchored box with no other constraint */
	height: 2.25rem;
	box-sizing: border-box;
	border: 2px solid var(--wp--preset--color--plant-green);
	border-radius: 999px 0 0 999px;
	padding: 0 1rem;
	font-size: var(--wp--preset--font-size--small);
	color: var(--wp--preset--color--plant-green);
	background: var(--wp--preset--color--white);
}

.rd-nav-search .wp-block-search__input:focus {
	outline: none;
	border-color: var(--wp--preset--color--spinach-green);
}

/* Resting (icon-only) state: core's own .wp-block-search__searchfield-
   hidden rules already shrink the input to zero width and force its
   left/right border-width to 0 (with !important, so ours can't touch
   those two sides) — this just also zeroes the top/bottom border and
   padding core doesn't cover, so nothing renders as a stray line or
   gap before the field is expanded. */
.rd-nav-search.wp-block-search__searchfield-hidden .wp-block-search__input {
	border-top: none;
	border-bottom: none;
	padding-top: 0;
	padding-bottom: 0;
}

/* Expanded state: real toggle class is wp-block-search__searchfield-
   hidden, present while collapsed and removed by core's own view
   script on click — NOT "wp-block-search__inline-input" (an earlier
   version of this rule targeted that class, which doesn't exist in WP
   core, so this styling silently never applied and the field rendered
   with browser defaults instead). Flattening the input's right edge
   and the button's left edge where they meet reads as one continuous
   pill growing out of the icon, rather than two separate controls with
   a gap between them. */
.rd-nav-search.wp-block-search__button-only:not(.wp-block-search__searchfield-hidden) .wp-block-search__button {
	border-radius: 0 999px 999px 0;
	border-left: none;
}

/* "Popular"-style badge on card images (bound to recipe_badge meta) */
.rd-card-media {
	position: relative;
}

.rd-badge {
	position: absolute;
	top: 0.75rem;
	left: 0.75rem;
	z-index: 1;
	margin: 0;
	background-color: var(--wp--preset--color--carrot);
	color: var(--wp--preset--color--plant-green);
	font-size: var(--wp--preset--font-size--small);
	font-weight: 700;
	text-transform: uppercase;
	letter-spacing: 0.03em;
	padding: 0.35em 0.85em;
	border-radius: 999px;
}

.rd-badge:empty {
	display: none;
}

/* Bookmark toggle on card images: opposite corner from the badge above,
   same absolute-positioning-within-.rd-card-media approach. z-index
   matches the badge's own (both float above the featured image, never
   above each other, since they never overlap). */
.rd-card-media .rd-bookmark {
	position: absolute;
	top: 0.75rem;
	right: 0.75rem;
	z-index: 1;
}

/* .rd-bookmark__btn — shared visual for every bookmark-icon element on
   the site: the interactive toggle inside the Recipe Bookmark block
   (blocks/recipe-bookmark/render.php), AND the header nav icon
   (patterns/nav-bookmark-link.php, a plain wp:html snippet reusing this
   same class). It lives HERE rather than in the block's own style.css
   on purpose: WordPress only auto-enqueues a block's style.css when
   that exact block type is actually present on the page, and the nav
   icon isn't that block — it's raw HTML that happens to reuse the
   class name. On any page (or template-part edit screen) where the
   real block doesn't also appear, that stylesheet would never load,
   and the nav icon would fall back to an unstyled inline <a> — no
   sizing, no flex-centering, the SVG left at its default inline
   baseline gap, which reads as "sitting too low" next to the rest of
   the nav row. frontend.css loads unconditionally site-wide (see
   rd_enqueue_assets() in functions.php), so putting the shared rules
   here guarantees both usages are always styled the same, everywhere. */
.rd-bookmark__btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 2.25rem;
	height: 2.25rem;
	border-radius: 999px;
	border: 1px solid var(--wp--preset--color--beet-red);
	background: var(--wp--preset--color--white);
	color: var(--wp--preset--color--beet-red);
	padding: 0;
	cursor: pointer;
	text-decoration: none;
	transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease, box-shadow 0.15s ease;
}

.rd-bookmark__btn svg {
	width: 1.1rem;
	height: 1.1rem;
	display: block;
	/* Optical centering, not geometric: the ribbon shape's visual mass
	   sits in its upper rectangle, tapering to a thin V at the bottom —
	   so a mathematically-centered bounding box reads as bottom-heavy
	   with empty space, even though the box itself is perfectly
	   centered in the button. A small upward nudge corrects for that
	   without needing to redraw the icon off-center in its own viewBox
	   (which would then need un-doing anywhere else this SVG is used
	   at a different size). */
	transform: translateY(-1px);
}

/* Bookmarked: same heart-red fill the servings multiplier's is-active
   pill uses — one "this is selected/saved" color across the theme
   rather than a bookmark-specific one. */
.rd-bookmark__btn.is-bookmarked {
	background: var(--wp--preset--color--heart-red);
	border-color: var(--wp--preset--color--heart-red);
	color: var(--wp--preset--color--white);
}

/* Not yet bookmarked, hovering: same heart-red + translucent-white
   lighten overlay as the servings buttons' hover state (see
   blocks/recipe-ingredients/style.css) — it previews what clicking
   will turn it into, using the color that state already owns, rather
   than a third unrelated hover color. */
.rd-bookmark__btn:not(.is-bookmarked):hover {
	background: var(--wp--preset--color--heart-red);
	border-color: var(--wp--preset--color--heart-red);
	color: var(--wp--preset--color--white);
	box-shadow: inset 0 0 0 999px rgba(255, 255, 255, 0.18);
}

/* Already bookmarked, hovering: darken slightly instead of lightening
   further — same overlay technique as .has-hover-darken above. Signals
   "a click here removes it" rather than looking identical to the
   resting bookmarked state. */
.rd-bookmark__btn.is-bookmarked:hover {
	box-shadow: inset 0 0 0 999px rgba(0, 0, 0, 0.15);
}

/* Two different anchor treatments, not one: the per-recipe logged-out
   link (single-recipe.html / a Recipe Card when you're signed out) is
   just a hint that this leads somewhere — border and icon tint to
   heart-red, no fill, since there's no bookmark state to preview. The
   nav icon (.rd-nav-bookmark, always this same <a>-not-<button> shape)
   gets excluded from that and instead falls through to the
   :not(.is-bookmarked):hover rule above — a full heart-red fill with a
   white icon, same as the toggle buttons elsewhere use for "this is
   what clicking turns it into." Without the :not(.rd-nav-bookmark)
   here, this rule's color: heart-red would win the cascade (equal
   specificity, declared later) over that rule's color: white, and the
   icon would blend invisibly into its own red background. */
.rd-bookmark__btn[href]:not(.rd-nav-bookmark):hover {
	border-color: var(--wp--preset--color--heart-red);
	color: var(--wp--preset--color--heart-red);
}

/* Spotlight — a Block Style on core/group (see functions.php section
   5b). One big recipe feature, image on one side, content on the other.
   Used via patterns/recipe-spotlight.php in a 1-item Query Loop. Select
   "Spotlight (media + content split)" from any Group's Styles panel. */
.is-style-spotlight {
	gap: 2.5rem;
	align-items: center;
}

.rd-spotlight__media,
.rd-spotlight__body {
	flex: 1 1 0;
	min-width: 0;
}

.rd-spotlight__media img {
	border-radius: 14px;
	aspect-ratio: 4 / 3;
	object-fit: cover;
	width: 100%;
}

/* Feature Card — a Block Style on core/group (see functions.php section
   5b). Bigger than the standard grid card, used for a small editorial
   selection (2–3 items). patterns/recipe-feature-card.php. Select
   "Feature Card" from any Group's Styles panel. */
.is-style-feature-card .wp-block-post-featured-image img {
	border-radius: 14px;
	aspect-ratio: 4 / 3;
	object-fit: cover;
}

.rd-feature-card__body {
	padding-top: 1rem;
}

.rd-feature-card__byline {
	color: var(--wp--preset--color--beet-red);
}

/* Category Tile Row — round image tiles linking to category archives.
   patterns/section-category-tiles.php */
.rd-category-tiles {
	gap: 1.5rem 1rem;
	margin-top: 1.5rem;
}

.rd-category-tile {
	width: 6.5rem;
	text-align: center;
}

.rd-category-tile__image {
	width: 6.5rem;
	height: 6.5rem;
	margin: 0 0 0.5rem;
	border-radius: 999px;
}

.rd-category-tile__image img {
	width: 6.5rem;
	height: 6.5rem;
	object-fit: cover;
}

/* ---------- Hover Animations ----------
   Set per-block via "Hover Animation" in the Styles tab (Button, Group,
   and Image; see assets/js/hover-animation-control.js). Exactly one
   .has-hover-* class is applied at a time — the control strips any
   previous one before adding the new one — so these never compete with
   each other. They DO stack with whatever Block Style is selected,
   which is the point, but also the thing to watch: .is-style-recipe-card
   and .is-style-feature-card already lift/shadow on hover on their own,
   so pairing those with Lift/Elevate doubles the effect.

   Every effect here uses one of three mechanisms, deliberately, so
   nothing needs retuning if the palette in theme.json ever changes:
     - pure geometry (transform, opacity, filter) — no color at all
     - currentColor — inherits whatever text color is in effect, so
       Underline and Ring adapt automatically. Deliberately NOT
       var(--wp--preset--color--*), which would couple these to
       specific palette slugs.
     - neutral black/white overlays — see the Darken/Brighten pair.

   Anything added here that moves must also be listed in the
   prefers-reduced-motion block at the end of this file. */

/* Geometry-only effects. Transitions are declared on the base class
   rather than the :hover state so they ease back out on mouseleave
   too, not just on the way in. */
.has-hover-lift {
	transition: transform 0.2s ease;
}

.has-hover-lift:hover {
	transform: translateY(-4px);
}

.has-hover-elevate {
	transition: transform 0.2s ease, box-shadow 0.2s ease;
}

.has-hover-elevate:hover {
	transform: translateY(-4px);
	box-shadow: 0 6px 16px rgba(48, 66, 24, 0.2);
}

/* Zoom scales the inner image, not the block, so the frame stays put
   and the picture grows inside it. overflow:hidden is set here because
   core/image's figure has it but a Group does not — without it the
   image would spill past its own box on hover. It's scoped to blocks
   that actually contain an image so it can't clip anything on a button.

   The :not(:has(img)) fallback scales the block itself when there's no
   image to scale — otherwise picking Zoom on a Button or a text-only
   Group would appear to do nothing at all, which reads as a broken
   control rather than an inapplicable one. */
.has-hover-zoom:has(img) {
	overflow: hidden;
}

.has-hover-zoom img {
	transition: transform 0.4s cubic-bezier(0.22, 1, 0.36, 1);
}

.has-hover-zoom:hover img {
	transform: scale(1.05);
}

.has-hover-zoom:not(:has(img)) {
	transition: transform 0.4s cubic-bezier(0.22, 1, 0.36, 1);
}

.has-hover-zoom:not(:has(img)):hover {
	transform: scale(1.05);
}

/* Fade and Darken are NOT the same effect, though they converge in one
   case. Fade is transparency: it lets the page background through, and
   it takes the element's text and child content down with it. Darken
   is an opaque overlay painted between the element's background and
   its content, so it only ever darkens and leaves text at full
   strength. Fade earns its place on images and media, where there's no
   text to weaken; Darken is the one to reach for on buttons and cards,
   where legible text matters. */
.has-hover-fade {
	transition: opacity 0.2s ease;
}

.has-hover-fade:hover {
	opacity: 0.75;
}

/* Starts desaturated and returns to full color on hover. */
.has-hover-desaturate {
	filter: grayscale(1);
	transition: filter 0.3s ease;
}

.has-hover-desaturate:hover {
	filter: grayscale(0);
}

/* currentColor effects — these are the two that need a color, and both
   inherit it rather than declaring one.

   Both also have to be applied to the element that actually carries the
   visible box, which is NOT always the element the class lands on.
   className support puts the class on core/button's outer
   .wp-block-button wrapper and on core/image's <figure>, but the border
   radius, background, and visual bounds live on the inner
   .wp-block-button__link and <img>. Drawing on the wrapper gives a
   square ring around a pill button, and an underline positioned against
   the wrapper's box rather than the image's. So both effects retarget
   to the inner element for those two block types. Group needs no
   special case — the class lands directly on the styled box. */
/* The `:not(.block-editor-block-list__block)` guard is load-bearing, not
   defensive tidying. In the editor, a block's wrapper carries BOTH its
   `wp-block-*` class and `block-editor-block-list__block`, and core
   draws the selected-block outline with an `::after` on that same
   element. Without this guard our rule lands on the identical
   pseudo-element and reshapes core's selection outline into a 2px bar —
   core's own `top` positioning beats our `bottom: 0`, so it surfaces as
   a stray admin-blue line above the block. The class never exists on
   the front end, so the underline itself is unaffected there. */
.has-hover-underline {
	position: relative;
}

.has-hover-underline:not(.block-editor-block-list__block)::after {
	content: "";
	position: absolute;
	left: 0;
	bottom: 0;
	width: 100%;
	height: 2px;
	background: currentColor;
	transform: scaleX(0);
	transform-origin: left center;
	transition: transform 0.25s ease;
}

.has-hover-underline:not(.block-editor-block-list__block):hover::after {
	transform: scaleX(1);
}

/* Button: move the pseudo-element off the wrapper and onto the link.
   The wrapper's own pseudo is switched off so the two don't stack. */
.wp-block-button.has-hover-underline:not(.block-editor-block-list__block)::after {
	content: none;
}

.wp-block-button.has-hover-underline .wp-block-button__link {
	position: relative;
}

.wp-block-button.has-hover-underline .wp-block-button__link::after {
	content: "";
	position: absolute;
	left: 0;
	bottom: 0;
	width: 100%;
	height: 2px;
	background: currentColor;
	transform: scaleX(0);
	transform-origin: left center;
	transition: transform 0.25s ease;
}

.wp-block-button.has-hover-underline:hover .wp-block-button__link::after {
	transform: scaleX(1);
}

/* Image: an <img> is a replaced element and can't carry a pseudo-
   element, so the underline stays on the <figure> — but the figure is
   taller than the image by the inline descender gap under it, which is
   what pushes the line away from the image's actual edge. Making the
   image a block removes that gap so bottom:0 lands on the image. */
.wp-block-image.has-hover-underline img {
	display: block;
}

.has-hover-ring {
	transition: outline-color 0.2s ease;
	outline: 2px solid transparent;
	outline-offset: 3px;
}

.has-hover-ring:hover {
	outline-color: currentColor;
}

/* Button and Image: retarget the ring to the inner element so it picks
   up that element's border-radius. The wrapper's own ring is switched
   off to avoid drawing two. */
.wp-block-button.has-hover-ring,
.wp-block-image.has-hover-ring {
	outline: none;
}

.wp-block-button.has-hover-ring .wp-block-button__link,
.wp-block-image.has-hover-ring img {
	transition: outline-color 0.2s ease;
	outline: 2px solid transparent;
	outline-offset: 3px;
}

.wp-block-button.has-hover-ring:hover .wp-block-button__link,
.wp-block-image.has-hover-ring:hover img {
	outline-color: currentColor;
}

/* Darken / Brighten — a deliberate pair rather than one "adaptive"
   effect. A semi-transparent black overlay reads as a darken on a
   light or mid-tone surface but is nearly invisible on a near-black
   one, and the reverse is true of the white overlay — both are offered
   since which reads depends on what background the block ends up on.

   box-shadow is used instead of changing background-color because core
   ships preset background-color classes with !important, which a
   background-color hover rule would have to fight color by color.
   box-shadow isn't touched by that rule, and it clips cleanly to the
   element's own border-radius with no extra rules.

   Button needs the nested variant, same as Ring and Underline above:
   className support puts the class on the outer .wp-block-button
   wrapper, but the fill lives on the inner __link, which is also the
   only one of the two with a border-radius. The wrapper's own rule is
   switched off (:not(.wp-block-button)) so it can't paint a square
   overlay behind the pill — without that exclusion both the wrapper
   and the inner link would draw the effect at once, showing up as a
   square frame around a rounded button. Group and Image need no
   special case.

   The literal black and white here are deliberate and must NOT be
   swapped for palette vars: they are neutral overlays, not colors. */
.has-hover-darken:not(.wp-block-button):hover,
.wp-block-button.has-hover-darken:hover .wp-block-button__link {
	box-shadow: inset 0 0 0 999px rgba(0, 0, 0, 0.15);
}

.has-hover-brighten:not(.wp-block-button):hover,
.wp-block-button.has-hover-brighten:hover .wp-block-button__link {
	box-shadow: inset 0 0 0 999px rgba(255, 255, 255, 0.18);
}

/* ---------- Hover Color swap ----------
   Set via the "Hover Color" swatch picker in the Styles tab (Button and
   Group; see assets/js/hover-animation-control.js). Independent of
   Hover Animation above — a block can carry a has-hover-lift AND a
   has-hover-swap-* class at once, motion and color being separate
   choices. Unlike the animations, this can't stay palette-agnostic: a
   real color swap has to name a specific theme.json slug, so there's
   one rule pair per palette color rather than one generic rule.

   Each pair follows the same wrapper/inner split as Ring and
   Darken/Brighten above: Group gets the rule directly, Button retargets
   to .wp-block-button__link (where the fill actually lives) with the
   wrapper's own version excluded via :not(.wp-block-button) so it can't
   double up the same way the Darken bug did.

   var(--wp--preset--color--*) rather than a literal hex, so retuning a
   color in theme.json updates the hover state too, same as everywhere
   else in this theme. Core's has-*-background-color classes ship
   !important, so beating them on :hover needs !important as well —
   there's no specificity trick around that.

   Add a color to theme.json's palette → add its pair here, using the
   same slug. Nothing on the JS side needs to change; the picker reads
   the palette directly. */
.has-hover-swap-white:not(.wp-block-button):hover,
.wp-block-button.has-hover-swap-white .wp-block-button__link:hover {
	background-color: var(--wp--preset--color--white) !important;
}

.has-hover-swap-cream:not(.wp-block-button):hover,
.wp-block-button.has-hover-swap-cream .wp-block-button__link:hover {
	background-color: var(--wp--preset--color--cream) !important;
}

.has-hover-swap-plant-green:not(.wp-block-button):hover,
.wp-block-button.has-hover-swap-plant-green .wp-block-button__link:hover {
	background-color: var(--wp--preset--color--plant-green) !important;
}

.has-hover-swap-spinach-green:not(.wp-block-button):hover,
.wp-block-button.has-hover-swap-spinach-green .wp-block-button__link:hover {
	background-color: var(--wp--preset--color--spinach-green) !important;
}

.has-hover-swap-fresh-green:not(.wp-block-button):hover,
.wp-block-button.has-hover-swap-fresh-green .wp-block-button__link:hover {
	background-color: var(--wp--preset--color--fresh-green) !important;
}

.has-hover-swap-beet-red:not(.wp-block-button):hover,
.wp-block-button.has-hover-swap-beet-red .wp-block-button__link:hover {
	background-color: var(--wp--preset--color--beet-red) !important;
}

.has-hover-swap-heart-red:not(.wp-block-button):hover,
.wp-block-button.has-hover-swap-heart-red .wp-block-button__link:hover {
	background-color: var(--wp--preset--color--heart-red) !important;
}

.has-hover-swap-carrot:not(.wp-block-button):hover,
.wp-block-button.has-hover-swap-carrot .wp-block-button__link:hover {
	background-color: var(--wp--preset--color--carrot) !important;
}

.has-hover-swap-cool-blue:not(.wp-block-button):hover,
.wp-block-button.has-hover-swap-cool-blue .wp-block-button__link:hover {
	background-color: var(--wp--preset--color--cool-blue) !important;
}

.has-hover-swap-sky-blue:not(.wp-block-button):hover,
.wp-block-button.has-hover-swap-sky-blue .wp-block-button__link:hover {
	background-color: var(--wp--preset--color--sky-blue) !important;
}

.has-hover-swap-washed-blue:not(.wp-block-button):hover,
.wp-block-button.has-hover-swap-washed-blue .wp-block-button__link:hover {
	background-color: var(--wp--preset--color--washed-blue) !important;
}

@media (prefers-reduced-motion: reduce) {
	*,
	*::before,
	*::after {
		transition-duration: 0.01ms !important;
		animation-duration: 0.01ms !important;
	}

	.is-style-recipe-card:hover,
	.has-hover-lift:hover,
	.has-hover-elevate:hover,
	.has-hover-zoom:hover img,
	.has-hover-zoom:not(:has(img)):hover,
	.has-hover-underline:hover::after,
	.wp-block-button.has-hover-underline:hover .wp-block-button__link::after {
		transform: none;
	}

	/* Underline would otherwise be stuck at scaleX(0) — i.e. invisible —
	   once the transform above is nulled, silently removing the hover
	   affordance rather than just removing its motion. Reveal it whole
	   instead, no wipe. */
	.has-hover-underline:hover::after {
		transform: scaleX(1);
	}

	.wp-block-button.has-hover-underline:hover .wp-block-button__link::after {
		transform: scaleX(1);
	}
}

/* ---------- Button style variations (registered in functions.php) ----------
   Arrows are drawn with a masked SVG (stroke-width 2.5) rather than a
   Unicode glyph, so their thickness is explicit and consistent and
   doesn't depend on how a given font renders "→". mask-image +
   background: currentColor lets the icon inherit the button's text
   color automatically, including on hover. */
.wp-block-button.is-style-outline-left-arrow .wp-block-button__link,
.wp-block-button.is-style-outline-right-arrow .wp-block-button__link,
.wp-block-button.is-style-outline-down-arrow .wp-block-button__link {
	background-color: transparent;
	border: 2px solid currentColor;
	color: inherit;
}

.wp-block-button.is-style-fill-left-arrow .wp-block-button__link,
.wp-block-button.is-style-outline-left-arrow .wp-block-button__link,
.wp-block-button.is-style-fill-right-arrow .wp-block-button__link,
.wp-block-button.is-style-outline-right-arrow .wp-block-button__link,
.wp-block-button.is-style-fill-down-arrow .wp-block-button__link,
.wp-block-button.is-style-outline-down-arrow .wp-block-button__link {
	display: inline-flex;
	align-items: center;
	gap: 0.55em;
	transition: transform 0.15s ease;
}

.wp-block-button.is-style-fill-left-arrow .wp-block-button__link::before,
.wp-block-button.is-style-outline-left-arrow .wp-block-button__link::before,
.wp-block-button.is-style-fill-right-arrow .wp-block-button__link::after,
.wp-block-button.is-style-outline-right-arrow .wp-block-button__link::after,
.wp-block-button.is-style-fill-down-arrow .wp-block-button__link::after,
.wp-block-button.is-style-outline-down-arrow .wp-block-button__link::after {
	content: "";
	display: inline-block;
	width: 1em;
	height: 1em;
	flex-shrink: 0;
	background-color: currentColor;
	mask-repeat: no-repeat;
	mask-position: center;
	mask-size: contain;
	-webkit-mask-repeat: no-repeat;
	-webkit-mask-position: center;
	-webkit-mask-size: contain;
}

.wp-block-button.is-style-fill-left-arrow .wp-block-button__link::before,
.wp-block-button.is-style-outline-left-arrow .wp-block-button__link::before {
	mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='20' y1='12' x2='4' y2='12'/%3E%3Cpolyline points='11 5 4 12 11 19'/%3E%3C/svg%3E");
	-webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='20' y1='12' x2='4' y2='12'/%3E%3Cpolyline points='11 5 4 12 11 19'/%3E%3C/svg%3E");
}

.wp-block-button.is-style-fill-right-arrow .wp-block-button__link::after,
.wp-block-button.is-style-outline-right-arrow .wp-block-button__link::after {
	mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='4' y1='12' x2='20' y2='12'/%3E%3Cpolyline points='13 5 20 12 13 19'/%3E%3C/svg%3E");
	-webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='4' y1='12' x2='20' y2='12'/%3E%3Cpolyline points='13 5 20 12 13 19'/%3E%3C/svg%3E");
}

.wp-block-button.is-style-fill-down-arrow .wp-block-button__link::after,
.wp-block-button.is-style-outline-down-arrow .wp-block-button__link::after {
	mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='12' y1='4' x2='12' y2='20'/%3E%3Cpolyline points='5 13 12 20 19 13'/%3E%3C/svg%3E");
	-webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='12' y1='4' x2='12' y2='20'/%3E%3Cpolyline points='5 13 12 20 19 13'/%3E%3C/svg%3E");
}

/* Directional hover nudge: arrow-styled buttons drift a few px toward
   whichever way their arrow points, reinforcing the icon rather than
   just changing color. Kept small (4px) so it reads as a nudge. */
.wp-block-button.is-style-fill-left-arrow .wp-block-button__link:hover,
.wp-block-button.is-style-outline-left-arrow .wp-block-button__link:hover {
	transform: translateX(-4px);
}

.wp-block-button.is-style-fill-right-arrow .wp-block-button__link:hover,
.wp-block-button.is-style-outline-right-arrow .wp-block-button__link:hover {
	transform: translateX(4px);
}

.wp-block-button.is-style-fill-down-arrow .wp-block-button__link:hover,
.wp-block-button.is-style-outline-down-arrow .wp-block-button__link:hover {
	transform: translateY(4px);
}

/* Pill CTA: a solid circle badge with an arrow, riding the button's
   trailing edge — slides further right on hover. Deliberately a plain
   glyph, not a masked SVG like the arrow-direction styles above: this
   badge needs its own circular background showing behind the arrow,
   and a mask clips an element down to the icon's own outline, so
   background-color and border-radius on a masked element never
   actually render as a circle — two different techniques for two
   different visual results. */
.wp-block-button.is-style-pill-cta .wp-block-button__link {
	position: relative;
	padding-right: 3.4rem;
}

.wp-block-button.is-style-pill-cta .wp-block-button__link::after {
	content: "\2192";
	position: absolute;
	right: 0.4rem;
	top: 50%;
	transform: translateY(-50%);
	width: 2rem;
	height: 2rem;
	border-radius: 999px;
	background-color: var(--wp--preset--color--carrot);
	color: var(--wp--preset--color--plant-green);
	display: flex;
	align-items: center;
	justify-content: center;
	font-size: 1rem;
	line-height: 1;
	transition: transform 0.25s ease;
}

.wp-block-button.is-style-pill-cta .wp-block-button__link:hover::after {
	transform: translateY(-50%) translateX(4px);
}

/* ---------- Recipe content styles (registered in functions.php) ----------
   For use inside a recipe's own post body — intro tips, a "why this
   works" checklist, section dividers between steps and notes. */

/* Pull Quote — a "chef's tip" or standout line pulled from the recipe's
   intro. Quote mark in heart-red to match the site's link/accent color;
   attribution in the same muted beet-red used for meta text elsewhere. */
.is-style-pull-quote {
	border: none;
	margin: 2.5rem 0;
	padding: 0;
}

.is-style-pull-quote::before {
	content: "\201C";
	display: block;
	font-size: 3.5rem;
	line-height: 1;
	font-weight: 800;
	color: var(--wp--preset--color--heart-red);
	margin-bottom: 0.25rem;
}

.is-style-pull-quote p {
	font-size: clamp(1.375rem, 2.75vw, 2rem);
	font-weight: 700;
	line-height: 1.35;
	letter-spacing: -0.01em;
	margin: 0;
}

.is-style-pull-quote cite {
	display: block;
	margin-top: 1.25rem;
	font-size: 0.9375rem;
	font-style: normal;
	font-weight: 600;
	color: var(--wp--preset--color--beet-red);
}

/* Checklist — replaces the default bullet with a small circular check
   badge in spinach-green, matching the button/accent color used
   elsewhere for "done"/positive actions. Good for a recipe's "why this
   works" list or a prep checklist. */
.is-style-checklist {
	list-style: none;
	margin-left: 0;
	padding-left: 0;
}

.is-style-checklist li {
	position: relative;
	padding-left: 1.85rem;
}

.is-style-checklist li:not(:last-child) {
	margin-bottom: 0.65rem;
}

.is-style-checklist li::before {
	content: "";
	position: absolute;
	left: 0;
	top: 0.2em;
	width: 1.15rem;
	height: 1.15rem;
	border-radius: 50%;
	background-color: var(--wp--preset--color--spinach-green);
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3.5 8.5l3 3 6-7'/%3E%3C/svg%3E");
	background-repeat: no-repeat;
	background-position: center;
	background-size: 0.65rem;
}

/* Nested checklists indent from the parent item's badge, not the margin */
.is-style-checklist li .is-style-checklist,
.is-style-checklist li ul {
	margin-top: 0.65rem;
}

/* Accent Underline — a short carrot-colored bar beneath heading text,
   matching the same carrot underline already used on Section Heading
   Row. Shrinks to content width via inline-block so the bar sits under
   the text itself. Not intended for wide/full-aligned headings. */
.is-style-accent-underline {
	position: relative;
	display: inline-block;
	padding-bottom: 0.9rem;
}

.is-style-accent-underline::after {
	content: "";
	position: absolute;
	left: 0;
	bottom: 0;
	width: 3rem;
	height: 4px;
	border-radius: 2px;
	background: var(--wp--preset--color--carrot);
}

/* Centered headings: the bar should center under the text too. */
.has-text-align-center.is-style-accent-underline::after {
	left: 50%;
	transform: translateX(-50%);
}

/* Dot Divider — core already ships its own gray "Dots" style
   (.is-style-dots); this is a separate, beet-red-colored variation
   matching this theme's default separator color. */
.is-style-dot-divider {
	border: none;
	height: 1em;
	background: none;
	display: flex;
	align-items: center;
	justify-content: center;
}

.is-style-dot-divider::before {
	content: "\2022 \2022 \2022";
	color: var(--wp--preset--color--beet-red);
	font-size: 1.125rem;
	line-height: 1;
	letter-spacing: 0.6em;
	/* Optical re-centering: trailing letter-spacing adds a gap after the
	   last dot that isn't mirrored before the first, so nudge right. */
	margin-left: 0.6em;
}

/* Horizontal Scroll — a Gallery style for a recipe's process photos:
   fixed-width cards in a snap-scrolling row instead of a squeezed grid.
   Good for step-by-step cooking shots. */
.wp-block-gallery.is-style-horizontal-scroll {
	display: flex;
	flex-wrap: nowrap;
	overflow-x: auto;
	overflow-y: hidden;
	scroll-snap-type: x mandatory;
	-webkit-overflow-scrolling: touch;
	padding-left: calc(50% - 190px) !important;
	padding-right: calc(50% - 190px) !important;
	scroll-padding-left: calc(50% - 190px);
	scroll-padding-right: calc(50% - 190px);
}

.wp-block-gallery.is-style-horizontal-scroll .wp-block-image {
	flex: 0 0 auto !important;
	flex-basis: clamp(220px, 32vw, 380px) !important;
	width: clamp(220px, 32vw, 380px) !important;
	margin: 0;
	scroll-snap-align: center;
	aspect-ratio: 4 / 3;
	border-radius: 8px;
	overflow: hidden;
}

.wp-block-gallery.is-style-horizontal-scroll .wp-block-image img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	display: block;
}

@media (max-width: 600px) {
	.wp-block-gallery.is-style-horizontal-scroll {
		padding-left: calc(50% - 130px) !important;
		padding-right: calc(50% - 130px) !important;
		scroll-padding-left: calc(50% - 130px);
		scroll-padding-right: calc(50% - 130px);
	}

	.wp-block-gallery.is-style-horizontal-scroll .wp-block-image {
		flex-basis: clamp(200px, 70vw, 260px) !important;
		width: clamp(200px, 70vw, 260px) !important;
	}
}

/* ---------- Recipe Step pattern (patterns/recipe-step.php) ----------
   A numbered step for recipe instructions — number badge, title, short
   description, optional image. Meant to be duplicated once per step
   directly in a recipe's Post Content. */
.rd-recipe-step {
	display: flex;
	gap: 1.25rem;
	align-items: flex-start;
}

.rd-recipe-step__number {
	flex-shrink: 0;
	width: 2.5rem;
	height: 2.5rem;
	border-radius: 999px;
	background-color: var(--wp--preset--color--spinach-green);
	color: var(--wp--preset--color--white);
	display: flex;
	align-items: center;
	justify-content: center;
	font-weight: 700;
	font-size: var(--wp--preset--font-size--medium);
}

.rd-recipe-step__body {
	flex: 1 1 auto;
	min-width: 0;
}

.rd-recipe-step__body img {
	border-radius: 10px;
	margin-top: 0.75rem;
}

/* ---------- Lightbox (Image + Gallery blocks) ----------
   A native <dialog> reused across every image on the page — see
   assets/js/lightbox.js. Nav buttons are position:fixed to the viewport
   rather than the dialog, since the dialog only wraps tightly around
   the image itself and the buttons should stay pinned to the screen
   edges regardless of image size. */
dialog.rd-lightbox {
	border: none;
	padding: 0;
	background: transparent;
	max-width: 92vw;
	max-height: 92vh;
}

dialog.rd-lightbox::backdrop {
	background: rgba(0, 0, 0, 0.92);
}

dialog.rd-lightbox[open] {
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: 0.85rem;
}

.rd-lightbox-img {
	max-width: 92vw;
	max-height: 88vh;
	object-fit: contain;
	display: block;
	border-radius: 4px;
}

.rd-lightbox-counter {
	font-size: 0.875rem;
	font-weight: 600;
	letter-spacing: 0.03em;
	color: rgba(255, 255, 255, 0.75);
}

.rd-lightbox-counter[hidden] {
	display: none;
}

/* On desktop this wrapper is invisible to layout — prev/next escape it
   via position: fixed below. Its real flex-row layout only activates
   under the mobile breakpoint further down, where prev/next also drop
   their fixed positioning to join it. */
.rd-lightbox-controls {
	display: contents;
}

.rd-lightbox-close,
.rd-lightbox-prev,
.rd-lightbox-next {
	position: fixed;
	border: none;
	background: rgba(255, 255, 255, 0.12);
	color: var(--wp--preset--color--white);
	width: 44px;
	height: 44px;
	border-radius: 50%;
	display: flex;
	align-items: center;
	justify-content: center;
	font-size: 1.5rem;
	line-height: 1;
	cursor: pointer;
	transition: background-color 0.2s ease;
}

.rd-lightbox-close:hover,
.rd-lightbox-prev:hover,
.rd-lightbox-next:hover {
	background: rgba(255, 255, 255, 0.24);
}

/* The ×/‹/› glyphs sit low within their own line box in most fonts — a
   font-metrics quirk, not a flex-centering issue — so nudging is done
   on this inner span rather than the button. */
.rd-lightbox-icon {
	display: inline-block;
	transform: translateY(-2px);
}

.rd-lightbox-close {
	top: 1.25rem;
	right: 1.25rem;
}

.rd-lightbox-prev {
	left: 1.25rem;
	top: 50%;
	transform: translateY(-50%);
}

.rd-lightbox-next {
	right: 1.25rem;
	top: 50%;
	transform: translateY(-50%);
}

.rd-lightbox-prev[hidden],
.rd-lightbox-next[hidden] {
	display: none;
}

/* Mobile: arrows move below the image instead of overlaying it. */
@media (max-width: 600px) {
	.rd-lightbox-prev,
	.rd-lightbox-next {
		position: static;
		transform: none;
	}

	.rd-lightbox-controls {
		display: flex;
		align-items: center;
		justify-content: center;
		gap: 1.5rem;
	}
}

/* -----------------------------------------------------------------------
 * Responsive fixes
 *
 * Most responsiveness comes for free: theme.json's fluid font sizes,
 * WordPress's own constrained/wide layout system, core Navigation's
 * built-in mobile overlay menu (explicitly set in header.html/footer.html
 * rather than relied on as a default), and Media & Text's own
 * is-stacked-on-mobile behavior on the promo band. This section covers
 * the custom flex/grid layouts built specifically for this theme, which
 * don't get any of that automatically.
 * -------------------------------------------------------------------- */

/* Mobile nav: hamburger left, logo centered, search right — a true
   3-column grid rather than flex order tricks, specifically so the
   logo centers on the actual row midpoint regardless of the hamburger
   and search icon having slightly different widths. A flex row with
   space-between/auto-margins can only center something if the items on
   both sides are equal width; grid-template-columns: 1fr auto 1fr
   sidesteps that — the two outer 1fr tracks always stay equal to each
   other (whatever's left after the middle column's content width is
   subtracted), so the middle column is always the row's true center,
   independent of how wide column 1 vs column 3 happen to be.

   Bookmark + Log In/Sign Up (.rd-nav-overlay-extras, see parts/header.html
   and the desktop rule earlier in this file) don't get a 4th/5th grid
   column — three icons is already the full ask for the collapsed row.
   They move into the open overlay instead, shown via
   .wp-block-navigation.is-menu-open, the one class this theme already
   depends on elsewhere (sticky-header.js's "don't hide the header while
   the overlay is open" check relies on the same class, so it's proven
   reliable in this codebase rather than assumed). A general sibling
   selector (~) reaches .rd-nav-overlay-extras because it's a later
   sibling of .wp-block-navigation under the same .rd-nav-grid parent;
   no DOM move needed. Positioned fixed and layered above the overlay
   (rather than requiring it to be a literal descendant of core's
   dialog) so it reads as part of the open menu without depending on
   core's internal structure at all. The !important is needed because
   the desktop .rd-nav-overlay-extras rule above it in this file would
   otherwise win on source order for the `display` property. */
@media (max-width: 599px) {
	/* !important needed on `display` here for the same reason documented
	   on .rd-nav-auth below: .rd-nav-grid was given layout:"flex" in the
	   editor (parts/header.html), so core's own layout support generates
	   a same-specificity-beating stacked selector (something like
	   .wp-block-group.rd-nav-grid.is-layout-flex) that would otherwise
	   keep it a flex row here. */
	.rd-nav-grid {
		display: grid !important;
		grid-template-columns: 1fr auto 1fr;
		align-items: center;
		column-gap: 0.75rem;
	}

	.rd-nav-grid .wp-block-navigation {
		grid-column: 1;
		justify-self: start;
	}

	.rd-nav-grid .wp-block-site-logo {
		grid-column: 2;
		justify-self: center;
	}

	.rd-nav-grid .rd-nav-search {
		grid-column: 3;
		justify-self: end;
	}

	/* iOS Safari zooms the whole viewport in when an input is focused if
	   its computed font-size is under 16px — the field's resting/desktop
	   size (the "small" preset, 0.875rem ≈ 14px) triggers it. This is
	   set unconditionally here (not only inside the .rd-search-open rules
	   further down) so it's already in effect the moment the field is
	   focused, rather than depending on assets/js/nav-mobile.js's
	   MutationObserver having already applied .rd-search-open by then. */
	.rd-nav-search .wp-block-search__input {
		font-size: 16px;
	}

	.rd-nav-overlay-extras {
		display: none;
	}

	/* .rd-menu-open is written onto .rd-site-header by
	   assets/js/nav-mobile.js, which derives it from is-menu-open on
	   .wp-block-navigation__responsive-container — the element
	   Gutenberg's own source actually applies that class to, confirmed
	   after two earlier, incorrect assumptions here (see that file's
	   header comment). It's applied to .rd-site-header specifically
	   (rather than .rd-nav-grid) so the z-index rule earlier in this
	   file can also reach it — .rd-nav-overlay-extras being reachable
	   via a plain descendant selector, rather than the old general-
	   sibling-off-.wp-block-navigation approach, is a side benefit: it
	   no longer has to be a particular sibling of the nav, just
	   somewhere inside .rd-site-header. */
	.rd-site-header.rd-menu-open .rd-nav-overlay-extras {
		display: flex !important;
		flex-direction: column;
		align-items: stretch;
		gap: 0.75rem;
		position: fixed;
		left: 0;
		right: 0;
		bottom: 0;
		padding: 1.25rem 1.5rem calc(1.25rem + env(safe-area-inset-bottom, 0px));
		background-color: var(--wp--preset--color--white);
		border-top: 1px solid rgba(0, 0, 0, 0.08);
		z-index: 999999; /* deliberately far above any reasonable z-index of core's own overlay dialog, which this is meant to visually sit on top of */
	}

	/* The original bookmark link stays hidden in the collapsed row — see
	   .rd-nav-overlay-extras above — but ALSO needs hiding here
	   specifically once the footer becomes visible below, since
	   assets/js/nav-mobile.js leaves it in place in the DOM (only a
	   clone moves into the overlay dialog). Without this it would
	   reappear a second time, floating loose above the Log In/Sign Up
	   buttons, once .rd-nav-overlay-extras switches to display:flex. */
	.rd-site-header.rd-menu-open .rd-nav-overlay-extras .rd-nav-bookmark {
		display: none;
	}

	/* The overlay's own bookmark icon: a clone inserted by
	   assets/js/nav-mobile.js as a literal sibling of the close button
	   inside .wp-block-navigation__responsive-dialog, sitting directly
	   to its left — not mirrored to the opposite corner, which an
	   earlier version of this rule did on a misreading of "left of the
	   close icon" as "opposite side of the screen." Being a real DOM
	   sibling means both buttons resolve position:absolute against the
	   exact same parent, so plain values here are guaranteed correct
	   with no measurement involved: top:1.5rem matches the close
	   button's own top:1.5rem exactly (elsewhere in this file), and
	   right is calculated from the close button's own known box — its
	   right:1.5rem inset plus its own 2.5rem width plus a 0.75rem gap —
	   rather than measured, since those three numbers are already fixed
	   values elsewhere in this stylesheet, not something that varies at
	   runtime. No z-index needed either, since it shares the dialog's
	   own stacking context instead of needing to reach it from outside. */
	.rd-nav-bookmark--overlay {
		position: absolute;
		top: 1.5rem;
		right: 4.75rem; /* 1.5rem (close button's own right inset) + 2.5rem (close button's own width) + 0.75rem (gap between them) */
	}

	/* The overlay's own site logo: same clone-as-sibling technique as
	   the bookmark icon above, top-left this time — mirroring the close
	   button's top-right corner rather than sitting to one side of it,
	   since there's nothing else up there on the left for it to crowd.
	   max-width matches the capped mobile logo size set on the real
	   header logo further down this file (the 480px breakpoint rule),
	   so it reads as the same brand mark at the same scale, not a
	   differently-sized one that happens to reuse the same image. */
	.rd-nav-logo--overlay {
		position: absolute;
		top: 1.5rem;
		left: 1.5rem;
		max-width: 100px;
	}
}

/* Defensive only: the dialog these clones live in is already inert at
   wider viewports (core hides the hamburger button that would open it),
   so this shouldn't be reachable outside the max-width:599px case above
   — but if it ever were, this stops them from turning up in the desktop
   header. */
@media (min-width: 600px) {
	.rd-nav-bookmark--overlay,
	.rd-nav-logo--overlay {
		display: none;
	}
}

@media (max-width: 599px) {
	.rd-site-header.rd-menu-open .rd-nav-overlay-extras .rd-nav-auth {
		flex-direction: column;
		align-items: stretch;
		gap: 0.75rem;
		width: 100%;
	}

	.rd-site-header.rd-menu-open .rd-nav-overlay-extras .wp-block-button__link {
		display: block;
		text-align: center;
	}

	/* Search takeover: pressing the search icon should hide the other
	   two items (hamburger, logo) and let the field use the whole row,
	   then bring them back once it's closed again. Core's own view
	   script is what actually opens/closes the field (toggling
	   .wp-block-search__searchfield-hidden on .rd-nav-search — see the
	   comments on that class further up this file); this theme has no
	   hook into that click itself. assets/js/nav-mobile.js watches that
	   same class with a MutationObserver instead of trying to intercept
	   the click, so it reacts correctly no matter which of core's own
	   interactions removes/restores the class (click-to-open,
	   click-to-close, blur, Escape) — and it mirrors the state onto
	   .rd-nav-grid as .rd-search-open, which is all the CSS below reads.

	   display:none (not visibility:hidden) on the hidden items so their
	   grid tracks collapse to zero content. */
	.rd-nav-grid.rd-search-open .wp-block-navigation,
	.rd-nav-grid.rd-search-open .wp-block-site-logo {
		display: none;
	}

	/* .rd-nav-search itself deliberately keeps its resting grid-column:3;
	   justify-self:end; small fixed box (set earlier in this file,
	   unconditionally) rather than being stretched to span the row —
	   an earlier version of this rule did stretch it, and also switched
	   .wp-block-search__inside-wrapper to position:static, which broke
	   the right-anchored growth technique the desktop rules already use
	   (see the comments on .rd-nav-search .wp-block-search__inside-wrapper
	   further up this file): with the wrapper back to position:absolute;
	   right:0 (its unmodified desktop value), the field still grows out
	   from the icon's own fixed position at the right edge, rather than
	   from wherever a stretched, flex-centered container happened to
	   place it.

	   The open width is calculated against the theme's own global
	   content padding (--wp--style--root--padding-left/-right, set from
	   styles.spacing.padding in theme.json) rather than a flat rem value
	   subtracted from 100vw — .rd-nav-search's right edge sits at the
	   header's own right padding edge, already inset from the true
	   viewport edge, so sizing off raw 100vw overshoots past the left
	   margin by roughly that same padding amount (this is exactly what
	   happened with an earlier calc(100vw - 3rem) version here).

	   That's still the width of the INPUT specifically, though, not the
	   row — .wp-block-search__inside-wrapper (the actual right-anchored,
	   absolutely-positioned box) is a nowrap flex row containing both
	   the input and the 2.25rem search button side by side, sized to
	   fit its content; giving the input the full available width alone
	   left the wrapper's true total width (input + button) that much
	   too wide, overshooting the left edge by the button's own
	   footprint even with the padding-variable fix above (an earlier
	   version here stopped one bug short of this one). Subtracting the
	   button's fixed 2.25rem below (it has no margin from the input —
	   button-only search variants zero that out) makes the wrapper's
	   real total width match the available space exactly. */
	.rd-nav-grid.rd-search-open .rd-nav-search .wp-block-search__input {
		width: calc(100vw - var(--wp--style--root--padding-left, 1.25rem) - var(--wp--style--root--padding-right, 1.25rem) - 2.25rem);
	}
}

/* Close button: core renders this automatically whenever overlayMenu is
   set (it's the "×" inside .wp-block-navigation__responsive-dialog,
   alongside .wp-block-navigation__responsive-container-content) — this
   just gives it the theme's own circular-icon-button look instead of
   core's bare default, so it's unmistakable against the overlay's
   white background (see the overlayBackgroundColor/overlayTextColor
   set on the wp:navigation block in parts/header.html) and matches the
   hamburger toggle, search, and bookmark icons elsewhere in the header.
   If a future WordPress/Gutenberg version renders this with different
   class names, these two rules simply match nothing and fall back to
   core's own default button styling — nothing else in this theme
   depends on them the way the overlay content used to. */
.wp-block-navigation__responsive-container-close,
.wp-block-navigation__responsive-container-open {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 2.5rem;
	height: 2.5rem;
	padding: 0;
	margin: 0;
	border-radius: 999px;
	border: 1px solid var(--wp--preset--color--plant-green);
	background-color: var(--wp--preset--color--white);
	color: var(--wp--preset--color--plant-green);
	transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}

/* Without an explicit size, core's default hamburger/close SVG can
   render slightly larger than the other header icons and off-register
   inside the flex-centered button above (extra intrinsic whitespace
   baked into the SVG's own viewBox) — pinning both dimensions and
   display:block (killing the inline-element baseline gap) is what
   actually centers the glyph, not just centering its container. */
.wp-block-navigation__responsive-container-close svg,
.wp-block-navigation__responsive-container-open svg {
	width: 1.1rem;
	height: 1.1rem;
	display: block;
}

.wp-block-navigation__responsive-container-close:hover,
.wp-block-navigation__responsive-container-open:hover {
	background-color: var(--wp--preset--color--plant-green);
	border-color: var(--wp--preset--color--plant-green);
	color: var(--wp--preset--color--white);
}

.wp-block-navigation__responsive-container-close {
	position: absolute;
	top: 1.5rem;
	right: 1.5rem;
}

/* Overlay menu list ("Home", "Recipes", "Recipes to Try" — see the
   Navigation panel in the Site Editor, not this file: the theme ships
   the Navigation block empty and WordPress fills it from whatever menu
   the site owner builds there). Core's own overlay styling is close to
   bare — this gives the list the same deliberate, editorial feel as the
   rest of the theme instead of looking unfinished: full-width divided
   rows sized for a thumb rather than core's compact left-aligned text,
   consistent horizontal padding matching the header's own side margin,
   and room at the bottom reserved for .rd-nav-overlay-extras (the
   bookmark/Log In/Sign Up footer revealed by the "Mobile nav" rules
   further down) so a long menu can never scroll underneath it.

   Core's own SCSS deliberately pins this list to the top of the overlay
   ("Always align the contents of the menu to the top" is the literal
   comment in Gutenberg's source) — for a 3-item menu on a full-height
   phone screen that reads as mostly empty space under a few small
   lines, so justify-content:center overrides that intentionally here;
   min-height needs its own explicit viewport-relative value (a
   percentage wouldn't have anything to resolve against, since core
   doesn't give this element's own ancestors a percentage-based height
   chain to inherit). The unprefixed vh rule first is a fallback for
   browsers that don't understand dvh — the dvh rule right after it
   simply gets ignored by those browsers rather than erroring, so the
   vh version stays in effect for them, while modern mobile browsers use
   the dvh one and get the correct height even as their own address bar
   shows/hides. */
@media (max-width: 599px) {
	.wp-block-navigation__responsive-container-content {
		min-height: 100vh;
		min-height: 100dvh;
		justify-content: center !important;
		padding: calc(2rem + 2.5rem) 1.5rem calc(var(--rd-nav-overlay-extras-height, 176px) + 1rem);
		gap: 0;
	}

	.wp-block-navigation__responsive-container-content .wp-block-navigation-item__content {
		display: block;
		width: 100%;
		padding: 1.4rem 0;
		font-size: var(--wp--preset--font-size--large);
		font-weight: 700;
		border-bottom: 1px solid rgba(0, 0, 0, 0.08);
		transition: color 0.15s ease, padding-left 0.15s ease;
	}

	.wp-block-navigation__responsive-container-content .wp-block-navigation-item:first-child > .wp-block-navigation-item__content {
		border-top: 1px solid rgba(0, 0, 0, 0.08);
	}

	.wp-block-navigation__responsive-container-content .wp-block-navigation-item__content:hover,
	.wp-block-navigation__responsive-container-content .wp-block-navigation-item__content:active {
		color: var(--wp--preset--color--spinach-green);
		padding-left: 0.5rem;
	}
}


/* Recipe Spotlight: the pattern sets flexWrap:"nowrap" deliberately for
   the desktop image+content split (see patterns/recipe-spotlight.php) —
   without an override, that never stacks, and the image and content
   just get squeezed into an unreadable sliver on a narrow screen.
   !important is needed here since it's overriding a layout rule the
   block itself generates, not a plain authored class. */
@media (max-width: 781px) {
	.is-style-spotlight {
		flex-wrap: wrap !important;
	}

	.rd-spotlight__media,
	.rd-spotlight__body {
		flex-basis: 100% !important;
	}
}

/* Card grids (Recipe Card / Feature Card, wherever a Query Loop's Post
   Template uses grid layout with a fixed columnCount — Recipe Grid
   Section, Most Popular, Editors' Picks, archive-recipe.html,
   taxonomy.html) — a fixed columnCount doesn't reduce on its own at
   narrow widths, so a 4-column grid would squeeze every card to a
   sliver on a phone. Targets every grid Post Template sitewide with one
   rule rather than touching each pattern individually. */
@media (max-width: 781px) {
	.wp-block-post-template.is-layout-grid {
		grid-template-columns: repeat(2, 1fr) !important;
	}
}

@media (max-width: 480px) {
	.wp-block-post-template.is-layout-grid {
		grid-template-columns: 1fr !important;
	}
}

/* Recipe Ingredients: a long ingredient name (e.g. "finely chopped
   fresh rosemary") has no room to wrap without this — flex items don't
   shrink below their content's natural width by default, so without
   min-width:0 the row would just overflow horizontally instead of
   wrapping the name onto a second line. */
.rd-ingredients__item {
	flex-wrap: wrap;
}

.rd-ingredients__name {
	flex: 1 1 auto;
	min-width: 0;
}

/* Category tiles: space-between reads fine as a full row, but pins a
   wrapped partial row (2-3 tiles on a phone) to opposite edges with an
   odd gap between them instead of grouping them together. */
@media (max-width: 600px) {
	.rd-category-tiles {
		justify-content: center;
	}
}

/* Header: Site Logo + Navigation + two buttons already wraps (flexWrap
   is set directly on the block in header.html), but at the very
   narrowest phone widths the gap alone eats into precious space. Tighten
   it and cap the logo's width so Log In / Sign Up have room to sit on
   the same row as the (by-then-collapsed) hamburger menu. */
@media (max-width: 480px) {
	.rd-nav-grid {
		gap: 0.75rem;
	}

	.rd-nav-grid .wp-block-site-logo img {
		max-width: 100px;
	}
}

/* Search results page (templates/search.html): the "Not Seeing What
   You're Looking For?" toggle and the ingredient-match panel it
   reveals. Styled as a plain understated text link rather than another
   button pill — it's a secondary, optional path, not a primary action
   competing with the search form above it. */
.rd-search-fallback-toggle {
	display: inline-block;
	margin-top: 0.5rem;
	padding: 0;
	border: none;
	background: none;
	color: var(--wp--preset--color--spinach-green);
	font-size: var(--wp--preset--font-size--small);
	text-decoration: underline;
	cursor: pointer;
}

.rd-search-fallback-toggle:hover {
	color: var(--wp--preset--color--plant-green);
}

.rd-search-fallback {
	padding-top: 1.5rem;
	border-top: 1px solid var(--wp--preset--color--cream);
}

/* Search results page (templates/search.html). Reuses the site's
   existing visual vocabulary rather than inventing a new one: the same
   eyebrow label as the Hero, the same Recipe Card grid as every other
   listing, the same Section Heading Row (colored-dot accent) as the
   dashboard sections, the same pill/arrow button language as the rest
   of the buttons on the site. */

/* Centered intro block — eyebrow, "Search results for…" heading, and
   the search field, narrower than the full-width results grid below it
   so the page reads as "focused ask, wide answer" rather than one flat
   column the whole way down. */
.rd-search-intro {
	text-align: center;
	margin-inline: auto;
}

.rd-search-intro .wp-block-query-title {
	margin: 0.5rem 0 0;
}

.rd-search-form.wp-block-search {
	display: flex;
	justify-content: center;
	gap: 0;
}

.rd-search-form .wp-block-search__inside-wrapper {
	max-width: 28rem;
	width: 100%;
	border-radius: 999px;
	border: 2px solid var(--wp--preset--color--plant-green);
	overflow: hidden;
}

.rd-search-form .wp-block-search__input {
	border: none;
	padding: 0.75em 1.25em;
	font-size: var(--wp--preset--font-size--medium);
}

.rd-search-form .wp-block-search__input:focus {
	outline: none;
}

.rd-search-form .wp-block-search__button {
	border-radius: 0;
	border: none;
	background: var(--wp--preset--color--plant-green);
	color: var(--wp--preset--color--white);
	font-weight: 700;
	padding: 0 1.5em;
}

.rd-search-form .wp-block-search__button:hover {
	background: var(--wp--preset--color--spinach-green);
}

/* Results grid — the same three-up Recipe Card layout "All Recipes"
   (archive-recipe.html) and taxonomy pages already use, so search
   results look like they belong to the same site instead of falling
   back to a plain title/excerpt list once you're on this one page. */
.rd-search-results .wp-block-post-template {
	gap: 1.75rem;
}

/* Empty state — an oversized "?" in the same glyph treatment as the
   in-recipe Pull Quote's giant quotation mark (frontend.css, "Pull
   Quote" section), so a dead-end search still feels like this site's
   typography rather than a generic system message. Paired with a
   concrete next step (Browse All Recipes) instead of leaving the
   visitor at a bare sentence. */
.rd-search-empty {
	text-align: center;
	max-width: 32rem;
	margin: 2rem auto 0;
}

.rd-search-empty__mark {
	font-size: 3.5rem;
	line-height: 1;
	font-weight: 800;
	color: var(--wp--preset--color--fresh-green);
	margin: 0 0 0.5rem;
}

.rd-search-empty .wp-block-buttons {
	justify-content: center;
	margin-top: 1.5rem;
}

/* "Not Seeing What You're Looking For?" toggle — an outline pill in the
   same heart-red "this reveals something" language as the category
   filter pills and bookmark toggle, not a bare underlined link riding
   on default link styles. */
.rd-search-fallback-row {
	text-align: center;
	margin-top: 3rem;
}

.rd-search-fallback-toggle {
	display: inline-flex;
	align-items: center;
	font-size: var(--wp--preset--font-size--small);
	font-weight: 700;
	background: var(--wp--preset--color--white);
	color: var(--wp--preset--color--heart-red);
	border: 1px solid var(--wp--preset--color--heart-red);
	border-radius: 999px;
	padding: 0.6em 1.5em;
	cursor: pointer;
	transition: background-color 0.15s ease, color 0.15s ease, box-shadow 0.15s ease;
}

.rd-search-fallback-toggle:hover {
	background: var(--wp--preset--color--heart-red);
	color: var(--wp--preset--color--white);
	box-shadow: inset 0 0 0 999px rgba(255, 255, 255, 0.12);
}

.rd-search-fallback {
	margin-top: 2.5rem;
	padding-top: 2rem;
	border-top: 1px solid var(--wp--preset--color--cream);
}

.rd-search-fallback .wp-block-post-template {
	gap: 1.75rem;
}

.rd-search-fallback__hint {
	color: var(--wp--preset--color--beet-red);
	margin-top: -1rem;
}

/* Hero content wrapper (patterns/section-hero.php). Actual page source
   confirms the numbered layout class IS being generated for
   .rd-hero-content (wp-container-core-group-is-layout-XXXXXXXX, with a
   correct max-width:1200px rule) — that part works. The real problem
   is one level up: .wp-block-cover__inner-container, the parent Cover
   itself provides for "bottom left" content positioning, shrinks to
   fit its content rather than spanning the full cover (that's how
   Cover's flex-based content-position system works) — so
   .rd-hero-content's max-width:1200px has no room to actually expand
   into; it's already sitting inside a box only as wide as "Now serving
   summer". Forcing the inner-container itself to full width first
   gives .rd-hero-content something to actually center within.

   !important on both rules: core's own Cover stylesheet almost
   certainly targets this same element with something like
   .wp-block-cover.is-position-bottom-left .wp-block-cover__inner-
   container (three classes) specifically to produce that shrink-wrap
   behavior — a rule that specific could out-rank a plain two-class
   selector regardless of which stylesheet loads later, since
   specificity beats source order when they differ. !important
   sidesteps needing to out-specify a rule I can't directly inspect
   (core's cover/style.min.css is an external file, not inlined in the
   page). */
.wp-block-cover .wp-block-cover__inner-container {
	width: 100% !important;
}

.rd-hero-content {
	width: 100% !important;
	max-width: 1200px !important;
	margin-left: auto !important;
	margin-right: auto !important;
	padding-bottom: 3.5rem;
	/* This group sits inside the Cover block's inner-container, which is
	   deliberately alignfull so the background image bleeds edge to
	   edge (see the comment above). Root padding (theme.json) only
	   reaches root-level blocks, and this content isn't one — it's
	   nested a level deeper inside that full-bleed Cover — so without
	   its own left/right padding here, the heading/eyebrow/button would
	   sit flush against the viewport edge on any screen narrower than
	   1200px, same failure mode section-promo-band.php already had to
	   solve for with its own explicit left/right padding. */
	padding-left: clamp(1.25rem, 4vw, 3rem);
	padding-right: clamp(1.25rem, 4vw, 3rem);
}
