/*
Theme Name: POME Heritage
Theme URI: https://pomevinegar.com
Author: Oregon Vinegar Co., LLC
Author URI: https://pomevinegar.com
Description: A custom block theme for POME Heritage Vinegars — raw, unfiltered apple cider vinegars made in Forest Grove, Oregon. Orchard ledger and letterpress broadside in feel: parchment, ink, engraved rules, and no ornament that does not earn its place. Server rendered, no front-end framework, WCAG 2.2 AA.
Requires at least: 6.6
Tested up to: 6.8
Requires PHP: 8.1
Version: 0.1.2
License: GNU General Public License v2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
Text Domain: pome-heritage
Tags: block-theme, e-commerce, accessibility-ready, editorial, full-site-editing

POME Heritage is distributed under the terms of the GNU GPL v2 or later.

Design tokens live in theme.json and are the single source of truth. This file
carries only what theme.json cannot express: focus behaviour, the skip link,
paper grain, product accent rules, the accordion, motion preferences and print.

Do not add design values here that belong in theme.json.
*/

/* ─────────────────────────────────────────────────────────────
   1. Base
   ───────────────────────────────────────────────────────────── */

/* Anchor targets clear the sticky header (see §5). */
html {
	scroll-padding-top: calc(var(--wp--custom--header-height) + 1rem);
	-webkit-text-size-adjust: 100%;
}

body {
	text-rendering: optimizeLegibility;
	-webkit-font-smoothing: antialiased;
}

/*
 * Body copy is capped at a readable measure. Headings and media are exempt so
 * they can still use the layout's content and wide widths.
 *
 * ── The two things that made this look broken until 2026-08-16 ──────────────
 *
 * 1. THE MEASURE WAS `68ch`, AND `ch` IS FONT-RELATIVE.
 *
 *    A custom property is substituted at the point of use, so `68ch` was
 *    recomputed against each element's own font size rather than once against
 *    the body. Measured in Libre Franklin, that gave three different widths in
 *    a single column:
 *
 *        small    68ch = 529px
 *        body     68ch = 605px
 *        body-lg  68ch = 756px, clamped by the layout to the 704px column
 *
 *    It is now a fixed length. 38rem is the same 68 characters at body size —
 *    the measurement the `ch` value was reaching for — but it no longer moves
 *    when the font size does, so every paragraph in the flow is one width.
 *
 * 2. THE LAYOUT WAS CENTERING WHAT THIS RULE NARROWED.
 *
 *    WordPress emits, for every constrained container:
 *
 *        .is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)) {
 *            max-width: var(--wp--style--global--content-size);
 *            margin-left: auto !important;
 *            margin-right: auto !important;
 *        }
 *
 *    So anything this rule made narrower than the 44rem column was then
 *    centred inside it. Combined with (1), a heading sat flush at 0, body copy
 *    was inset 49px, and small print was inset 87px — three left edges down one
 *    page, which is what made the pages read as sloppy rather than as designed.
 *
 *    Body copy is pinned to the start edge instead. Headings and media keep the
 *    full column, so they overhang on the right only, which is the intended
 *    relationship. `!important` is not a preference here: it is the only way to
 *    beat an `!important` in core's generated layout CSS.
 *
 * `.wp-block-details` is in the list so the FAQ's accordion rows share the body
 * measure. Without it the questions would rule the full 44rem while every other
 * page set its text to 38rem.
 */
.entry-content > p,
.entry-content > ul,
.entry-content > ol,
.entry-content > blockquote,
.entry-content > .wp-block-details {
	max-width: var(--wp--custom--measure);
	margin-inline-start: 0 !important;
	margin-inline-end: auto !important;
}

/* Never let a long word or URL force a horizontal scrollbar. */
h1, h2, h3, h4, h5, h6, p, li, dd, dt, figcaption {
	overflow-wrap: break-word;
}

/* ─────────────────────────────────────────────────────────────
   2. Focus and keyboard access  (brief §29.1–29.2)
   ───────────────────────────────────────────────────────────── */

/* Every interactive element gets a visible focus ring. Never remove this.
   :focus-visible keeps it off mouse clicks but on for keyboard users. */
:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
	outline: var(--wp--custom--focus--width) solid var(--wp--preset--color--ink);
	outline-offset: var(--wp--custom--focus--offset);
}

/* On ink grounds the ink outline would be invisible — brass reaches 4.86:1
   against ink, the only ground where brass is legible. See docs/design-system.md. */
.has-ink-background-color :where(a, button, input, select, textarea, summary, [tabindex]):focus-visible,
.pome-section--dark :where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
	outline-color: var(--wp--preset--color--brass);
}

/* Skip link: off-screen until focused, then pinned top-left. */
.skip-link {
	position: absolute;
	top: -100vh;
	left: var(--wp--preset--spacing--40);
	z-index: 999;
	padding: var(--wp--preset--spacing--30) var(--wp--preset--spacing--50);
	background: var(--wp--preset--color--ink);
	color: var(--wp--preset--color--parchment);
	font-family: var(--wp--preset--font-family--utility);
	font-size: var(--wp--preset--font-size--small);
	text-decoration: none;
	text-transform: uppercase;
	letter-spacing: 0.08em;
}

.skip-link:focus {
	top: var(--wp--preset--spacing--40);
}

/* Visually hidden but available to screen readers. */
.screen-reader-text {
	position: absolute !important;
	width: 1px;
	height: 1px;
	margin: -1px;
	padding: 0;
	overflow: hidden;
	clip-path: inset(50%);
	white-space: nowrap;
	border: 0;
}

.screen-reader-text:focus {
	position: static !important;
	width: auto;
	height: auto;
	margin: 0;
	clip-path: none;
	white-space: normal;
}

/* ─────────────────────────────────────────────────────────────
   2b. Links on dark grounds
   ───────────────────────────────────────────────────────────── */

/*
 * The default link colour is cider-brown, which is right on parchment
 * (10.21:1) and unreadable on ink (1.40:1). theme.json has no way to express
 * "this colour, except on dark sections", so the dark case is handled here.
 *
 * parchment on ink measures 14.31:1. The underline is brass (4.86:1 on ink)
 * so the link still reads as a link without the text itself dropping in
 * contrast. See docs/design-system.md for the full matrix.
 */
.pome-section--dark a:where(:not(.wp-element-button)),
.has-ink-background-color a:where(:not(.wp-element-button)),
.wp-block-cover.is-dark a:where(:not(.wp-element-button)),
.wp-block-cover .pome-section--dark a:where(:not(.wp-element-button)) {
	color: var(--wp--preset--color--parchment);
	text-decoration-color: var(--wp--preset--color--brass);
	text-underline-offset: 0.2em;
}

.pome-section--dark a:where(:not(.wp-element-button)):hover,
.has-ink-background-color a:where(:not(.wp-element-button)):hover,
.wp-block-cover.is-dark a:where(:not(.wp-element-button)):hover,
.wp-block-cover .pome-section--dark a:where(:not(.wp-element-button)):hover {
	color: var(--wp--preset--color--brass);
	text-decoration-color: var(--wp--preset--color--brass);
}

/* Outline buttons on dark grounds: core draws the border from currentColor,
   so the text colour has to be forced or both go muddy. */
.wp-block-cover .is-style-outline > .wp-block-button__link,
.pome-section--dark .is-style-outline > .wp-block-button__link,
.has-ink-background-color .is-style-outline > .wp-block-button__link {
	color: var(--wp--preset--color--parchment);
	border-color: var(--wp--preset--color--parchment);
	background-color: transparent;
}

.wp-block-cover .is-style-outline > .wp-block-button__link:hover,
.pome-section--dark .is-style-outline > .wp-block-button__link:hover,
.has-ink-background-color .is-style-outline > .wp-block-button__link:hover {
	color: var(--wp--preset--color--ink);
	background-color: var(--wp--preset--color--parchment);
	border-color: var(--wp--preset--color--parchment);
}

/* ─────────────────────────────────────────────────────────────
   3. Texture and rules  (brief §12)
   ───────────────────────────────────────────────────────────── */

/* A single tiling SVG noise, applied to section grounds only.
   Never behind text — the brief forbids fine text over texture. */
.pome-grain {
	position: relative;
	isolation: isolate;
}

.pome-grain::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: -1;
	pointer-events: none;
	opacity: var(--wp--custom--grain-opacity);
	background-image: url("assets/img/grain.svg");
	background-repeat: repeat;
	background-size: 180px 180px;
}

.pome-rule {
	border: 0;
	border-top: var(--wp--custom--rule--hairline);
	margin-block: var(--wp--preset--spacing--60);
}

.pome-rule--section {
	border-top: var(--wp--custom--rule--section);
}

/* ─────────────────────────────────────────────────────────────
   4. Product accents  (brief §15 — a rule, never a fill)
   ───────────────────────────────────────────────────────────── */

/*
 * Half the previous step, so the ceiling is 3rem — which lands back on the h1
 * preset's own maximum. The preset is not reused because this heading has a
 * second requirement the preset cannot express: it must hold ONE line.
 *
 * Two things make that hold. The block carries alignwide, so it is measured
 * against the 76rem the product columns below it use rather than the 44rem
 * content width that was wrapping it. And the size is capped by viewport width
 * as well as by 3rem, so the line shrinks to fit instead of wrapping — 5.3vw
 * is derived from 33 characters at a deliberately pessimistic 0.5em average
 * advance, leaving roughly 6% breathing room each side.
 *
 * If the ceiling ever needs raising, raise 3rem and 5.3vw together or the line
 * will simply stop shrinking and wrap again.
 */
.pome-collection__title {
	font-size: min(3rem, 5.3vw);
	line-height: 1.1;
	white-space: nowrap;
}

/*
 * Below roughly 34rem, holding one line costs more legibility than the single
 * line is worth, so the heading is allowed to wrap and settles at a fixed size.
 * 1.75rem is where the fluid rule above already is at this width, so nothing
 * jumps at the breakpoint.
 */
@media (max-width: 34rem) {
	.pome-collection__title {
		font-size: 1.75rem;
		white-space: normal;
		text-wrap: balance;
	}
}

.pome-product-card {
	position: relative;
	padding-bottom: var(--wp--preset--spacing--40);
	border-bottom: 4px solid transparent;
	transition: border-color var(--wp--custom--transition);
}

.pome-product-card--bittersweet { border-bottom-color: var(--wp--preset--color--orchard-green); }
.pome-product-card--barrel-aged  { border-bottom-color: var(--wp--preset--color--oxblood); }
.pome-product-card--marionberry  { border-bottom-color: var(--wp--preset--color--marionberry); }
.pome-product-card--balsamic     { border-bottom-color: var(--wp--preset--color--brass); }

/* The accent is decorative. Product identity is always carried in text as well,
   so nothing is communicated by colour alone (brief §29.17). */

/* Coming-soon state for Balsamic — a label, never a disabled button (brief §6.D.4). */
.pome-coming-soon {
	display: inline-block;
	padding: var(--wp--preset--spacing--20) var(--wp--preset--spacing--40);
	border: 1px solid var(--wp--preset--color--brass);
	color: var(--wp--preset--color--cider-brown);
	font-family: var(--wp--preset--font-family--utility);
	font-size: var(--wp--preset--font-size--small);
	text-transform: uppercase;
	letter-spacing: 0.08em;
}

/* ─────────────────────────────────────────────────────────────
   5. Header
   ───────────────────────────────────────────────────────────── */

/*
 * Hero copy sits left, against the frame, not centred in the cover.
 *
 * The width is set by the HEADLINE, not by the paragraph. At the display size
 * "Apple cider vinegar" needs roughly 41rem in the current serif fallback, so
 * the old 34rem broke it across two lines and turned a two-line headline into
 * three. 46rem clears it with room to spare for the metric differences between
 * EB Garamond and the Georgia/Palatino fallbacks it is standing in for.
 */
.pome-hero__inner {
	max-width: min(46rem, 100%);
	margin-inline-end: auto;
}

/*
 * The body copy does NOT follow the headline out to 46rem — at body-lg that
 * would run past the 68-character measure the design system sets. It keeps the
 * editorial width, so only the headline spends the extra room.
 */
.pome-hero__inner p {
	max-width: var(--wp--custom--editorial-width);
}

/*
 * POME Core wraps theme-asset images in <picture> to offer WebP. The wrapper
 * must contribute no box of its own, or it would break the two places that
 * depend on the img's own geometry: the absolutely positioned cover background,
 * and the mix-blend-mode rules below, which need the img to multiply against
 * the section ground rather than against an intermediate inline wrapper.
 */
picture {
	display: contents;
}

/*
 * Bottle renders arrive on white seamless. Until they are re-shot or cut out
 * (docs/open-decisions.md OD-004) blend mode drops the white into whatever
 * ground sits behind, instead of punching a white rectangle into the page.
 *
 * Applied everywhere a bottle appears: homepage cards, the homepage collection
 * feature, the shop archive, the product gallery and its thumbnails, related
 * products, and cart line items.
 * Multiply leaves the amber and purple liquid untouched — only the white goes.
 */
.pome-product-card figure img,
.pome-collection__shot img,
.woocommerce-product-gallery img,
.woocommerce ul.products li.product img,
.wp-block-woocommerce-product-image img,
.wc-block-grid__product-image img,
.wc-block-components-product-image img,
.woocommerce-cart-form__cart-item .product-thumbnail img,
.wc-block-cart-item__image img,
.up-sells img,
.related.products img {
	mix-blend-mode: multiply;
}

/*
 * Blend modes need an opaque ground to multiply against, and it has to be the
 * REAL ground colour — not `transparent`.
 *
 * WooCommerce renders the single-product gallery with an inline
 * `opacity: 0; transition: opacity .25s` and animates it to 1 once its script
 * initialises. Any opacity below 1 creates a stacking context, and a blend mode
 * cannot reach outside its own stacking context — so for that quarter second
 * the bottle multiplied against the gallery's own backdrop instead of the page.
 * Multiplying against `transparent` returns the source colour unchanged, which
 * is why a white box flashed around the bottle and then vanished the moment the
 * fade finished and the isolation went away.
 *
 * Painting parchment here gives the blend something correct to land on whether
 * or not the gallery is isolated, so the two states look identical and there is
 * nothing to flash. Keep this in step with the page ground.
 */
.woocommerce-product-gallery,
.woocommerce-product-gallery__wrapper,
.woocommerce-product-gallery__image {
	background: var(--wp--preset--color--parchment);
}

/* Archive thumbnails are never isolated, so they only need Woo's white box
   removed — they blend straight against whatever section they sit in. */
.woocommerce ul.products li.product a img {
	background: transparent;
}

/*
 * The zoom overlay is the same bug wearing a different hat: WooCommerce gives
 * .zoomImg its own `background-color: #fff` and fades it in from opacity 0, so
 * hovering the bottle would flash the identical white box.
 *
 * The selector deliberately mirrors WooCommerce's own, character for character,
 * so the two carry equal specificity and this one wins on load order — the
 * theme stylesheet is enqueued after woocommerce.css. Do not shorten it.
 */
.woocommerce div.product div.images .woocommerce-product-gallery__wrapper .zoomImg {
	background-color: var(--wp--preset--color--parchment);
}

/*
 * Hide the still image while the zoom overlay is showing.
 *
 * jquery.zoom appends the magnified .zoomImg INSIDE
 * .woocommerce-product-gallery__image, as an absolutely positioned sibling of
 * the original. That overlay is an <img> inside the gallery, so the multiply
 * rule above catches it too — and instead of multiplying against the parchment
 * page it multiplied against the photo directly beneath it. Both images stayed
 * visible at once, one magnified and one not.
 *
 * Taking the still image out from under the overlay lets the zoom blend against
 * the container's parchment ground, exactly as the unzoomed bottle does, so the
 * two states match.
 *
 * :has(.zoomImg) is the guard. WooCommerce leaves the overlay in the DOM at
 * opacity 0 once its script has run, so this matches only where zoom is really
 * available; with JavaScript off there is no .zoomImg and the still image is
 * never hidden.
 *
 * The switch is discrete, not a cross-fade. Fading the two images through each
 * other would put both on screen at partial opacity, which is the doubled image
 * we are trying to remove — just briefer. So the still image goes at once on
 * entry, and comes back only after jquery.zoom's 120ms fade-out has finished,
 * which keeps it out of the way at both ends.
 *
 * The delay is carried by transition-delay rather than transition-duration, so
 * the reduced-motion block in §10 does not collapse it and reintroduce the
 * doubling for those users.
 */
.woocommerce-product-gallery__image:has(.zoomImg) > a > img,
.woocommerce-product-gallery__image:has(.zoomImg) > img:not(.zoomImg) {
	visibility: visible;
	transition: visibility 0s linear 120ms;
}

.woocommerce-product-gallery__image:has(.zoomImg):hover > a > img,
.woocommerce-product-gallery__image:has(.zoomImg):hover > img:not(.zoomImg) {
	visibility: hidden;
	transition-delay: 0s;
}

.pome-product-card__price {
	font-weight: 500;
}

.pome-product-card__price p {
	margin: 0;
}

.pome-header {
	position: sticky;
	top: 0;
	z-index: 100;
	min-height: var(--wp--custom--header-height);
	background: var(--wp--preset--color--parchment);
	border-bottom: var(--wp--custom--rule--hairline);
}

/* The engraved press has fine hairlines that fill in when it gets small.
   3.75rem was the point at which the press still reads as a press; the cap
   now sits 50% above that, matching the site-logo width in parts/header.html. */
.pome-header__logo img {
	display: block;
	width: auto;
	max-height: 5.625rem;
}

/* ─────────────────────────────────────────────────────────────
   6. Product page typography
   ───────────────────────────────────────────────────────────── */

/*
 * WooCommerce assembles the single-product page from its own markup, so the
 * headings in it never passed through a pattern and never got a size chosen for
 * them. They fell through to the global element styles, which are scaled for
 * editorial pages, and the result had no usable hierarchy:
 *
 *   product title      3rem     (h1)
 *   "Description"      2.75rem  (bare h2 — nearly the same as the title)
 *   subheads           1.75rem  (h3)
 *   lead               1.25rem
 *   body               1rem
 *   legal note         0.875rem
 *
 * Two problems. The tab headings are structural labels, not editorial headings,
 * so setting them at h2 made "Description" shout as loudly as the product name.
 * And the four sizes below the subheads sat close enough together to read as
 * accidental rather than deliberate.
 *
 * The ladder below is scoped to the product entry — NOT to body.single-product,
 * which would take the header and footer with it.
 */

/* The product name. Still the largest thing on the page, but it no longer has
   to shout over a tab label sitting directly beneath it. */
.single-product .wp-block-post-title {
	font-size: clamp(1.75rem, 1.35rem + 1.7vw, 2.5rem);
	line-height: 1.12;
}

/*
 * The tab list is the only label each panel has.
 *
 * WooCommerce used to name every panel twice — once in this list and again as
 * an <h2> inside the panel — so the page read "Description" and then
 * "Description" again. The duplicate is removed at source in
 * pome-core/includes/commerce/product-tabs.php, which leaves these tabs doing
 * the labelling on their own. They are set in the same utility language the
 * theme uses for eyebrows so they read as labels rather than as links.
 *
 * WooCommerce's own is-style-minimal already strips the default grey boxes and
 * supplies the 2px active underline; only the type is set here.
 */
.single-product .woocommerce-tabs ul.tabs li a {
	font-family: var(--wp--preset--font-family--utility);
	font-size: var(--wp--preset--font-size--small);
	font-weight: 600;
	letter-spacing: 0.12em;
	text-transform: uppercase;
}

/*
 * The reviews panel keeps its heading, because it is not a duplicate: with
 * reviews present it reads "2 reviews for Bittersweet Apple Cider Vinegar"
 * rather than repeating the tab. Same label treatment as the tabs above.
 */
.single-product .woocommerce-Reviews-title {
	margin-bottom: var(--wp--preset--spacing--50);
	padding-bottom: var(--wp--preset--spacing--30);
	border-bottom: var(--wp--custom--rule--hairline);
	font-family: var(--wp--preset--font-family--utility);
	font-size: var(--wp--preset--font-size--small);
	font-weight: 600;
	line-height: 1.3;
	letter-spacing: 0.12em;
	text-transform: uppercase;
}

/* Subheads inside a description. Below the product title, clearly above the
   lead, and the only serif heading left in the tab. */
.single-product .woocommerce-Tabs-panel h3,
.single-product .wp-block-woocommerce-product-details h3 {
	margin-top: var(--wp--preset--spacing--60);
	margin-bottom: var(--wp--preset--spacing--30);
	font-size: clamp(1.2rem, 1.08rem + 0.5vw, 1.375rem);
	line-height: 1.25;
}

/*
 * The lead paragraph and the closing note carry explicit classes rather than
 * font-size presets. Preset classes are printed with !important, so sizing them
 * per-context would mean an !important of our own; a class the theme owns keeps
 * the cascade honest and keeps the content files readable.
 */
.single-product .pome-product-lead {
	font-size: 1.125rem;
	line-height: 1.6;
}

.single-product .pome-product-note {
	margin-top: var(--wp--preset--spacing--60);
	padding-top: var(--wp--preset--spacing--40);
	border-top: var(--wp--custom--rule--hairline);
	font-size: 0.9375rem;
	line-height: 1.6;
	color: var(--wp--preset--color--cider-brown);
}

/* The short description under the price is the product's opening line, so it
   matches the lead rather than sitting at plain body size. */
.single-product .wp-block-post-excerpt__excerpt {
	font-size: 1.125rem;
	line-height: 1.6;
}

/* Woo renders the attributes table and the review furniture at its own sizes.
   Pin them to the theme scale so nothing on the page is off-ladder. */
.single-product .woocommerce-product-attributes,
.single-product .woocommerce-noreviews,
.single-product .comment-form-comment label,
.single-product .comment-notes {
	font-size: var(--wp--preset--font-size--small);
}

/* ─────────────────────────────────────────────────────────────
   7. Journal index, filters and search
   ───────────────────────────────────────────────────────────── */

/*
 * Two rows of filters. The first is the pair of grouping categories, Recipes
 * and Journal, plus Everything; the second is whichever specific categories
 * sit under the open group. Marking the current one is done with
 * aria-current="page" rather than a class, so the state is announced to a
 * screen reader and styled from the same source of truth.
 */
.pome-journal-filters {
	margin-top: var(--wp--preset--spacing--60);
	border-top: var(--wp--custom--rule--hairline);
	padding-top: var(--wp--preset--spacing--40);
}

.pome-journal-filters__row {
	display: flex;
	flex-wrap: wrap;
	gap: var(--wp--preset--spacing--20) var(--wp--preset--spacing--50);
	margin: 0;
	padding: 0;
	list-style: none;
}

.pome-journal-filters__row a {
	display: inline-block;
	padding-block: var(--wp--preset--spacing--20);
	font-family: var(--wp--preset--font-family--utility);
	text-decoration: none;
	border-bottom: 2px solid transparent;
}

.pome-journal-filters__row a:hover {
	border-bottom-color: var(--wp--preset--color--aged-paper);
}

/* The open filter. An underline rather than a fill, per brief §15. */
.pome-journal-filters__row a[aria-current="page"] {
	border-bottom-color: var(--wp--preset--color--ink);
}

.pome-journal-filters__row--primary a {
	font-size: var(--wp--preset--font-size--small);
	font-weight: 600;
	letter-spacing: 0.12em;
	text-transform: uppercase;
}

/* The specific categories sit quieter than the two groups above them. */
.pome-journal-filters__row--secondary {
	margin-top: var(--wp--preset--spacing--30);
	gap: var(--wp--preset--spacing--20) var(--wp--preset--spacing--40);
}

.pome-journal-filters__row--secondary a {
	font-size: var(--wp--preset--font-size--small);
	color: var(--wp--preset--color--cider-brown);
}

.pome-journal-filters__count {
	color: var(--wp--preset--color--cider-brown);
	opacity: 0.6;
	font-variant-numeric: tabular-nums;
}

.pome-journal-search {
	display: flex;
	gap: var(--wp--preset--spacing--30);
	margin-top: var(--wp--preset--spacing--50);
	max-width: 28rem;
}

.pome-journal-search input[type="search"] {
	flex: 1 1 auto;
	min-width: 0;
}

/*
 * The list itself. Entries are separated by a hairline rather than by large
 * gaps, so more of them are on screen at once — the point of the exercise is
 * finding one item, not reading the whole archive top to bottom.
 */
.pome-journal-entry {
	padding-block: var(--wp--preset--spacing--50);
	border-bottom: var(--wp--custom--rule--hairline);
}

.pome-journal-entry > * {
	margin-block: 0;
}

.pome-journal-entry__kind a {
	text-decoration: none;
	color: var(--wp--preset--color--cider-brown);
}

.pome-journal-entry .wp-block-post-title a {
	text-decoration: none;
}

.pome-journal-entry .wp-block-post-title a:hover {
	text-decoration: underline;
	text-underline-offset: 0.15em;
}

/* Pinned to the start edge for the same reason as the body copy rule in §1:
   the entry is a constrained group, so anything narrower than it is centred by
   core's layout CSS, and the excerpt was sitting indented from the kicker,
   title and date it belongs to. */
.pome-journal-entry .wp-block-post-excerpt {
	max-width: var(--wp--custom--measure);
	margin-inline-start: 0 !important;
	margin-inline-end: auto !important;
}

.pome-journal-entry__date {
	margin-top: var(--wp--preset--spacing--20);
	color: var(--wp--preset--color--cider-brown);
}

/* ─────────────────────────────────────────────────────────────
   8. Lab comparison chart  (brief §10 — accessible HTML, not an image)
   ───────────────────────────────────────────────────────────── */

/* The bar is drawn from a --pome-bar custom property set inline per row.
   Every value and unit is present as real table text, so screen readers and
   search engines get the numbers whether or not the bars render. */
.pome-lab-table {
	width: 100%;
	border-collapse: collapse;
	font-variant-numeric: tabular-nums;
}

.pome-lab-table th,
.pome-lab-table td {
	padding: var(--wp--preset--spacing--30);
	text-align: left;
	border-bottom: var(--wp--custom--rule--hairline);
}

.pome-lab-table th {
	font-family: var(--wp--preset--font-family--utility);
	font-size: var(--wp--preset--font-size--small);
	font-weight: 500;
	text-transform: uppercase;
	letter-spacing: 0.08em;
}

.pome-lab-bar {
	display: block;
	height: 0.75rem;
	width: var(--pome-bar, 0%);
	min-width: 2px;
	background: var(--wp--preset--color--cider-brown);
}

.pome-lab-bar--comparison {
	background: var(--wp--preset--color--aged-paper);
}

/* Always visible, never collapsed into a footnote (brief §10.4). */
.pome-lab-disclaimer {
	margin-top: var(--wp--preset--spacing--40);
	font-size: var(--wp--preset--font-size--small);
	color: var(--wp--preset--color--cider-brown);
}

/* ─────────────────────────────────────────────────────────────
   8b. Culinary uses list  (homepage)
   ───────────────────────────────────────────────────────────── */

/*
 * Eight short labels, set in CSS columns.
 *
 * Columns rather than a wp:columns of four separate lists, so the markup stays
 * one list: four two-item lists would be announced as four lists, and would
 * re-flow into reading order down each column instead of across on a phone.
 * `columns` keeps a single <ul> and lets the browser do the balancing.
 */
.pome-use-list {
	columns: 4;
	column-gap: var(--wp--preset--spacing--60);
	margin: 0;
	padding: 0;
	list-style: none;
}

.pome-use-list li {
	/* break-inside stops a label being split across the foot of one column and
	   the head of the next, which columns will happily do to a two-word item. */
	break-inside: avoid;
	border-top: var(--wp--custom--rule--hairline);
	font-family: var(--wp--preset--font-family--utility);
	font-size: var(--wp--preset--font-size--body);
}

/*
 * The padding is on the anchor, not the list item, so the whole row is the
 * click target rather than just the few words of the label. On a phone that is
 * the difference between a comfortable tap and a careful one, and it costs
 * nothing on a mouse.
 */
.pome-use-list a {
	display: block;
	padding: var(--wp--preset--spacing--30) 0;
	/* The rows are close together and the underline would otherwise sit almost
	   on the hairline of the row beneath. */
	text-underline-offset: 0.18em;
}

.pome-use-list a:hover {
	color: var(--wp--preset--color--ink);
}

@media (max-width: 900px) {
	.pome-use-list { columns: 2; }
}

@media (max-width: 480px) {
	.pome-use-list { columns: 1; }
}

/* ─────────────────────────────────────────────────────────────
   8c. Apple variety index  (/heritage-apples/)
   ───────────────────────────────────────────────────────────── */

/*
 * Markup comes from the [pome_apple_varieties] shortcode in
 * pome-core/includes/post-types/apple-variety.php.
 *
 * A photograph, a name, a classification and a note. The photographs are the
 * point of this index — several are the only picture of that fruit anywhere on
 * the site — so they lead, and the type line sits between name and note so the
 * classification is legible at a glance rather than buried in prose.
 */

/*
 * The index sits inside the 44rem text column, not wider.
 *
 * Widening it was tried and abandoned: max-width does compute to the 76rem wide
 * size, but .entry-content is itself capped at content-size by the constrained
 * <main> above it, so nothing inside can exceed 44rem and the override was
 * simply inert. Making .entry-content alignwide to get around that would give
 * this page a second column width and undo the single left edge the rest of the
 * site was fixed to keep.
 *
 * Two cards across at ~330px each is the better outcome anyway. The photographs
 * are the point of this index, and two large ones beat four small.
 */
.entry-content > .pome-variety-index {
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
	gap: var(--wp--preset--spacing--70) var(--wp--preset--spacing--60);
	margin-top: var(--wp--preset--spacing--70);
	/* Pinned to the start edge; core centres any child it has narrowed. */
	margin-inline-start: 0 !important;
	margin-inline-end: auto !important;
}

.pome-variety__shot img {
	display: block;
	width: 100%;
	height: auto;
	aspect-ratio: 1;
	object-fit: cover;
	/* Square crops, so a bin shot and a single apple on the branch sit in the
	   same grid without one towering over the other. */
}

.pome-variety__name {
	margin: var(--wp--preset--spacing--40) 0 var(--wp--preset--spacing--10);
	font-size: var(--wp--preset--font-size--heading-3);
	line-height: 1.2;
}

.pome-variety__meta {
	margin: 0 0 var(--wp--preset--spacing--30);
	font-family: var(--wp--preset--font-family--utility);
	font-size: var(--wp--preset--font-size--small);
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: 0.08em;
	color: var(--wp--preset--color--cider-brown);
}

.pome-variety__note {
	margin: 0;
	font-size: var(--wp--preset--font-size--small);
	line-height: 1.6;
}

/* ─────────────────────────────────────────────────────────────
   8d. Single apple variety  (/apple/<slug>/)
   ───────────────────────────────────────────────────────────── */

/*
 * Markup comes from the [pome_apple_variety_detail] shortcode in
 * pome-core/includes/post-types/apple-variety.php, on the template
 * templates/single-pome_apple_variety.html.
 *
 * A definition list, not a table. These are name/value pairs about one subject,
 * which is what <dl> is for, and it degrades to a readable stack with no styles
 * at all. The <div> wrapper around each dt/dd pair is what makes them
 * addressable as rows -- dt and dd cannot be grid items together without it.
 */

.pome-variety-detail {
	margin-top: var(--wp--preset--spacing--60);
}

.pome-variety-detail__facts {
	margin: 0 0 var(--wp--preset--spacing--60);
	border-top: var(--wp--custom--rule--hairline);
}

.pome-variety-detail__row {
	display: grid;
	/* The label column is sized for "Tannin, sugar and acid notes", the longest
	   label in the set. Fixed rather than auto so the values line up down the
	   page instead of stepping in and out with each label's length. */
	grid-template-columns: minmax(0, 13rem) 1fr;
	gap: var(--wp--preset--spacing--30) var(--wp--preset--spacing--50);
	padding: var(--wp--preset--spacing--40) 0;
	border-bottom: var(--wp--custom--rule--hairline);
}

.pome-variety-detail__row dt {
	margin: 0;
	font-family: var(--wp--preset--font-family--utility);
	font-size: var(--wp--preset--font-size--small);
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: 0.08em;
	color: var(--wp--preset--color--cider-brown);
	line-height: 1.5;
}

.pome-variety-detail__row dd {
	margin: 0;
	line-height: 1.6;
}

/* The sensory note is the one field that reads as prose, so it is set as prose
   -- body size, full measure -- rather than as another value in the list. */
.pome-variety-detail__note {
	margin: 0;
	font-size: var(--wp--preset--font-size--body-lg);
	line-height: 1.65;
}

@media (max-width: 600px) {
	.pome-variety-detail__row {
		grid-template-columns: 1fr;
		gap: var(--wp--preset--spacing--10);
	}
}

/* ─────────────────────────────────────────────────────────────
   9. Accordion  (secondary detail only, brief §24)
   ───────────────────────────────────────────────────────────── */

/* Sized for a whole question, not a one-word label. The FAQ is fifty of these
   in a column, so the closed state has to read as a scannable index: sentence
   case, body font, hairline between each, and the sign is the only ornament.
   Uppercase and letter-spacing were removed on 2026-08-16 — they are right for
   an eyebrow of two words and unreadable across "What is the difference between
   hard and soft tannins?".

   No JavaScript. <details> does this natively, so it works before scripts load,
   with scripts blocked, and inside the block editor. */

/* The rule belongs to the <details>, not to the <summary>. On the summary it
   would draw between the question and its own answer once opened; here it
   closes the whole item, open or shut.

   One line per item, never two: each item rules below itself, and only the
   first of a run rules above. That is why the top rule is hung off "a question
   preceded by something that is not a question" rather than :first-of-type,
   which would only ever match once per page rather than once per section. */
.is-style-pome-accordion {
	border-bottom: var(--wp--custom--rule--hairline);
}

:not(.is-style-pome-accordion) + .is-style-pome-accordion {
	border-top: var(--wp--custom--rule--hairline);
}

/* The set closes up against itself: consecutive questions sit flush rather
   than carrying the block gap between them. */
.is-style-pome-accordion + .is-style-pome-accordion {
	margin-top: 0;
}

.is-style-pome-accordion summary {
	/* Absolute sign rather than a float or flex: the glyph then holds its
	   column no matter how many lines the question wraps to, and <summary> is
	   left as a plain block, which is the layout mode its disclosure-widget
	   behaviour is best tested against. */
	position: relative;
	padding: var(--wp--preset--spacing--40) var(--wp--preset--spacing--50) var(--wp--preset--spacing--40) 0;
	font-family: var(--wp--preset--font-family--body);
	font-size: var(--wp--preset--font-size--body);
	line-height: 1.4;
	cursor: pointer;
	list-style: none;
	/* A question is a control here. Stop double-tap-to-select on touch from
	   selecting the text instead of opening the answer. */
	-webkit-user-select: none;
	user-select: none;
}

.is-style-pome-accordion summary::-webkit-details-marker { display: none; }

.is-style-pome-accordion summary:hover {
	color: var(--wp--preset--color--cider-brown);
}

.is-style-pome-accordion summary::after {
	content: "+";
	position: absolute;
	right: 0;
	/* Aligned to the first line, not the box, so the sign stays put whether the
	   question runs to one line or three. */
	top: var(--wp--preset--spacing--40);
	font-size: 1.25em;
	/* 1.4 / 1.25. The sign is set larger than the question, so it needs the
	   reciprocal leading to keep its line box the same height as the text's and
	   its glyph on the same optical line. Leaving this at 1.4 drops it visibly. */
	line-height: 1.12;
	color: var(--wp--preset--color--cider-brown);
}

/* U+2212 MINUS SIGN, not a hyphen: it matches the width and the optical weight
   of the plus it replaces, so the row does not shift when it opens. */
.is-style-pome-accordion[open] summary::after { content: "−"; }

.is-style-pome-accordion[open] summary {
	font-weight: 600;
}

/* The answer is indented to the depth of the sign column, which lines the
   answer up under the question rather than under the page margin. */
.is-style-pome-accordion > :not(summary) {
	margin-right: var(--wp--preset--spacing--50);
}

.is-style-pome-accordion > :not(summary):first-of-type {
	margin-top: 0;
}

.is-style-pome-accordion > :not(summary):last-child {
	margin-bottom: var(--wp--preset--spacing--50);
}

/* Paper does not fold. Print every answer whether or not it was open on
   screen, so a printed FAQ is not a list of questions with nothing under them. */
@media print {
	.is-style-pome-accordion > :not(summary) {
		display: block !important;
	}

	.is-style-pome-accordion summary::after { content: none; }
}

/* ─────────────────────────────────────────────────────────────
   10. Forms
   ───────────────────────────────────────────────────────────── */

input[type="text"],
input[type="email"],
input[type="tel"],
input[type="url"],
input[type="search"],
input[type="number"],
select,
textarea {
	width: 100%;
	padding: var(--wp--preset--spacing--30);
	background: var(--wp--preset--color--warm-white);
	border: 1px solid var(--wp--preset--color--ink);
	border-radius: 0;
	font-family: inherit;
	font-size: max(1rem, var(--wp--preset--font-size--body)); /* ≥16px stops iOS zoom */
	color: var(--wp--preset--color--ink);
}

/* Errors are never signalled by colour alone — the icon and text carry it too. */
.pome-field-error {
	display: block;
	margin-top: var(--wp--preset--spacing--20);
	color: var(--wp--preset--color--oxblood);
	font-size: var(--wp--preset--font-size--small);
	font-weight: 500;
}

.pome-field-error::before {
	content: "✕ ";
	font-weight: 700;
}

.pome-error-summary {
	padding: var(--wp--preset--spacing--40);
	margin-bottom: var(--wp--preset--spacing--50);
	border: 2px solid var(--wp--preset--color--oxblood);
	background: var(--wp--preset--color--warm-white);
}

input[aria-invalid="true"],
select[aria-invalid="true"],
textarea[aria-invalid="true"] {
	border-width: 2px;
	border-color: var(--wp--preset--color--oxblood);
}

/* ── Contact form ──────────────────────────────────────────────────────────
   Markup comes from pome-core/includes/contact-form.php. Only the layout is
   here; the field, error and focus treatments above are shared with every
   other form on the site. */

/* Capped to the body measure and pinned to the start edge. Without the pin the
   constrained layout centres it, because it is narrower than the column — the
   same trap documented against the body-copy rule in §1. It is repeated here
   rather than added to that selector list because the form arrives through a
   shortcode and is not reliably a direct child of .entry-content. */
.pome-contact-form,
.pome-form-success {
	max-width: var(--wp--custom--measure);
	margin-inline-start: 0 !important;
	margin-inline-end: auto !important;
}

.pome-field {
	margin-bottom: var(--wp--preset--spacing--50);
}

.pome-field label {
	display: block;
	margin-bottom: var(--wp--preset--spacing--20);
	font-family: var(--wp--preset--font-family--utility);
	font-size: var(--wp--preset--font-size--small);
	font-weight: 600;
	letter-spacing: 0.04em;
}

/* "optional" rather than marking everything else with an asterisk. Three of
   the five fields are required, so the shorter list is the exceptions. */
.pome-optional {
	font-weight: 400;
	text-transform: none;
	letter-spacing: 0;
	color: var(--wp--preset--color--cider-brown);
}

/* Sits between the label and the input, and is wired to the field with
   aria-describedby, so it is read out as part of the field rather than as
   loose text a screen reader user meets before knowing what it belongs to. */
.pome-field-hint {
	display: block;
	margin-bottom: var(--wp--preset--spacing--20);
	font-size: var(--wp--preset--font-size--small);
	color: var(--wp--preset--color--cider-brown);
}

.pome-form-privacy {
	font-size: var(--wp--preset--font-size--small);
	color: var(--wp--preset--color--cider-brown);
}

/* The confirmation, not an alert: nothing went wrong. It carries a rule rather
   than a colour fill so it reads as part of the page. */
.pome-form-success {
	padding: var(--wp--preset--spacing--50);
	border: 2px solid var(--wp--preset--color--orchard-green);
	background: var(--wp--preset--color--warm-white);
}

.pome-form-success p:last-child {
	margin-bottom: 0;
}

.pome-error-summary ul {
	margin: var(--wp--preset--spacing--30) 0 0;
	padding-left: var(--wp--preset--spacing--50);
}

/*
 * The honeypot.
 *
 * Not display:none. Some bots ignore fields hidden that way, which is exactly
 * the ones this is meant to catch, so it is moved off-screen while staying a
 * rendered, fillable field. aria-hidden and tabindex="-1" in the markup keep it
 * away from screen readers and the keyboard, so no person can reach it.
 */
.pome-hp {
	position: absolute;
	left: -9999px;
	width: 1px;
	height: 1px;
	overflow: hidden;
}

/* Marketing consent is never pre-checked (brief §15, §26). */
.pome-consent {
	display: flex;
	gap: var(--wp--preset--spacing--30);
	align-items: flex-start;
	font-size: var(--wp--preset--font-size--small);
}

.pome-consent input[type="checkbox"] {
	flex: 0 0 auto;
	width: 1.15rem;
	height: 1.15rem;
	margin-top: 0.15rem;
	accent-color: var(--wp--preset--color--cider-brown);
}

/* ─────────────────────────────────────────────────────────────
   11. Motion  (brief §29.10)
   ───────────────────────────────────────────────────────────── */

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

/* ─────────────────────────────────────────────────────────────
   12. Print  (brief §34.9 — recipes and order confirmations)
   ───────────────────────────────────────────────────────────── */

@media print {
	.pome-header,
	.pome-announcement,
	.wp-block-site-footer,
	.pome-newsletter,
	.pome-related,
	nav {
		display: none !important;
	}

	body {
		background: #fff;
		color: #000;
		font-size: 11pt;
	}

	.pome-grain::before { display: none; }

	/* A printed link that says "click here" is useless — print the target. */
	.entry-content a[href^="http"]::after {
		content: " (" attr(href) ")";
		font-size: 9pt;
		word-break: break-all;
	}

	h2, h3 { break-after: avoid; }
	figure, table, li { break-inside: avoid; }
}
