/* odf-theme CSS bundle - SOURCE OF TRUTH since 29 Jul 2026: edit this file directly.
   Produced by the one-time split of the retired main.css. Conventions + how to add
   components or page types: docs/CSS_ARCHITECTURE.md. Gate: scripts/css-coverage.py. */
/* ==========================================================================
   OnlyDogFood - Components & layout (consumes tokens.css; light mode only)
   Trimmed port of the tc-theme main.css: generic primitives kept (reset,
   header/nav, buttons, cards, forms, tables, chips, FAQ, guides, footer),
   TC-specific blocks (clinics, specialists, maps, price widgets) removed.
   New ODF components (score dial, ingredient pills, verdict box, compare
   tray) land here as their mockup-approved styles are built.
   ========================================================================== */

/* --- Reset --- */
*, *::before, *::after { box-sizing: border-box; }
/* The `hidden` attribute must always win. The UA's `[hidden]{display:none}` lives in the
   user-agent origin, so ANY author `display:` rule on the same element silently beats it.
   JS toggles `hidden` on several components, so this reset is load-bearing. */
[hidden] { display: none !important; }
/* Form controls do NOT inherit the page font - set the family once here so no
   component has to remember `font-family: inherit` for itself. */
button, input, select, textarea, optgroup { font-family: inherit; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
body {
	margin: 0;
	font-family: var(--odf-font-sans);
	font-size: var(--odf-fs-base);
	line-height: var(--odf-lh-base);
	color: var(--odf-ink-2);
	background: var(--odf-surface);
	-webkit-font-smoothing: antialiased;
	text-rendering: optimizeLegibility;
}
img { max-width: 100%; height: auto; display: block; }
svg { display: block; }
.odf-ico { display: inline-block; vertical-align: middle; flex: none; }
a { color: var(--odf-green); text-decoration: none; transition: color var(--odf-dur) var(--odf-ease); }
a:hover { color: var(--odf-ink); }
/* Text selection. The old rule painted --odf-green-soft (#e7f2ed) behind ink that
   kept its normal colour - on a white card or the cream canvas that is a ~2%
   shift, so you genuinely could not see what you had highlighted. Solid brand
   green with white text is unmistakable on every light surface. */
::selection      { background: var(--odf-green); color: #fff; text-shadow: none; }
::-moz-selection { background: var(--odf-green); color: #fff; text-shadow: none; }

/* Dark surfaces already run white text on green, where the rule above would be
   green-on-green - the same invisibility, inverted. Gold reads clearly on both.
   Each surface needs BOTH selectors: ::selection does not cascade to descendants
   the way ordinary colour does, so `.x ::selection` alone misses text sitting
   directly in .x, and `.x::selection` alone misses everything nested. */
.odf-footer::selection,    .odf-footer ::selection,
.odf-statcard::selection,  .odf-statcard ::selection,
.odf-statsband::selection, .odf-statsband ::selection { background: var(--odf-gold); color: var(--odf-ink); }

/* Headings use the display stack (Fraunces). Heading weight is 700 sitewide;
   800 would be faux-bold. */
h1, h2, h3, h4 { font-family: var(--odf-font-display); line-height: var(--odf-lh-tight); color: var(--odf-ink); margin: 0 0 var(--odf-sp-4); font-weight: 700; letter-spacing: var(--odf-tracking-tight); }
h1 { font-size: var(--odf-fs-3xl); }
h2 { font-size: var(--odf-fs-2xl); }
h3 { font-size: var(--odf-fs-lg); }
p  { margin: 0 0 var(--odf-sp-4); }

/* Focus ring via box-shadow, plus a transparent outline so the indicator still
   shows in Windows High Contrast Mode (where box-shadow is dropped). */
:focus-visible { outline: 2px solid transparent; outline-offset: 2px; box-shadow: var(--odf-ring); border-radius: var(--odf-radius-sm); }

/* Respect users who prefer reduced motion. */
@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;
	}}

/* --- Layout --- */
.odf-container { width: 100%; max-width: var(--odf-container); margin-inline: auto; padding-inline: var(--odf-sp-5); }
.odf-section { padding-block: var(--odf-section-gap); }
.odf-section + .odf-section { padding-top: 0; }
.odf-section--tight { padding-top: var(--odf-sp-6); }
.odf-section--tint { background: var(--odf-tint); }
/* Surface-wash band (the one green-soft moment per page). A washed section
   keeps its own top padding even mid-flow, and hands padding back to the
   section that follows it - otherwise content sits flush on the band edge. */
.odf-section.odf-section--wash { background: var(--odf-green-soft); padding-block: var(--odf-section-gap); }
.odf-section--wash + .odf-section { padding-top: var(--odf-section-gap); }

/* Section heading with eyebrow */
.odf-eyebrow {
	display: inline-flex; align-items: center; gap: var(--odf-sp-2);
	font-size: var(--odf-fs-xs); font-weight: 700; text-transform: uppercase;
	letter-spacing: var(--odf-tracking-wide); color: var(--odf-green);
	margin-bottom: var(--odf-sp-3);
}
.odf-eyebrow::before { content: ""; width: 22px; height: 2px; border-radius: 2px; background: var(--odf-green); }
/* .odf-section__head retired - templates render odf_section_header()
   (.odf-sechead, the ONE section header - see the design-backbone block). */
.odf-section__cta { display: flex; justify-content: center; margin-top: var(--odf-sp-5); }

/* Designed empty states: one helpful sentence + one action. */
.odf-emptystate { text-align: center; max-width: 480px; margin: var(--odf-sp-6) auto; padding: var(--odf-sp-7); background: var(--odf-tint); border: 1px solid var(--odf-line); border-radius: var(--odf-radius-lg); }
/* The dog mark on PAGE-level dead ends only (no results, no matches, 404) -
   the moments where someone is actually stuck. Muted, not decorative: it is
   there to make an empty page feel designed rather than broken, so it sits
   behind the message in weight, never in front of it. */
.odf-emptystate--mark { padding-top: var(--odf-sp-6); }
.odf-emptystate__mark { display: flex; justify-content: center; margin-bottom: var(--odf-sp-4); color: color-mix(in srgb, var(--odf-green) 32%, transparent); }
.odf-emptystate__mark .odf-dogmark { display: block; }
.odf-404__mark { display: flex; justify-content: center; margin-bottom: var(--odf-sp-4); color: color-mix(in srgb, var(--odf-green) 32%, transparent); }
@media (max-width: 600px) {
	.odf-emptystate__mark .odf-dogmark, .odf-404__mark .odf-dogmark { width: 62px; height: auto; }}
.odf-emptystate__title { font-weight: 800; font-size: var(--odf-fs-base); color: var(--odf-ink); margin: 0 0 var(--odf-sp-2); }
.odf-emptystate__text { color: var(--odf-ink-2); font-size: var(--odf-fs-sm); margin: 0 0 var(--odf-sp-4); }
.odf-emptystate__actions { display: flex; gap: var(--odf-sp-2); justify-content: center; flex-wrap: wrap; }

/* --- Skip link --- */
.odf-skip-link { position: absolute; left: -9999px; top: 0; z-index: 100; background: var(--odf-ink); color: #fff; padding: var(--odf-sp-2) var(--odf-sp-4); border-radius: 0 0 var(--odf-radius-sm) 0; }
.odf-skip-link:focus { left: 0; }

/* --- Header (minimal: logo, nav, search, sign-in; sticky) --- */
.odf-header {
	position: sticky; top: 0; z-index: var(--odf-z-header);
	background: rgba(255, 255, 255, .85);
	backdrop-filter: saturate(180%) blur(12px);
	border-bottom: 1px solid var(--odf-line);
}
/* Floating pill nav on desktop/tablet (founder ask 28 Jul 2026): centred,
   rounded, narrower than the page. The founder's three properties, plus the
   supporting cast a pill needs: a full border (a bottom-only border reads as a
   glitch on rounded corners), a small top inset so the radius is visible
   against the viewport edge, and a soft shadow so it reads as floating over
   the content scrolling behind the blur. Phones keep the full-width bar - a
   pill at 390px wastes tap space. */
@media (min-width: 769px) {
	.odf-header {
		margin: auto;
		max-width: calc(var(--odf-container) - 3rem);
		border-radius: 50px;
		top: 10px;
		border: 1px solid var(--odf-line);
		box-shadow: var(--odf-shadow-soft);
	}}
.odf-header__inner { display: flex; align-items: center; gap: var(--odf-sp-5); min-height: 68px; position: relative; }
/* Wordmark: lowercase, tight tracking, heavy + gold dot. */
.odf-brand { font-family: var(--odf-font-sans); font-size: var(--odf-fs-lg); font-weight: 800; color: var(--odf-ink); letter-spacing: -.04em; display: inline-flex; align-items: center; }
.odf-brand:hover { color: var(--odf-ink); }
.odf-brand__dot { width: 8px; height: 8px; border-radius: 50%; background: var(--odf-gold); margin-left: 3px; align-self: flex-end; margin-bottom: 6px; }
/* EXPLICIT height, not max-height: an SVG has no intrinsic size, so `max-height`
   plus `width: auto` collapses it to nothing. object-fit: contain keeps a wide
   wordmark whole instead of cropping it. */
.odf-brand__logo { height: 30px; width: auto; max-width: 230px; object-fit: contain; display: block; }
.odf-nav { margin: auto; display: flex; align-items: center; }
.odf-nav__menu { list-style: none; margin: 0; padding: 0; display: flex; gap: var(--odf-sp-6); align-items: center; }
.odf-nav__menu > li { position: relative; }
.odf-nav a { position: relative; color: var(--odf-ink-2); font-size: var(--odf-fs-md); font-weight: 700; display: inline-flex; align-items: center; gap: 4px; padding-block: 4px; }
.odf-nav a:hover { color: var(--odf-ink); }
/* Active section: ink text + a short green underline (identity colour). */
.odf-nav__menu > .current-menu-item > a,
.odf-nav__menu > .current-menu-ancestor > a,
.odf-nav__menu > .current_page_item > a,
.odf-nav a[aria-current="page"] { color: var(--odf-ink); font-weight: 700; }
.odf-nav__menu > .current-menu-item > a::after,
.odf-nav__menu > .current-menu-ancestor > a::after,
.odf-nav__menu > .current_page_item > a::after,
.odf-nav a[aria-current="page"]::after { content: ""; position: absolute; left: 0; right: 0; bottom: -2px; height: 2px; border-radius: 2px; background: var(--odf-green); }
/* Simple dropdown submenus (no mega-menu - design brief). */
.odf-nav__menu .sub-menu { list-style: none; margin: 0; padding: var(--odf-sp-2); position: absolute; top: 100%; left: 0; min-width: 200px; background: var(--odf-card); border: 1px solid var(--odf-line); border-radius: var(--odf-radius); box-shadow: var(--odf-shadow); opacity: 0; visibility: hidden; transform: translateY(8px); transition: opacity var(--odf-dur) var(--odf-ease), transform var(--odf-dur) var(--odf-ease); z-index: var(--odf-z-nav); }
.odf-nav__menu li:hover > .sub-menu, .odf-nav__menu li:focus-within > .sub-menu { opacity: 1; visibility: visible; transform: translateY(4px); }
.odf-nav__menu .sub-menu a { display: block; padding: var(--odf-sp-2) var(--odf-sp-3); border-radius: var(--odf-radius-sm); }
.odf-nav__menu .sub-menu a:hover { background: var(--odf-green-soft); }

/* Mega-menu panels (Dog food / Best / Can dogs eat...?). Desktop only - the
   whole .odf-nav is display:none under the burger breakpoint. */
/* Every mega panel opens in the SAME place: centred under the header bar
   (founder 2026-07-17d - "opens randomly in different location"). Anchored to
   .odf-header__inner (a centred container), not the hovered <li>, so all three
   panels share one position + width. */
.odf-mega {
	position: absolute;
	top: 100%;
	left: 50%;
	transform: translateX(-50%) translateY(8px);
	/* One consistent width for every panel; wide enough that no label overflows. */
	width: 780px;
	max-width: calc(100vw - 40px);
	display: flex;
	gap: var(--odf-sp-4);
	padding: var(--odf-sp-5);
	background: var(--odf-card);
	border: 1px solid var(--odf-line);
	border-radius: var(--odf-radius);
	box-shadow: var(--odf-shadow);
	opacity: 0;
	visibility: hidden;
	transition: opacity var(--odf-dur) var(--odf-ease), transform var(--odf-dur) var(--odf-ease);
	z-index: var(--odf-z-nav);
}
/* The <li> must NOT be the positioning context (that made each panel anchor to
   its own item = the "random location"); the panel resolves against the
   position:relative .odf-header__inner instead. NB: needs to out-specify
   `.odf-nav__menu > li { position: relative }`, hence the child selector. */
.odf-nav__menu > .odf-mega-parent { position: static; }
/* Invisible hover bridge across the gap between the nav bar and the panel. */
.odf-mega::before { content: ""; position: absolute; left: 0; right: 0; top: -28px; height: 28px; }
/* Dropdown caret is a real inline SVG (.odf-nav__caret) - see header.php - so it
   never fights the active-page underline (both would be ::after otherwise). */
.odf-nav__caret { flex: 0 0 auto; margin-left: 2px; opacity: .5; transition: transform var(--odf-dur) var(--odf-ease); }
.odf-mega-parent:hover > a .odf-nav__caret,
.odf-mega-parent:focus-within > a .odf-nav__caret { transform: rotate(180deg); opacity: .8; }
.odf-mega-parent:hover > .odf-mega,
.odf-mega-parent:focus-within > .odf-mega { opacity: 1; visibility: visible; transform: translateX(-50%) translateY(4px); }
.odf-mega__col { flex: 1 1 0; min-width: 0; }
.odf-mega__col--feature { flex: 0 0 210px; align-self: stretch; background: var(--odf-green-soft); border-radius: var(--odf-radius-sm); padding: var(--odf-sp-4); }
.odf-mega__head { display: block; font-size: var(--odf-fs-xs); font-weight: 700; text-transform: uppercase; letter-spacing: .05em; color: var(--odf-ink-3); margin-bottom: var(--odf-sp-2); }
.odf-mega__list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 1px; }
.odf-mega__list a { display: flex; align-items: center; gap: var(--odf-sp-2); padding: 6px 8px; border-radius: var(--odf-radius-sm); font-size: var(--odf-fs-md); font-weight: 600; color: var(--odf-ink-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.odf-mega__list a:hover { background: var(--odf-green-soft); color: var(--odf-green); }
.odf-mega__col--feature .odf-mega__list a:hover { background: var(--odf-card); }
.odf-mega__ico { flex: 0 0 auto; color: var(--odf-green); }
.odf-mega__grid { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 1px var(--odf-sp-4); width: 100%; }
.odf-mega__grid a { display: flex; align-items: center; gap: var(--odf-sp-2); padding: 6px 8px; border-radius: var(--odf-radius-sm); font-size: var(--odf-fs-md); font-weight: 600; color: var(--odf-ink-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* The Best panel carries full keyword phrases ("Best dog food for joints and
   mobility"), which need ~250px of text width. Three columns of a 780px panel
   leave ~190px, so they would ellipsise - two columns give ~300px and fit. */
.odf-mega--best .odf-mega__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
/* The panel is a flex ROW by default (the CDE panel needs columns side by side),
   so the see-all link would land to the right of the grid instead of under it. */
.odf-mega--best { flex-direction: column; align-items: stretch; gap: var(--odf-sp-3); }
.odf-mega__more--foot { padding-top: var(--odf-sp-3); border-top: 1px solid var(--odf-line); }
.odf-mega__grid a:hover { background: var(--odf-green-soft); color: var(--odf-green); }
.odf-mega--cde .odf-mega__col--safe .odf-mega__head { color: var(--odf-green); }
.odf-mega--cde .odf-mega__col--never .odf-mega__head { color: #b3261e; }
/* Every dropdown link is icon + text: the label span truncates, the icon never shrinks. */
.odf-mega__list a span, .odf-mega__grid a span { overflow: hidden; text-overflow: ellipsis; min-width: 0; }
.odf-mega--cde .odf-mega__col--safe .odf-mega__ico { color: var(--odf-green); }
.odf-mega--cde .odf-mega__col--never .odf-mega__ico { color: #b3261e; }
.odf-mega__blurb { font-size: var(--odf-fs-sm); color: var(--odf-ink-3); margin: 0 0 var(--odf-sp-3); max-width: 210px; line-height: 1.5; }
.odf-mega__more { display: inline-flex; align-items: center; gap: 5px; font-size: var(--odf-fs-md); font-weight: 700; color: var(--odf-green); }
.odf-mega__more:hover { color: var(--odf-green); text-decoration: underline; }

/* Header utility cluster (search icon, sign-in). */
.odf-header__util { display: flex; align-items: center; gap: var(--odf-sp-3); margin-left: auto; }
.odf-header__iconlink { display: inline-flex; align-items: center; justify-content: center; width: 40px; height: 40px; border-radius: var(--odf-radius-pill); color: var(--odf-ink-2); }
.odf-header__iconlink:hover { background: var(--odf-tint); color: var(--odf-ink); }

/* --- Account dropdown (signed-out header) ---------------------------------
   Opens on hover, keyboard focus AND click (.is-open from theme.js). Animated
   with opacity+lift; visibility delays on close so the fade completes. The
   ::before bridge spans the 8px gap - without it the menu closes while the
   cursor travels from button to menu (the TC lesson). Lives INSIDE the sticky
   header, so it ranks with --odf-z-nav like the mega menu. */
.odf-accdrop { position: relative; }
.odf-accdrop__btn { display: inline-flex; align-items: center; gap: 6px; }
.odf-accdrop__chev { transition: transform .18s var(--odf-ease); }
.odf-accdrop__menu {
	position: absolute; top: calc(100% + 8px); right: 0; z-index: var(--odf-z-nav);
	min-width: 230px; padding: 6px;
	background: var(--odf-card); border: 1px solid var(--odf-line);
	border-radius: var(--odf-radius); box-shadow: var(--odf-shadow);
	opacity: 0; visibility: hidden; transform: translateY(6px);
	transition: opacity var(--odf-dur) var(--odf-ease), transform var(--odf-dur) var(--odf-ease), visibility 0s linear var(--odf-dur);
}
.odf-accdrop__menu::before { content: ""; position: absolute; top: -10px; left: 0; right: 0; height: 10px; }
.odf-accdrop:hover .odf-accdrop__menu,
.odf-accdrop:focus-within .odf-accdrop__menu,
.odf-accdrop.is-open .odf-accdrop__menu {
	opacity: 1; visibility: visible; transform: translateY(0); transition-delay: 0s;
}
.odf-accdrop:hover .odf-accdrop__chev,
.odf-accdrop.is-open .odf-accdrop__chev { transform: rotate(180deg); }
.odf-accdrop__menu a { display: flex; flex-direction: column; gap: 1px; padding: 9px 12px; border-radius: var(--odf-radius-sm); color: var(--odf-ink); }
.odf-accdrop__menu a:hover { background: var(--odf-tint); color: var(--odf-ink); }
.odf-accdrop__menu strong { font-size: var(--odf-fs-sm); }
.odf-accdrop__menu a span { font-size: var(--odf-fs-xs); color: var(--odf-ink-3); }
.odf-accdrop__brands { border-top: 1px solid var(--odf-line); border-radius: 0 0 var(--odf-radius-sm) var(--odf-radius-sm); margin-top: 4px; padding-top: 11px; }
.odf-accdrop__brands strong { color: var(--odf-green-deep); }

/* --- Hamburger + mobile nav --- */
.odf-burger { display: none; flex-direction: column; gap: 5px; width: 44px; height: 44px; align-items: center; justify-content: center; background: transparent; border: 0; cursor: pointer; }
.odf-burger span { width: 24px; height: 2px; background: var(--odf-ink); border-radius: 2px; transition: transform var(--odf-dur) var(--odf-ease), opacity var(--odf-dur) var(--odf-ease); }
.odf-mobile-nav { display: none; border-top: 1px solid var(--odf-line); background: var(--odf-card); }
.odf-mobile-nav .odf-container { display: flex; flex-direction: column; padding-block: var(--odf-sp-2); }
.odf-mobile-nav a { padding: var(--odf-sp-3) 0; font-weight: 600; color: var(--odf-ink); border-bottom: 1px solid var(--odf-line); }
.odf-mobile-nav a:last-child { border-bottom: 0; }
.odf-mobile-nav a[aria-current="page"] { color: var(--odf-green); }

/* Expandable groups in the drawer (Dog food / Best dog food). <details> so it
   works with no JS; closed by default so the drawer stays short. */
.odf-mnav__grp { border-bottom: 1px solid var(--odf-line); }
.odf-mnav__grp > summary {
	list-style: none; cursor: pointer;
	display: flex; align-items: center; justify-content: space-between; gap: var(--odf-sp-2);
	padding: var(--odf-sp-3) 0; font-weight: 600; color: var(--odf-ink);
}
.odf-mnav__grp > summary::-webkit-details-marker { display: none; }
.odf-mnav__chev { color: var(--odf-ink-3); flex: none; transition: transform var(--odf-dur) var(--odf-ease); }
.odf-mnav__grp[open] > summary .odf-mnav__chev { transform: rotate(180deg); }
/* flex column: the drawer's anchors are inline, and the parent .odf-container
   is what stacks the top-level ones - without this the sub-links ran together
   on one line ("DryWetRawCold-pressed"). */
.odf-mnav__sub { display: flex; flex-direction: column; padding: 0 0 var(--odf-sp-3) var(--odf-sp-3); border-left: 2px solid var(--odf-green-soft); margin-left: 2px; }
.odf-mobile-nav .odf-mnav__sub a { border-bottom: 0; padding: var(--odf-sp-2) 0; font-weight: 500; color: var(--odf-ink-2); }
.odf-mobile-nav .odf-mnav__sub a:hover { color: var(--odf-green); }
.odf-mobile-nav .odf-mnav__sublink--all { font-weight: 700; color: var(--odf-green); }
.odf-mnav__head {
	display: block; margin-top: var(--odf-sp-2);
	font-size: var(--odf-fs-xs); font-weight: 700; text-transform: uppercase;
	letter-spacing: var(--odf-tracking-wide); color: var(--odf-ink-3);
}
body.odf-mobile-open .odf-mobile-nav { display: block; }
body.odf-mobile-open .odf-burger span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
body.odf-mobile-open .odf-burger span:nth-child(2) { opacity: 0; }
body.odf-mobile-open .odf-burger span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }
@media (max-width: 768px) { .odf-burger { display: flex; }}


/* --- Buttons (one primary action per screen: gold is for THE action;
       secondary actions wear the identity green) --- */
.odf-btn {
	display: inline-flex; align-items: center; justify-content: center; gap: var(--odf-sp-2);
	font-weight: 700; font-size: var(--odf-fs-base); line-height: 1;
	padding: 0.85rem 1.4rem; border-radius: var(--odf-radius-pill); border: 0; cursor: pointer;
	transition: transform var(--odf-dur) var(--odf-ease), box-shadow var(--odf-dur) var(--odf-ease), background var(--odf-dur) var(--odf-ease);
}
.odf-btn:hover { transform: translateY(-1px); }
.odf-btn:active { transform: translateY(0); }
.odf-btn svg { width: 18px; height: 18px; }
/* Dark text on gold, NOT white. White on our gold is 2.94:1 (fails WCAG AA) and
   can't be fixed without turning the gold into a dark brown - so the accessible
   answer for a gold/amber button is dark ink, which is 6.04:1 here. Hover stays
   a light-enough gold (#bd7f15) that dark text keeps 5.25:1; gold-deep (#a86f10)
   would drop dark text to 4.18 and fail, which is why hover is NOT gold-deep. */
.odf-btn--primary { background: var(--odf-gold); color: var(--odf-ink); box-shadow: var(--odf-shadow-xs); }
.odf-btn--primary:hover { background: #bd7f15; color: var(--odf-ink); }
.odf-btn--dark { background: var(--odf-ink); color: #fff; }
.odf-btn--dark:hover { color: #fff; }
.odf-btn--ghost { background: var(--odf-green-soft); color: var(--odf-green-deep); }
.odf-btn--ghost:hover { color: var(--odf-ink); }
.odf-btn--outline { background: var(--odf-card); color: var(--odf-ink); box-shadow: inset 0 0 0 1.5px var(--odf-line); }
.odf-btn--outline:hover { box-shadow: inset 0 0 0 1.5px var(--odf-green); color: var(--odf-green-deep); }
.odf-btn--sm { padding: 0.5rem 0.9rem; font-size: var(--odf-fs-sm); }

/* --- Hero (search-first) --- */
/* No overflow:hidden here - it would clip the search autocomplete dropdown.
   Homepage hero is CENTERED (mockup): contained measure, centered search box.
   Page heroes (--page) stay left-aligned. */
/* DENSITY pass rule 1: hero block padding capped at 40px. */
.odf-hero { position: relative; padding-block: var(--odf-sp-6) var(--odf-sp-7); text-align: center; }
.odf-hero h1 { font-size: var(--odf-fs-3xl); max-width: 21ch; margin-inline: auto; margin-bottom: var(--odf-sp-4); text-wrap: balance; }
.odf-hero h1 em { font-style: normal; color: var(--odf-green); }
.odf-hero__lead { font-size: var(--odf-fs-lg); color: var(--odf-ink-2); max-width: 52ch; margin-inline: auto; margin-bottom: var(--odf-sp-5); }
.odf-hero .odf-search { margin-inline: auto; }
.odf-hero .odf-trust-strip, .odf-hero .odf-popular { justify-content: center; }
/* Hub hero: .odf-hero--hub is the odf_hero() name; --page is the legacy alias
   still on templates awaiting the re-lay pass. .odf-hero--home is the helper's
   name for the centered default (no extra rules needed). */
.odf-hero--page, .odf-hero--hub, .odf-hero--entity { padding-block: var(--odf-sp-6); text-align: left; }
.odf-hero--page h1, .odf-hero--hub h1, .odf-hero--entity h1 { max-width: none; margin-inline: 0; }
.odf-hero--page .odf-hero__lead, .odf-hero--page .odf-search,
.odf-hero--hub .odf-hero__lead, .odf-hero--hub .odf-search,
.odf-hero--entity .odf-hero__lead, .odf-hero--entity .odf-search { margin-inline: 0; }
.odf-hero--page .odf-trust-strip, .odf-hero--page .odf-popular,
.odf-hero--hub .odf-trust-strip, .odf-hero--hub .odf-popular { justify-content: flex-start; }

/* Search box (homepage hero + header search) */
.odf-search {
	/* relative so the type-ahead panel (.odf-sg, appended here by search.js)
	   spans the WHOLE bar. It used to anchor to .odf-search__field, which is
	   only as wide as the text input, leaving a cramped narrow dropdown. The
	   panel is absolutely positioned, so it never becomes a flex item. */
	position: relative;
	display: flex; gap: var(--odf-sp-2); flex-wrap: wrap;
	background: var(--odf-card); padding: var(--odf-sp-2); border-radius: var(--odf-radius-xl);
	box-shadow: var(--odf-shadow); border: 1px solid var(--odf-line);
	max-width: 640px;
}
.odf-search__field { position: relative; flex: 1 1 200px; display: flex; align-items: center; }
.odf-search__field svg { position: absolute; left: 14px; width: 18px; height: 18px; color: var(--odf-ink-3); pointer-events: none; }
.odf-search input {
	width: 100%; border: 1.5px solid var(--odf-line); background: var(--odf-card); border-radius: var(--odf-radius);
	padding: 0.95rem 1rem 0.95rem 2.6rem; font-size: var(--odf-fs-base); color: var(--odf-ink);
}
.odf-search input:focus { outline: none; border-color: var(--odf-green); }
.odf-search .odf-btn { flex: 0 0 auto; }
.odf-trust-strip { margin-top: var(--odf-sp-5); font-size: var(--odf-fs-sm); color: var(--odf-ink-3); display: inline-flex; align-items: center; gap: var(--odf-sp-2); }
.odf-trust-strip svg { width: 16px; height: 16px; color: var(--odf-band-verygood); }

/* Autocomplete dropdown */
.odf-suggest { list-style: none; margin: 0; padding: 6px; position: absolute; top: calc(100% + 6px); left: 0; right: 0; background: var(--odf-card); border: 1px solid var(--odf-line); border-radius: var(--odf-radius); box-shadow: var(--odf-shadow); z-index: var(--odf-z-popover); display: none; max-height: 320px; overflow: auto; }
.odf-suggest.is-open { display: block; }
.odf-suggest__item { padding: var(--odf-sp-2) var(--odf-sp-3); border-radius: var(--odf-radius-sm); cursor: pointer; font-size: var(--odf-fs-sm); color: var(--odf-ink); }
.odf-suggest__item:hover, .odf-suggest__item.is-active { background: var(--odf-green-soft); color: var(--odf-ink); }

/* Popular searches / quick-start chips */
.odf-popular { display: flex; flex-wrap: wrap; align-items: center; gap: var(--odf-sp-2); margin-top: var(--odf-sp-4); }
.odf-popular__label { font-size: var(--odf-fs-sm); color: var(--odf-ink-3); font-weight: 700; }
.odf-popular__chip { font-size: var(--odf-fs-sm); font-weight: 600; padding: 6px 12px; border-radius: var(--odf-radius-pill); background: var(--odf-card); border: 1px solid var(--odf-line); color: var(--odf-ink-2); }
.odf-popular__chip:hover { border-color: var(--odf-green); color: var(--odf-green-deep); background: var(--odf-green-soft); }

/* --- Cards / grid --- */
.odf-grid { display: grid; gap: var(--odf-sp-5); }
.odf-grid--2 { grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); }
.odf-grid--3 { grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); }
.odf-grid--4 { grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); }

.odf-card {
	position: relative; background: var(--odf-card); border: 1px solid var(--odf-line);
	border-radius: var(--odf-radius-card); padding: var(--odf-sp-4); /* DENSITY rule 1: sp-4, not sp-5/6. */
	box-shadow: var(--odf-shadow-card);
	transition: transform var(--odf-dur) var(--odf-ease), box-shadow var(--odf-dur) var(--odf-ease), border-color var(--odf-dur) var(--odf-ease);
}
.odf-card:hover { transform: translateY(-3px); box-shadow: var(--odf-shadow-lift); border-color: var(--odf-green); }

/* Generic tile (quick-start facets, tools) */
.odf-tile { display: flex; flex-direction: column; gap: var(--odf-sp-3); }
.odf-tile__icon { width: 54px; height: 54px; border-radius: var(--odf-radius); display: grid; place-items: center; background: var(--odf-green-soft); color: var(--odf-green-deep); }
.odf-tile__icon svg { width: 30px; height: 30px; }
.odf-tile:hover .odf-tile__icon { background: var(--odf-green); color: #fff; }
.odf-tile-title { font-weight: 800; font-size: var(--odf-fs-base); color: var(--odf-ink); margin: 0; }
.odf-tile-sub { color: var(--odf-ink-3); font-size: var(--odf-fs-sm); margin-top: auto; }
.odf-tile__arrow { position: absolute; top: var(--odf-sp-5); right: var(--odf-sp-5); color: var(--odf-line); transition: transform var(--odf-dur) var(--odf-ease), color var(--odf-dur) var(--odf-ease); }
.odf-tile__arrow svg { width: 20px; height: 20px; }
.odf-card:hover .odf-tile__arrow { color: var(--odf-green); transform: translateX(3px); }

/* Stretched link: whole card clickable to its primary destination. */
.odf-card__link::after { content: ""; position: absolute; inset: 0; z-index: 1; }

/* --- Numbers / prices --- */
.odf-num { font-weight: 800; color: var(--odf-ink); letter-spacing: -.02em; font-variant-numeric: tabular-nums; }

/* --- Pills (type / life-stage / property chips) --- */
.odf-pill {
	display: inline-flex; align-items: center; gap: 4px;
	font-size: var(--odf-fs-xs); font-weight: 700; padding: 3px 9px;
	border-radius: var(--odf-radius-pill); letter-spacing: .02em;
	background: var(--odf-tint); color: var(--odf-ink-2);
}
.odf-pill svg { width: 12px; height: 12px; }
.odf-pill--gold { background: var(--odf-gold-soft); color: var(--odf-gold-deep); }
.odf-pill--green { background: var(--odf-green-soft); color: var(--odf-green-deep); }

/* --- Score bands ---
   Functional scale only. The number + band label ALWAYS accompany the colour
   (accessibility / colour-blind rule). Applied via .odf-band--{band} on chips,
   dial strokes and breakdown rows. */
.odf-band--exceptional { --odf-band: var(--odf-band-exceptional); }
.odf-band--verygood    { --odf-band: var(--odf-band-verygood); }
.odf-band--good        { --odf-band: var(--odf-band-good); }
.odf-band--average     { --odf-band: var(--odf-band-average); }
.odf-band--poor        { --odf-band: var(--odf-band-poor); }
.odf-band--avoid       { --odf-band: var(--odf-band-avoid); }
/* .odf-scorechip retired - odf_score_badge( $score, 'text' ) is the inline
   number + label form (.odf-scorebadge--text, design-backbone block). */

/* --- Star rating (overlay technique: grey base + clipped gold fill) --- */
.odf-rating { display: inline-flex; align-items: center; gap: var(--odf-sp-2); flex-wrap: wrap; }
.odf-rating__stars { position: relative; display: inline-block; line-height: 0; font-size: 0; white-space: nowrap; }
.odf-rating__base { color: var(--odf-line); }
.odf-rating__base, .odf-rating__fill { display: block; white-space: nowrap; line-height: 0; }
.odf-rating__fill { color: var(--odf-gold); position: absolute; top: 0; left: 0; overflow: hidden; width: 0; }
.odf-rating .odf-star { display: inline-block; vertical-align: top; width: 17px; height: 17px; }
.odf-rating__num { font-weight: 800; color: var(--odf-ink); font-size: var(--odf-fs-sm); }
.odf-rating__meta { font-size: var(--odf-fs-xs); color: var(--odf-ink-3); }
.odf-rating--compact { gap: 6px; }
.odf-rating--compact .odf-star { width: 14px; height: 14px; }

/* --- Breadcrumbs (ONE styled component sitewide: odf_breadcrumbs()) ---
   Slash separators, hover states, muted current page; on mobile the trail
   scrolls horizontally under a soft fade edge instead of wrapping. */
.odf-breadcrumbs { position: relative; margin-bottom: var(--odf-sp-4); font-size: var(--odf-fs-sm); color: var(--odf-ink-3); }
.odf-breadcrumbs__list { list-style: none; margin: 0; padding: 0; display: flex; align-items: center; flex-wrap: nowrap; overflow-x: auto; white-space: nowrap; scrollbar-width: none; }
.odf-breadcrumbs__list::-webkit-scrollbar { display: none; }
.odf-breadcrumbs__item { display: inline-flex; align-items: center; flex: none; }
.odf-breadcrumbs__item + .odf-breadcrumbs__item::before { content: "/"; margin: 0 var(--odf-sp-2); color: var(--odf-line); }
.odf-breadcrumbs a { color: var(--odf-ink-2); }
.odf-breadcrumbs a:hover { color: var(--odf-ink); text-decoration: underline; text-underline-offset: 3px; }
.odf-breadcrumbs__current { color: var(--odf-ink-3); }
@media (max-width: 768px) {
	.odf-breadcrumbs::after { content: ""; position: absolute; top: 0; right: 0; bottom: 0; width: 36px; pointer-events: none; background: linear-gradient(to right, transparent, var(--odf-surface)); }}

/* --- Entry content rhythm --- */
.odf-entry > section { margin-bottom: var(--odf-section-gap); } /* one rhythm token (Phase 1b) */
.odf-entry h2 { margin-bottom: var(--odf-sp-4); }
.odf-content { max-width: var(--odf-container-narrow); margin-inline: auto; }
.odf-content img { border-radius: var(--odf-radius); }
.odf-prose { max-width: var(--odf-measure); }

/* --- Generic data table (retailer prices, brand product lists, nutrition) --- */
.odf-table-wrap { margin: var(--odf-sp-6) 0; background: var(--odf-card); border: 1px solid var(--odf-line); border-radius: var(--odf-radius-lg); box-shadow: var(--odf-shadow-xs); overflow-x: auto; }
.odf-table { width: 100%; border-collapse: collapse; font-size: var(--odf-fs-md); }
.odf-table caption { text-align: left; font-weight: 800; color: var(--odf-ink); font-size: var(--odf-fs-base); padding: var(--odf-sp-4) var(--odf-sp-5); background: var(--odf-tint); border-bottom: 1px solid var(--odf-line); }
.odf-table thead th { text-align: left; font-size: var(--odf-fs-xs); text-transform: uppercase; letter-spacing: .05em; color: var(--odf-ink-3); border-bottom: 1px solid var(--odf-line); padding: 12px var(--odf-sp-5); }
.odf-table tbody th, .odf-table tbody td { padding: 13px var(--odf-sp-5); border-bottom: 1px solid var(--odf-line); vertical-align: middle; font-variant-numeric: tabular-nums; }
.odf-table tbody tr:last-child th, .odf-table tbody tr:last-child td { border-bottom: 0; }
.odf-table tbody th { text-align: left; font-weight: 800; color: var(--odf-ink); }
.odf-table tbody tr:hover { background: var(--odf-tint); }
.odf-table__note { font-size: var(--odf-fs-xs); color: var(--odf-ink-3); margin: 0; padding: var(--odf-sp-3) var(--odf-sp-5); background: var(--odf-tint); border-top: 1px solid var(--odf-line); }
@media (max-width: 560px) {
	.odf-table { font-size: var(--odf-fs-sm); }
	.odf-table caption, .odf-table thead th, .odf-table tbody th, .odf-table tbody td, .odf-table__note { padding-inline: var(--odf-sp-3); }}

/* --- Forms (generic primitives; dashboards get more in app.css) --- */
.odf-fld { display: block; margin-bottom: var(--odf-sp-3); }
.odf-fld > span { display: block; font-size: var(--odf-fs-sm); font-weight: 600; color: var(--odf-ink); margin-bottom: 4px; }
.odf-input, .odf-fld input:not([type=checkbox]):not([type=radio]), .odf-fld textarea, .odf-fld select {
	width: 100%; padding: 10px 12px; border-radius: var(--odf-radius-sm);
	border: 1.5px solid var(--odf-line); background: var(--odf-card); color: var(--odf-ink);
	font-size: var(--odf-fs-base);
}
.odf-input:focus, .odf-fld input:focus, .odf-fld textarea:focus, .odf-fld select:focus { outline: none; border-color: var(--odf-green); box-shadow: var(--odf-ring); }

.odf-agree { display: flex; flex: 1 1 100%; width: 100%; gap: 8px; align-items: flex-start; font-size: var(--odf-fs-sm); color: var(--odf-ink-2); margin: 8px 0; line-height: 1.5; }
.odf-agree input[type="checkbox"] { margin: 3px 0 0; flex: 0 0 auto; width: 16px; height: 16px; }
.odf-agree a { color: var(--odf-green); text-decoration: underline; }

/* --- Chips (facet links, related items) --- */
.odf-chips { display: flex; flex-wrap: wrap; gap: var(--odf-sp-2); margin-top: var(--odf-sp-2); }
.odf-chip { display: inline-flex; align-items: center; gap: 6px; padding: 0.5rem 1rem; background: var(--odf-card); border: 1px solid var(--odf-line); color: var(--odf-ink-2); border-radius: var(--odf-radius-pill); font-size: var(--odf-fs-sm); font-weight: 600; }
.odf-chip svg { width: 14px; height: 14px; color: var(--odf-green); }
.odf-chip:hover { border-color: var(--odf-green); color: var(--odf-green-deep); background: var(--odf-green-soft); }

/* --- FAQ accordion --- */
.odf-faq { margin-top: var(--odf-sp-5); }
.odf-faq__item { border: 1px solid var(--odf-line); border-radius: var(--odf-radius); padding: var(--odf-sp-4) var(--odf-sp-5); margin-bottom: var(--odf-sp-3); background: var(--odf-card); transition: box-shadow var(--odf-dur) var(--odf-ease); }
.odf-faq__item[open] { box-shadow: var(--odf-shadow-xs); }
.odf-faq__item summary { font-weight: 700; cursor: pointer; color: var(--odf-ink); list-style: none; display: flex; justify-content: space-between; align-items: center; gap: var(--odf-sp-3); }
.odf-faq__item summary::-webkit-details-marker { display: none; }
.odf-faq__item summary::after { content: "+"; font-size: 1.4rem; color: var(--odf-green); font-weight: 400; transition: transform var(--odf-dur) var(--odf-ease); }
.odf-faq__item[open] summary::after { transform: rotate(45deg); }
.odf-faq__a { margin-top: var(--odf-sp-3); color: var(--odf-ink-2); line-height: var(--odf-lh-base); }


/* --- Guides (cards, article body, TOC, byline) --- */
.odf-card.odf-guide-card { padding: 0; overflow: hidden; display: flex; flex-direction: column; }
.odf-card.odf-guide-card:hover .odf-guide-card__title { color: var(--odf-green); }
.odf-grid--guides { grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); } /* shared components carry their own margins; the flex gap owns spacing here */

/* Rail card shell (TOC + CTA reuse it). */
.odf-guidenav {
	background: var(--odf-card);
	border: 1px solid var(--odf-line);
	border-radius: var(--odf-radius-lg);
	padding: var(--odf-sp-4);
	box-shadow: var(--odf-shadow-xs);
}
.odf-guidenav__title {
	margin: 0 0 var(--odf-sp-3);
	font-size: var(--odf-fs-xs);
	font-weight: 800;
	text-transform: uppercase;
	letter-spacing: .05em;
	color: var(--odf-ink-3);
}

/* Social share card (sidebar + reusable inline). Round buttons that adopt each
   platform's colour on hover; "Copy link" flips green when it fires.

   The buttons used to wrap 5-then-1, stranding a lone orphan circle on its own
   line. The cause was a CONTAINER width, not the viewport: this card lives in a
   fixed 300px guide rail, so six 40px circles never fit one row however wide the
   screen - a viewport media query could not have fixed it. Six equal 1fr columns
   fit ANY container in one clean row (each button caps at 44px and centres in its
   cell), so there is no orphan and no overflow whether the card is 268px in the
   rail or 320px in the share popover. */
.odf-share { background: var(--odf-green-soft); border: 1px solid var(--odf-line); border-radius: var(--odf-radius-lg); padding: var(--odf-sp-3); }
.odf-share__title { margin: 0 0 var(--odf-sp-2); font-size: var(--odf-fs-xs); font-weight: 700; letter-spacing: .04em; text-transform: uppercase; color: var(--odf-ink-3); }
.odf-share__row { display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); gap: var(--odf-sp-2); }
.odf-share__btn { width: 100%; max-width: 44px; aspect-ratio: 1 / 1; justify-self: center; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center; background: var(--odf-card); border: 1px solid var(--odf-line); color: var(--odf-ink-2); cursor: pointer; transition: transform .12s ease, background .12s ease, color .12s ease, border-color .12s ease; }
.odf-share__btn:hover { transform: translateY(-1px); color: #fff; }
.odf-share__btn--facebook:hover { background: #1877f2; border-color: #1877f2; }
.odf-share__btn--x:hover { background: #000; border-color: #000; }
.odf-share__btn--whatsapp:hover { background: #25d366; border-color: #25d366; }
.odf-share__btn--pinterest:hover { background: #e60023; border-color: #e60023; }
.odf-share__btn--email:hover { background: var(--odf-green-deep); border-color: var(--odf-green-deep); }
.odf-share__btn--copy:hover { background: var(--odf-ink); border-color: var(--odf-ink); }
.odf-share__btn--copy.is-copied { background: var(--odf-green); border-color: var(--odf-green); color: #fff; }
.odf-share__ico { width: 18px; height: 18px; }

/* Compact Share control (product/brand hero): one button that opens the native
   OS share sheet on mobile, or a popover of the social buttons on desktop. Built
   on <details>/<summary> so it works with JS off. */
.odf-sharebtn { position: relative; display: inline-block; }
/* The <summary> is styled as an .odf-btn - kill the disclosure marker so it
   reads as a button, not a twisty. */
.odf-sharebtn__trigger { list-style: none; }
.odf-sharebtn__trigger::-webkit-details-marker { display: none; }
.odf-sharebtn__trigger::marker { content: ""; }
.odf-sharebtn__ico { width: 18px; height: 18px; }
/* The popover. Absolutely positioned so opening it never nudges the CTA row.
   Anchored to the button's LEFT edge and extending right (into the page), so it
   stays on-screen whether the button is a rightish product CTA or a left-aligned
   brand-hero control - a right-anchored popover ran off the left edge on the
   brand page. max-width clamps it to the viewport on the rare desktop-narrow
   case; phones use the native sheet, not this. */
.odf-sharebtn__pop {
	position: absolute; z-index: var(--odf-z-popover); top: calc(100% + 8px); left: 0; right: auto;
	max-width: calc(100vw - 2 * var(--odf-sp-4));
	padding: var(--odf-sp-3); background: var(--odf-card); border: 1px solid var(--odf-line);
	border-radius: var(--odf-radius-lg); box-shadow: var(--odf-shadow-card);
	animation: odf-sharepop .14s ease;
}
@keyframes odf-sharepop { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: none; } }
/* Inside the popover the share row is already framed by the popover card, so
   drop the nested .odf-share's own green panel chrome and give the six buttons a
   comfortable fixed 40px each. */
.odf-sharebtn__pop .odf-share { background: none; border: 0; padding: 0; }
.odf-sharebtn__pop .odf-share__row { grid-template-columns: repeat(6, 40px); }
@media (prefers-reduced-motion: reduce) { .odf-sharebtn__pop { animation: none; }}

/* Vet-advice disclaimer (YMYL) - unobtrusive note on guides + food pages */
.odf-disclaimer { display: flex; gap: 8px; align-items: flex-start; margin: var(--odf-sp-5) 0; padding: var(--odf-sp-3) var(--odf-sp-4); background: var(--odf-tint); border: 1px solid var(--odf-line); border-radius: var(--odf-radius); font-size: var(--odf-fs-sm); color: var(--odf-ink-3); line-height: 1.6; }
.odf-disclaimer svg { flex: 0 0 auto; color: var(--odf-ink-3); margin-top: 2px; }
.odf-disclaimer p { margin: 0; }

/* --- Pagination --- */
.page-numbers { display: inline-block; padding: 8px 14px; margin: 0 3px; border: 1px solid var(--odf-line); border-radius: var(--odf-radius-sm); font-weight: 600; color: var(--odf-ink-2); }
.page-numbers.current { background: var(--odf-ink); color: #fff; border-color: var(--odf-ink); }
a.page-numbers:hover { border-color: var(--odf-green); color: var(--odf-green-deep); }


/* --- Footer (fat: SEO links, trust pages, newsletter, disclosure) --- */
/* Newsletter band: the page's green-soft wash moment, compact + centered. */
.odf-footersub { background: var(--odf-green-soft); border-top: 1px solid var(--odf-line); padding-block: var(--odf-sp-7); }
.odf-footersub__inner { display: flex; flex-direction: column; align-items: center; text-align: center; gap: var(--odf-sp-4); }
.odf-footersub__title { font-family: var(--odf-font-display); font-weight: 700; font-size: var(--odf-fs-xl); color: var(--odf-ink); margin: 0 0 var(--odf-sp-1); }
.odf-footersub__text { color: var(--odf-ink-2); font-size: var(--odf-fs-sm); margin: 0; max-width: 52ch; }
.odf-footersub__form { width: 100%; display: flex; justify-content: center; }
/* The shortcode card melts into the band: borderless, centered, compact. */
.odf-footersub .odf-subscribe { background: transparent; border: 0; box-shadow: none; padding: 0; max-width: 560px; width: 100%; align-items: center; text-align: center; }
.odf-footersub .odf-subscribe__row { width: 100%; justify-content: center; }
.odf-footersub .odf-subscribe__field { background: var(--odf-card); }
.odf-footersub .odf-subscribe__lists { justify-content: center; }
.odf-footersub .odf-subscribe__btn { align-self: center; }

/* Dark band = the identity green gradient (never plain black). */
.odf-footer { background: var(--odf-green-deep); background-image: var(--odf-green-grad); color: rgba(231, 242, 237, .78); padding-block: var(--odf-sp-8) var(--odf-sp-5); }
.odf-footer__cols { display: grid; gap: var(--odf-sp-5) var(--odf-sp-6); grid-template-columns: 1.6fr 1fr 1fr 1fr 1fr; margin-bottom: var(--odf-sp-5); align-items: start; }
.odf-footer .odf-brand { color: #fff; }
/* Column headings pick up the light-gold accent (echoes the how-band em). */
/* 42% gold, not 62% - the richer mix measured 3.89:1 on the footer gradient,
   under WCAG AA for these column labels. This reads 4.84:1 and still warm. */
.odf-footer__h { color: color-mix(in srgb, var(--odf-gold) 42%, #fff); font-size: var(--odf-fs-sm); font-weight: 700; text-transform: uppercase; letter-spacing: var(--odf-tracking-wide); margin: 0 0 var(--odf-sp-3); }
.odf-footer a { color: rgba(231, 242, 237, .78); font-size: var(--odf-fs-sm); display: block; padding: 4px 0; }
.odf-footer a:hover { color: #fff; }
/* Disclosures: readable statements, not smallprint. .78 alpha is the floor that
   clears WCAG AA (4.5) across the whole footer gradient - .6 measured 3.41:1 on
   the light end. Do not lower it. */
.odf-footer__disclosure { border-top: 1px solid rgba(255, 255, 255, .14); padding-top: var(--odf-sp-4); display: grid; gap: var(--odf-sp-2); max-width: 100%; text-align: center; }
.odf-footer__disclosure p { margin: 0; font-size: var(--odf-fs-sm); line-height: 1.6; color: rgba(231, 242, 237, .78); }
/* Copyright left, legal right - one row, so the legal links stop floating as an
   orphaned centred strip between the columns and the baseline. */
.odf-footer__bottom { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--odf-sp-2) var(--odf-sp-4); margin-top: var(--odf-sp-4); padding-top: var(--odf-sp-3); border-top: 1px solid rgba(255, 255, 255, .1); font-size: var(--odf-fs-sm); color: rgba(231, 242, 237, .78); }
.odf-footer__legal { display: flex; flex-wrap: wrap; gap: var(--odf-sp-4); }
.odf-footer__legal a { display: inline-block; padding: 0; color: rgba(231, 242, 237, .78); font-size: var(--odf-fs-sm); }
.odf-footer__legal a:hover { color: #fff; }

/* ==========================================================================
   ODF signature components (mockup-approved: design/mockups/product-page.html
   + homepage.html). Colours come ONLY from tokens - tints are color-mix()
   derivations of the band tokens, never new hex values.
   ========================================================================== */

/* --- Prices (every amount carries data-gbp for the display-only currency
       switcher; JS conversion lands later, markup is ready now) --- */
.odf-price { font-variant-numeric: tabular-nums; white-space: nowrap; }

/* "approx." tag beside an RRP-derived cost-per-day (not a live shop price). */
.odf-approx { display: inline-block; margin-left: .25em; padding: 0 .35em; border-radius: 4px; font-size: var(--odf-fs-xs); font-weight: 600; line-height: 1.5; color: var(--odf-ink-3); background: var(--odf-surface-2, #f1f1f3); cursor: help; vertical-align: baseline; }

/* How-we-rate teaser (sidebar card 3): identity green, links the method. */
.odf-miniabout { background: var(--odf-card); border: 1px solid var(--odf-line); border-left: 3px solid var(--odf-green); border-radius: var(--odf-radius-lg); box-shadow: var(--odf-shadow-xs); padding: var(--odf-sp-4) var(--odf-sp-5); }
.odf-miniabout__h { font-size: var(--odf-fs-xs); font-weight: 700; letter-spacing: var(--odf-tracking-wide); text-transform: uppercase; color: var(--odf-green); margin: 0 0 var(--odf-sp-2); }
.odf-miniabout p { font-size: var(--odf-fs-sm); color: var(--odf-ink-2); margin: 0 0 var(--odf-sp-3); }
.odf-miniabout__link { display: inline-flex; align-items: center; gap: 5px; font-size: var(--odf-fs-sm); font-weight: 700; color: var(--odf-green); }
.odf-miniabout__link:hover { color: var(--odf-ink); }
/* Phones/small tablets: the 5-column range table's 560px min-width forced the
   whole page to scroll sideways (everything below it overflowed right). Drop the
   floor so the table fits the viewport, and hide the low-value Life stage column
   - the 4th cell in every row (thead <th> and tbody <td> both count, so
   nth-child(4) targets it consistently). overflow-x:auto on .odf-table-wrap stays
   as a safety net for any residual width. */
@media (max-width: 640px) {
	#range .odf-table { min-width: 0; }
	#range .odf-table tr > :nth-child(4) { display: none; }}

/* --- Verdict card (+ pros/cons) - editorial voice wears the green spine --- */
.odf-verdict {
	background: var(--odf-card); border: 1px solid var(--odf-line); border-left: 3px solid var(--odf-green);
	border-radius: var(--odf-radius); padding: var(--odf-sp-4) var(--odf-sp-5);
	box-shadow: var(--odf-shadow); margin-top: var(--odf-sp-4);
}
.odf-verdict__h { font-family: var(--odf-font-sans); font-size: var(--odf-fs-sm); font-weight: 700; letter-spacing: var(--odf-tracking-wide); text-transform: uppercase; color: var(--odf-ink-3); margin: 0 0 var(--odf-sp-2); }
.odf-verdict__text { font-size: var(--odf-fs-base); color: var(--odf-ink); max-width: 70ch; }
/* Two columns ONLY when both lists exist (live-browse item 3a) - a pros-only
   card renders one full-width column, never a half-empty grid. */
.odf-verdict__cols { display: grid; grid-template-columns: 1fr 1fr; gap: var(--odf-sp-4); margin-top: var(--odf-sp-3); }
.odf-verdict__cols--single { grid-template-columns: 1fr; }
@media (max-width: 640px) { .odf-verdict__cols { grid-template-columns: 1fr; }}
.odf-verdict__cols ul { list-style: none; margin: 0; padding: 0; font-size: var(--odf-fs-md); color: var(--odf-ink-2); display: flex; flex-direction: column; gap: 6px; }
.odf-verdict__cols li { padding-left: 22px; position: relative; }
.odf-verdict__pros li::before { content: "+"; position: absolute; left: 0; top: -1px; font-weight: 800; color: var(--odf-band-verygood); }
.odf-verdict__cons li::before { content: "-"; position: absolute; left: 0; top: -1px; font-weight: 800; color: var(--odf-band-average); }
.odf-verdict__meta { font-size: var(--odf-fs-sm); color: var(--odf-ink-3); margin: var(--odf-sp-3) 0 0; }

/* Section headers inside the product page. */
/* .odf-sech retired - odf_section_header() (.odf-sechead) is the one header. */
.odf-secsub { font-size: var(--odf-fs-sm); color: var(--odf-ink-3); margin: 0 0 var(--odf-sp-4); }
.odf-secsub a { text-decoration: underline; text-underline-offset: 2px; }

/* --- Ingredient pills (THE screenshot feature) --- */
.odf-ingpills { display: flex; flex-wrap: wrap; gap: var(--odf-sp-2); }
.odf-ingpill {
	display: inline-flex; align-items: baseline; gap: 5px;
	font-size: var(--odf-fs-sm); font-weight: 600; border-radius: var(--odf-radius-pill);
	padding: 6px 13px; border: 1px solid var(--odf-line);
	background: var(--odf-tint); color: var(--odf-ink-2);
}
.odf-ingpill small { font-weight: 500; opacity: .75; font-size: var(--odf-fs-xs); }
a.odf-ingpill:hover { border-color: currentColor; }
.odf-ingpill--green {
	background: color-mix(in srgb, var(--odf-band-verygood) 10%, #fff);
	border-color: color-mix(in srgb, var(--odf-band-verygood) 24%, #fff);
	color: color-mix(in srgb, var(--odf-band-exceptional) 88%, #000);
}
.odf-ingpill--amber {
	background: color-mix(in srgb, var(--odf-band-average) 12%, #fff);
	border-color: color-mix(in srgb, var(--odf-band-average) 30%, #fff);
	color: color-mix(in srgb, var(--odf-band-average) 72%, #000);
}
.odf-ingpill--red {
	background: color-mix(in srgb, var(--odf-band-avoid) 10%, #fff);
	border-color: color-mix(in srgb, var(--odf-band-avoid) 26%, #fff);
	color: color-mix(in srgb, var(--odf-band-avoid) 85%, #000);
}
.odf-inglegend { display: flex; gap: var(--odf-sp-4); font-size: var(--odf-fs-xs); color: var(--odf-ink-3); margin-top: var(--odf-sp-3); flex-wrap: wrap; }
.odf-inglegend i { display: inline-block; width: 8px; height: 8px; border-radius: var(--odf-radius-pill); margin-right: 5px; }
.odf-inglegend__green i { background: var(--odf-band-verygood); }
.odf-inglegend__amber i { background: var(--odf-band-average); }
.odf-inglegend__red i { background: var(--odf-band-avoid); }
.odf-inglegend__neutral i { background: var(--odf-line); }

/* --- Food card (ONE card design sitewide) ---
   DENSITY pass rule 9 + live-browse item 8: equal heights within any row -
   eyebrow clamps to 1 line, name clamps to 2 with 2 lines reserved, the chip
   row stays a single row, the price line pins to the card bottom and the
   score badge sits at the same top-right spot on every card. */
.odf-foodcard { padding: var(--odf-sp-4); display: flex; flex-direction: column; gap: var(--odf-sp-3); }
.odf-foodcard__head { display: flex; align-items: flex-start; gap: var(--odf-sp-3); padding-right: 54px; }
/* Packshot: a fixed box the (proportional 'medium') image is CONTAINED in, never
   cropped - tall pouches and wide trays both show whole. */
.odf-foodcard__thumb { flex: none; display: flex; align-items: center; justify-content: center; width: 52px; height: 56px; }
.odf-foodcard__thumb img { width: 100%; height: 100%; object-fit: contain; }
.odf-foodcard__titles { min-width: 0; display: flex; flex-direction: column; }
.odf-foodcard__brand { font-size: var(--odf-fs-xs); color: var(--odf-ink-3); text-transform: uppercase; letter-spacing: var(--odf-tracking-wide); font-weight: 700; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.odf-foodcard__name {
	font-weight: 700; font-size: var(--odf-fs-md); line-height: 1.3; color: var(--odf-ink);
	display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
	min-height: 2.6em; /* Reserve 2 lines - 1-line names no longer shift the row below. */
}
.odf-foodcard:hover .odf-foodcard__name { color: var(--odf-green); }
/* Wrap, not clip: the life stage is now up to three separate chips (Puppy /
   Adult / Senior) alongside the food type, so a single clipped row would hide
   the last one. */
.odf-foodcard__chips { display: flex; gap: 6px; flex-wrap: wrap; row-gap: 5px; min-height: 27px; }
.odf-foodcard__chips .odf-pill { flex: none; }
/* The card is a stretched link (.odf-card__link::after inset:0). Lift the chip
   LINKS above it so a stage chip goes to its facet, while the rest of the card
   still opens the food. Plain-pill chips stay under it and are inert. */
.odf-foodcard__chips a.odf-pill { position: relative; z-index: 2; }
.odf-foodcard__row { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center; gap: 6px var(--odf-sp-2); border-top: 1px dashed var(--odf-line); padding-top: 10px; margin-top: auto; font-size: var(--odf-fs-sm); color: var(--odf-ink-2); font-variant-numeric: tabular-nums; }
.odf-foodcard__price b { color: var(--odf-ink); }
.odf-foodcard__price--none { color: var(--odf-ink-3); font-size: var(--odf-fs-xs); }
.odf-foodcard__meat { flex: none; font-size: var(--odf-fs-xs); font-weight: 700; color: var(--odf-green-deep); background: var(--odf-green-soft); border-radius: 999px; padding: 2px 9px; white-space: nowrap; }
/* Auto-attached trait icons (active only) + hover/focus tooltip. */
.odf-traits { display: flex; flex-wrap: wrap; gap: 6px; list-style: none; margin: 10px 0 0; padding: 0; }
/* z-index 2: the card is a stretched link (.odf-card__link::after inset:0 z-1) that
   otherwise swallows hover/focus, so the tooltip never fired on live cards. */
.odf-trait { position: relative; z-index: 2; width: 28px; height: 28px; border-radius: 50%; display: flex; align-items: center; justify-content: center; background: var(--odf-green-soft); color: var(--odf-green-deep); cursor: help; }
.odf-trait svg { width: 16px; height: 16px; }
.odf-trait:focus-visible { outline: 2px solid var(--odf-green); outline-offset: 2px; }
.odf-trait__tip { position: absolute; bottom: calc(100% + 8px); left: 0; z-index: var(--odf-z-tip); width: max-content; max-width: 210px; background: var(--odf-ink); color: #fff; border-radius: 8px; padding: 7px 10px; font-size: 11px; line-height: 1.35; text-align: left; opacity: 0; visibility: hidden; transition: opacity .12s ease; pointer-events: none; box-shadow: var(--odf-shadow-soft); }
.odf-trait__tip b { display: block; font-weight: 700; margin-bottom: 1px; }
.odf-trait__tip span { color: #cdd6d1; }
.odf-trait__tip::after { content: ""; position: absolute; top: 100%; left: 14px; border: 5px solid transparent; border-top-color: var(--odf-ink); }
.odf-trait:hover .odf-trait__tip, .odf-trait:focus-within .odf-trait__tip { opacity: 1; visibility: visible; }
/* Compact variant for strips, best-of rows and brand tables. */
.odf-traits--sm { gap: 4px; margin-top: 6px; }
.odf-traits--sm .odf-trait { width: 22px; height: 22px; }
.odf-traits--sm .odf-trait svg { width: 13px; height: 13px; }
/* Homepage dense strip: the icon row wraps to its own full-width line. */
.odf-foodcard--dense { flex-wrap: wrap; }
.odf-foodcard--dense .odf-traits { width: 100%; margin-top: 2px; }
.odf-foodgrid { margin-top: var(--odf-sp-4); }
/* Active-filter chips under the search/count bar: label + x, click removes. */
.odf-dirchips { display: flex; flex-wrap: wrap; gap: 8px; margin-top: var(--odf-sp-3); }
.odf-dirchip { display: inline-flex; align-items: center; gap: 6px; font-size: var(--odf-fs-xs); font-weight: 700; color: var(--odf-green-deep); background: var(--odf-green-soft); border: 1px solid transparent; border-radius: var(--odf-radius-pill); padding: 4px 12px; text-decoration: none; }
.odf-dirchip:hover { border-color: var(--odf-green); }
.odf-dirchip__x { font-size: 1.1em; line-height: 1; opacity: .7; }
.odf-dirchip:hover .odf-dirchip__x { opacity: 1; }
.odf-dirchip--clear { background: transparent; border-color: var(--odf-line); color: var(--odf-ink-2); }
.odf-dirchip--clear:hover { border-color: var(--odf-ink-3); }
/* Mini dial + stars sit above the stretched link so they stay hoverable. */
.odf-foodcard .odf-scorebadge, .odf-foodcard .odf-rating { position: relative; z-index: 2; }
/* Consistent badge position: absolute top-right of the card (the head keeps
   54px clear for it above). */
/* Card footer (founder call 23 Jul 2026): trait icons left, score bottom-right as
   a quiet band-coloured text LABEL, not a disc/button. CSS appends the /100;
   unrated (--none) stays a plain dash. */
.odf-foodcard__foot { display: flex; align-items: center; justify-content: space-between; gap: var(--odf-sp-2); margin-top: 10px; }
.odf-foodcard__foot .odf-traits { margin-top: 0; }
/* Text-label score, shared by the directory card footer AND the dense homepage
   strip cards - band-coloured "90/100", never a filled disc. */
.odf-foodcard .odf-scorebadge--text { margin-left: auto; font-size: var(--odf-fs-lg); line-height: 1; }
/* In the dense strip the score sits in the right-hand column above the arrow. */
.odf-foodcard__denseside .odf-scorebadge--text { margin-left: 0; }
/* .odf-altcard retired - the alternatives strip renders the shared card's
   compact form: odf_food_card( $row, 'mini' ) (.odf-foodcard--mini). */
.odf-foodcard--mini { padding: var(--odf-sp-4); gap: var(--odf-sp-2); }
.odf-foodcard__mini { display: flex; align-items: center; gap: 10px; }
.odf-foodcard--mini .odf-foodcard__titles { flex: 1; min-width: 0; }
.odf-foodcard__minithumb { flex: 0 0 auto; width: 40px; height: 40px; border-radius: var(--odf-radius-sm, 8px); overflow: hidden; background: var(--odf-tint); display: grid; place-items: center; }
.odf-foodcard__minipack, .odf-foodcard__minithumb img { width: 100%; height: 100%; object-fit: contain; display: block; }
.odf-foodcard--mini .odf-foodcard__name:hover { color: var(--odf-green); }
.odf-foodcard__minirow { display: flex; justify-content: space-between; align-items: center; font-size: var(--odf-fs-sm); color: var(--odf-ink-3); border-top: 1px dashed var(--odf-line); padding-top: 10px; margin-top: auto; }
.odf-foodcard__minirow a { font-weight: 700; color: var(--odf-green); display: inline-flex; align-items: center; gap: 5px; position: relative; z-index: 2; }

/* --- Guide content-shortcode refinements (packshots + cost/day in [odf_food_table]
       and [odf_best]). The shortcode-only .odf-sc-* base lives in odf-core's
       shortcodes.css; these extend it and reuse the mini-card thumb above. --- */
/* Live food table ([odf_food_table]): packshot beside the brand + name. */
.odf-sc-foodcell { display: flex; align-items: center; gap: var(--odf-sp-3); }
/* Table rows have room for a readable packshot - 40px is a chip, not a product.
   Uncropped source + contain, so tall bags and wide trays both fit whole. */
.odf-sc-foodcell__thumb { width: 52px; height: 52px; padding: 3px; background: var(--odf-card); box-shadow: inset 0 0 0 1px var(--odf-line); }
.odf-sc-pack__img { width: 100%; height: 100%; object-fit: contain; display: block; }
.odf-sc-foodcell__t { display: flex; flex-direction: column; min-width: 0; }
/* Best-of embed ([odf_best]): the #1 pick's packshot + live cost per day. */
.odf-sc-best__pack { flex: 0 0 auto; width: 56px; height: 56px; border-radius: var(--odf-radius-sm); overflow: hidden; background: var(--odf-card); display: grid; place-items: center; box-shadow: inset 0 0 0 1px var(--odf-line); }
.odf-sc-best__pack img { width: 100%; height: 100%; object-fit: contain; display: block; }
.odf-sc-best__price { display: block; margin-top: 4px; font-weight: 700; font-size: var(--odf-fs-sm); color: var(--odf-ink-2); }

/* Dense card (DENSITY pass rule 5 - homepage "Best in ..." strips): badge +
   eyebrow + 2-line-clamped name + arrow. No dashed separators, no dead
   vertical space; grid stretch keeps every card in a row the same height. */
.odf-foodcard--dense { flex-direction: row; align-items: stretch; gap: var(--odf-sp-3); padding: var(--odf-sp-3) var(--odf-sp-4); }
.odf-foodcard--dense .odf-foodcard__titles { flex: 1 1 auto; justify-content: flex-start; }
.odf-foodcard__denseside { flex: none; display: flex; flex-direction: column; align-items: flex-end; justify-content: space-between; gap: var(--odf-sp-2); }
.odf-foodcard__go { display: inline-flex; color: var(--odf-ink-3); transition: color var(--odf-dur) var(--odf-ease), transform var(--odf-dur) var(--odf-ease); }
.odf-foodcard--dense:hover .odf-foodcard__go { color: var(--odf-green); transform: translateX(2px); }

/* --- THE image placeholder (odf_placeholder(): paw on green-soft; rule 8 -
       no visible placeholder text anywhere, ever). --- */
.odf-placeholder {
	flex: none; display: inline-flex; align-items: center; justify-content: center;
	width: var(--odf-ph, 64px); height: var(--odf-ph, 64px);
	border-radius: var(--odf-radius-sm); background: var(--odf-green-soft); color: var(--odf-green);
}
.odf-placeholder__ico { display: block; }
.odf-fld--rating .odf-fld__opt, .odf-fld__opt { font-style: normal; font-weight: 400; color: var(--odf-ink-3); font-size: .9em; }
/* The instant DOM filter sets card.hidden. A grid/flex child overrides the UA's
   [hidden]{display:none}, so state it explicitly or "hidden" cards stay visible. */
.odf-foodgrid .odf-foodcard[hidden] { display: none !important; }
.odf-pagination { display: flex; flex-wrap: wrap; gap: 4px; justify-content: center; margin-top: var(--odf-sp-6); }
.odf-dirseo { max-width: var(--odf-measure); margin-top: var(--odf-sp-7); }
/* The Share block sits directly beneath the facts row (the Website link). It
   shipped flush against it and read as one cramped cluster on phones - give it
   real separation. */
.odf-hero__share { margin-top: var(--odf-sp-4); }
/* Hero "verdict at a glance" pills (brand hero) - pros green, cons amber. */
.odf-hero__verdict { display: flex; flex-wrap: wrap; gap: var(--odf-sp-2); margin-top: var(--odf-sp-4); }
/* Editorial intro + Quick facts side by side (facts fills the reading column's gap). */
.odf-dirseo-split { display: grid; grid-template-columns: minmax(0, 1fr) minmax(240px, 320px); gap: var(--odf-sp-6); align-items: start; margin-top: var(--odf-sp-8); }
.odf-dirseo-split__main { margin-top: 0; }
.odf-dirseo-split__aside .odf-quickfacts { margin-top: 0; }
@media (max-width: 860px) { .odf-dirseo-split { grid-template-columns: 1fr; }}
/* Sortable column headers = plain links (no JS). */
.odf-table thead th a { color: var(--odf-ink-2); display: inline-flex; align-items: center; gap: 4px; }
.odf-table thead th a:hover { color: var(--odf-ink); }
.odf-table thead th a.is-sorted { color: var(--odf-green); }
.odf-brandcard { display: flex; flex-direction: column; gap: var(--odf-sp-2); }
.odf-brandcard__name { font-weight: 800; color: var(--odf-ink); font-size: var(--odf-fs-base); }
.odf-brandcard__meta { font-size: var(--odf-fs-sm); color: var(--odf-ink-3); }

/* --- Homepage --- */
/* Quick facet tiles (DENSITY pass rule 4): ONE auto-fit grid - tiles flow to
   fill the row at every width, never balloon, never leave an orphan row of
   one stretched tile. Name + count on two tight lines, arrow ghosted in the
   corner until hover. */
.odf-tiles-quick { display: grid; grid-template-columns: repeat(auto-fit, minmax(360px, 1fr)); gap: var(--odf-sp-3); }
.odf-tile__count { display: block; font-weight: 500; color: var(--odf-ink-3); font-size: var(--odf-fs-xs); }
.odf-tiles-quick .odf-card { text-align: center; padding: var(--odf-sp-3) var(--odf-sp-4); }
.odf-tiles-quick .odf-tile { gap: 2px; justify-content: center; min-height: 56px; }
.odf-tiles-quick .odf-tile-sub { margin-top: 0; }
.odf-tiles-quick .odf-tile__arrow { top: var(--odf-sp-3); right: var(--odf-sp-3); opacity: 0; }
.odf-tiles-quick .odf-card:hover .odf-tile__arrow { opacity: 1; }
.odf-sechead { display: flex; align-items: baseline; justify-content: space-between; gap: var(--odf-sp-3); margin-bottom: var(--odf-sp-4); }
.odf-sechead h2 { margin-bottom: 0; font-size: var(--odf-fs-xl); }
.odf-sechead__sub { font-size: var(--odf-fs-sm); color: var(--odf-ink-3); margin: 2px 0 0; }
.odf-sechead__more { font-size: var(--odf-fs-md); font-weight: 700; color: var(--odf-green); white-space: nowrap; display: inline-flex; align-items: center; gap: 5px; }
/* How-we-rate band: the identity green gradient (the brand's dark moment). */
.odf-howband { background: var(--odf-green-deep); background-image: var(--odf-green-grad); border-radius: 20px; color: #fff; padding: var(--odf-sp-7); display: grid; grid-template-columns: 1.1fr 1fr; gap: var(--odf-sp-6); align-items: center; }
@media (max-width: 820px) { .odf-howband { grid-template-columns: 1fr; padding: var(--odf-sp-5); }}
.odf-howband h2 { color: #fff; }
.odf-howband h2 em { font-style: normal; color: color-mix(in srgb, var(--odf-gold) 62%, #fff); }
/* Green eyebrow would vanish on the green band - swap to the light-gold accent. */
.odf-howband .odf-eyebrow { color: color-mix(in srgb, var(--odf-gold) 62%, #fff); }
.odf-howband .odf-eyebrow::before { background: color-mix(in srgb, var(--odf-gold) 62%, #fff); }
.odf-howband p { color: rgba(255, 255, 255, .75); font-size: var(--odf-fs-md); max-width: 48ch; }
.odf-howband .odf-btn { margin-top: var(--odf-sp-2); }
.odf-steps { display: flex; flex-direction: column; gap: var(--odf-sp-3); }
.odf-step { background: rgba(255, 255, 255, .06); border: 1px solid rgba(255, 255, 255, .1); border-radius: var(--odf-radius); padding: var(--odf-sp-3) var(--odf-sp-4); font-size: var(--odf-fs-md); color: rgba(255, 255, 255, .9); display: flex; gap: var(--odf-sp-3); align-items: flex-start; }
.odf-step b { color: color-mix(in srgb, var(--odf-gold) 62%, #fff); font-variant-numeric: tabular-nums; flex: none; font-family: var(--odf-font-display); }
.odf-panel { background: var(--odf-card); border: 1px solid var(--odf-line); border-radius: var(--odf-radius-lg); box-shadow: var(--odf-shadow-xs); padding: var(--odf-sp-4); }
.odf-panel h3 { margin-bottom: var(--odf-sp-3); }
/* Signup panel (homepage): compact + centered, shortcode card melts in. */
.odf-panel--signup { text-align: center; display: flex; flex-direction: column; align-items: center; padding: var(--odf-sp-7) var(--odf-sp-5); }
.odf-panel--signup h3 { margin-bottom: var(--odf-sp-1); }
.odf-panel--signup .odf-sechead__sub { margin-bottom: var(--odf-sp-4); max-width: 52ch; }
.odf-panel--signup .odf-subscribe { background: transparent; border: 0; box-shadow: none; padding: 0; width: 100%; max-width: 560px; align-items: center; text-align: center; }
.odf-panel--signup .odf-subscribe__row { width: 100%; justify-content: center; }
.odf-panel--signup .odf-subscribe__lists { justify-content: center; }
.odf-panel--signup .odf-subscribe__btn { align-self: center; }

/* --- Utilities --- */
.odf-mt-0 { margin-top: 0; }
.odf-text-center { text-align: center; }
.screen-reader-text { position: absolute !important; clip: rect(1px, 1px, 1px, 1px); width: 1px; height: 1px; overflow: hidden; }

/* --- Responsive --- */
@media (max-width: 900px) {
	.odf-footer__cols { grid-template-columns: 1fr 1fr; }}
@media (max-width: 768px) {
	h1 { font-size: var(--odf-fs-2xl); }
	.odf-hero h1 { font-size: var(--odf-fs-2xl); }
	.odf-nav { display: none; }
	/* Section rhythm shrinks via the --odf-section-gap token (tokens.css). */
}
@media (max-width: 560px) {
	/* PERF_MOBILE_AUDIT P0: on phones the header row (brand + currency chip +
	   search + Sign in + burger) overflowed and forced a sitewide horizontal
	   scroll. Keep it to brand + search + burger. The currency switch is
	   display-only (prices still show in GBP) and Sign in lives in the burger
	   menu, so nothing is lost. */
	.odf-header__util .odf-curr,
	.odf-header__util .odf-btn { display: none; }}
/* Phones: the footer used to drop to ONE column here, which stacked ~20 links
   into a very long scroll. Keep the three link groups TWO-up and let the brand
   blurb span the full width above them - roughly half the height, same links. */
@media (max-width: 600px) {
	.odf-footer__cols { grid-template-columns: 1fr 1fr; gap: var(--odf-sp-5) var(--odf-sp-4); }
	.odf-footer__cols > :first-child { grid-column: 1 / -1; }}
/* Only the very narrowest phones actually need a single column. */
@media (max-width: 380px) {
	.odf-footer__cols { grid-template-columns: 1fr; }}

/* ---- Newsletter subscribe (plugin [odf_subscribe] shortcode) ---- */
.odf-subscribe{background:var(--odf-card);border:1px solid var(--odf-line);border-radius:var(--odf-r-14);padding:var(--odf-sp-6);max-width:560px;display:flex;flex-direction:column;gap:var(--odf-sp-3);box-shadow:var(--odf-shadow)}
.odf-subscribe__title{font-family:var(--odf-font-display);font-size:var(--odf-fs-19);font-weight:700;margin:0}
.odf-subscribe__text{color:var(--odf-ink-2);font-size:var(--odf-fs-14);margin:0}
.odf-subscribe__row{display:flex;gap:var(--odf-sp-2);flex-wrap:wrap}
.odf-subscribe__field{flex:1;min-width:150px;border:1px solid var(--odf-line);border-radius:var(--odf-r-10);padding:10px 14px;font:inherit;font-size:var(--odf-fs-14);background:var(--odf-surface);color:var(--odf-ink)}
.odf-subscribe__field:focus{outline:2px solid var(--odf-green);outline-offset:1px;border-color:var(--odf-green)}
.odf-subscribe__lists{border:0;padding:0;margin:0;display:flex;flex-wrap:wrap;gap:var(--odf-sp-2) var(--odf-sp-4)}
.odf-subscribe__lists legend{font-size:var(--odf-fs-13);font-weight:600;color:var(--odf-ink-2);padding:0;margin-bottom:var(--odf-sp-1)}
.odf-subscribe__opt{display:inline-flex;align-items:center;gap:6px;font-size:var(--odf-fs-13);color:var(--odf-ink-2);cursor:pointer}
.odf-subscribe__consent{display:flex;align-items:flex-start;gap:8px;font-size:var(--odf-fs-12);color:var(--odf-ink-3);cursor:pointer}
.odf-subscribe__consent input{margin-top:2px}
.odf-subscribe__consent a{color:var(--odf-green);text-decoration:underline;text-underline-offset:2px}
.odf-subscribe__btn{align-self:flex-start}
/* Signup feedback. This used to be 13px of plain coloured text under the button
   and read as a caption - people finished the most important interaction on the
   page and could not tell whether it had worked. It is now a panel: tinted
   background, icon, and body-size text, so the confirmation is the loudest thing
   in the box at the moment it appears.
   Colour is never the only signal - there is an icon, the wording says what
   happened, and failures carry role="alert" so a screen reader is told. */
.odf-subscribe__msg{
	display:flex;align-items:flex-start;justify-content:center;gap:9px;
	margin:2px 0 0;padding:11px 14px;
	border:1px solid transparent;border-radius:12px;
	font-size:var(--odf-fs-14);line-height:1.45;font-weight:600;text-align:left;
	color:var(--odf-ink-2)
}
.odf-subscribe__msg:empty{display:none}
.odf-subscribe__msg::before{
	content:"";flex:0 0 auto;width:18px;height:18px;margin-top:1px;
	background-repeat:no-repeat;background-position:center;background-size:18px 18px
}
.odf-subscribe__msg.is-ok{
	background:var(--odf-green-soft);border-color:rgba(15,74,55,.18);color:var(--odf-green-deep);
	animation:odf-sub-in .22s ease-out both
}
.odf-subscribe__msg.is-ok::before{
	background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' fill='none' stroke='%230f4a37' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 10.5l4 4 8-9'/%3E%3C/svg%3E")
}
/* Tint kept deliberately light: --odf-band-avoid on a heavier wash measures
   4.45:1, and 14px/600 is NOT WCAG "large text" (that starts at 18.66px bold),
   so it would miss AA. This lifts it to 4.71:1 with the same red. */
.odf-subscribe__msg.is-error{
	background:#fef4f2;border-color:rgba(201,58,46,.28);color:var(--odf-band-avoid);
	animation:odf-sub-in .22s ease-out both
}
.odf-subscribe__msg.is-error::before{
	background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' fill='none' stroke='%23c93a2e' stroke-width='2.2' stroke-linecap='round'%3E%3Ccircle cx='10' cy='10' r='7.6'/%3E%3Cpath d='M10 6v4.8'/%3E%3Cpath d='M10 13.8v.1'/%3E%3C/svg%3E")
}
/* ink-2, not ink-3: the muted grey only reaches 3.04:1 on the tinted panel. */
.odf-subscribe__msg.is-busy{background:var(--odf-surface-2,#f6f5f1);color:var(--odf-ink-2);font-weight:500}
.odf-subscribe__msg.is-busy::before{
	border:2px solid var(--odf-line);border-top-color:var(--odf-ink-3);border-radius:50%;
	width:16px;height:16px;animation:odf-sub-spin .7s linear infinite
}
@keyframes odf-sub-in{from{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:none}}
@keyframes odf-sub-spin{to{transform:rotate(360deg)}}
@media (prefers-reduced-motion:reduce){
	.odf-subscribe__msg.is-ok,.odf-subscribe__msg.is-error{animation:none}
	.odf-subscribe__msg.is-busy::before{animation-duration:2s}}
.odf-subscribe__btn[disabled]{opacity:.6;cursor:progress}
.odf-subscribe--compact{padding:var(--odf-sp-4);box-shadow:none}

/* Ingredient pill qualifiers: bracket content renders small + muted, never full-size */
.odf-ingpill small{font-size:.72em;font-weight:500;opacity:.65}
.odf-ingpill__qual{font-style:normal}

/* Suggestions: packshot | name | score. */
.odf-suggest__item { display: flex; align-items: center; gap: var(--odf-sp-3); }
.odf-suggest__score { margin-left: auto; color: var(--odf-green); font-weight: 800; flex: 0 0 auto; }
.odf-suggest__thumb { flex: 0 0 auto; width: 36px; height: 36px; border-radius: 6px; background: var(--odf-tint); display: flex; align-items: center; justify-content: center; overflow: hidden; }
.odf-suggest__thumb img { width: 100%; height: 100%; object-fit: contain; display: block; }
.odf-suggest__label { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ==========================================================================
   Ingredients glossary: hub tools, avoid strip, A-Z nav, grouped list,
   classification dots, single-page blocks.
   ========================================================================== */

/* Classification dot (hub list, related chips) */
.odf-dot { display: inline-block; width: 9px; height: 9px; border-radius: var(--odf-radius-pill); background: var(--odf-line); flex: none; }
.odf-dot--green { background: var(--odf-band-verygood); }
.odf-dot--amber { background: var(--odf-band-average); }
.odf-dot--red { background: var(--odf-band-avoid); }

/* Grouped list */
.odf-gloss__group { margin-bottom: var(--odf-sp-6); }
.odf-gloss__letter { font-size: var(--odf-fs-xl); color: var(--odf-green); border-bottom: 1px solid var(--odf-line); padding-bottom: var(--odf-sp-2); margin-bottom: var(--odf-sp-3); scroll-margin-top: 90px; }
.odf-gloss__list { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: 1fr 1fr; gap: var(--odf-sp-2) var(--odf-sp-6); }
@media (max-width: 760px) { .odf-gloss__list { grid-template-columns: 1fr; }}
.odf-gloss__link { display: grid; grid-template-columns: auto auto 1fr; align-items: baseline; gap: 10px; padding: 8px 10px; border-radius: var(--odf-radius-sm); color: var(--odf-ink-2); }
.odf-gloss__link:hover { background: var(--odf-green-soft); color: var(--odf-ink); }
.odf-gloss__link .odf-dot { align-self: center; }
.odf-gloss__name { font-weight: 700; color: var(--odf-ink); white-space: nowrap; }
.odf-gloss__sum { font-size: var(--odf-fs-sm); color: var(--odf-ink-3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
@media (max-width: 560px) { .odf-gloss__link { grid-template-columns: auto 1fr; } .odf-gloss__sum { grid-column: 2; }}
.odf-chip__score { font-size: var(--odf-fs-xs); font-weight: 800; color: var(--odf-ink-3); background: var(--odf-tint); border-radius: var(--odf-radius-pill); padding: 1px 8px; font-variant-numeric: tabular-nums; }

/* ==========================================================================
   Product page V2 (founder review round 2): linked chips, variant switcher
   cards, image gallery carousel, ingredient role groups, feeding & cost
   block, about-the-brand card, scorecard foot. Tokens + color-mix() only.
   ========================================================================== */

/* --- Linked chips: any pill that is a real link gets a hover state --- */
a.odf-pill { transition: border-color var(--odf-dur) var(--odf-ease), color var(--odf-dur) var(--odf-ease), background var(--odf-dur) var(--odf-ease); }
a.odf-pill:hover { color: var(--odf-green-deep); background: var(--odf-green-soft); border-color: var(--odf-green); }
/* Top-5 label positions (they carry the most scoring weight): subtle bolder outline. */
.odf-ingpill--top { border-width: 1.5px; padding: 5.5px 12.5px; border-color: color-mix(in srgb, currentColor 42%, #fff); }
.odf-inglegend__top i { background: transparent; border: 1.5px solid var(--odf-ink-3); box-sizing: border-box; }

/* ---- Rail: compact brand card ---- */
/* Renamed .odf-brandcard -> .odf-brandcard--rail (Phase 1b duplicate-class
   fix: the bare name also styles the brand page's sibling-brand card).
   Logo/placeholder rules retired - odf_logo_box( $id, 44, $name ) renders them. */
.odf-brandcard--rail{background:var(--odf-card);border:1px solid var(--odf-line);border-radius:var(--odf-radius-lg);box-shadow:var(--odf-shadow-xs);padding:var(--odf-sp-4) var(--odf-sp-5);display:flex;flex-direction:column;gap:var(--odf-sp-2)}
.odf-brandcard__head{display:flex;align-items:center;gap:var(--odf-sp-3)}
.odf-brandcard__h{font-family:var(--odf-font-display);font-weight:700;font-size:var(--odf-fs-md);margin:0}
.odf-brandcard__lead{font-size:var(--odf-fs-sm);color:var(--odf-ink-2);margin:0}
.odf-brandcard__facts{display:flex;flex-wrap:wrap;gap:6px 12px;font-size:var(--odf-fs-xs);color:var(--odf-ink-3)}
.odf-brandcard__links a{font-size:var(--odf-fs-sm);font-weight:700;color:var(--odf-green);display:inline-flex;align-items:center;gap:6px}
.odf-brandcard__links a:hover{color:var(--odf-green-deep)}

/* ==========================================================================
   Brand page enrichment (APPEND-ONLY block): report card, where-to-buy grid,
   offer cards + copy-code, ownership block, recalls slot. Tokens and
   color-mix() derivations only - no new hexes.
   ========================================================================== */

/* --- Brand hero: full-width stat strip -----------------------------------
   The four tiles used to stack two-up inside the 340px side column beneath the
   logo, which made the right column ~160px taller than the left (dead white gap
   beside the facts) and squeezed labels like "of 270 ranked brands" onto three
   lines. Now they run full width under both columns as ONE card divided by
   hairlines, which reads as a single organised object rather than four floating
   boxes.

   The dividers are a 1px grid gap letting the container colour show through,
   not per-cell borders. That matters because the tile count varies - a brand
   with one rated food renders two tiles, not four - so any nth-child border
   scheme would break on wrap. This one is correct at any count and any width. */
.odf-hero__stats { margin-top: var(--odf-sp-5); }
.odf-hero__stats .odf-statrow {
	grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
	gap: 1px;
	background: var(--odf-line);
	border: 1px solid var(--odf-line);
	border-radius: var(--odf-radius-card);
	box-shadow: var(--odf-shadow-card);
	overflow: hidden;
}
.odf-hero__stats .odf-stat { background: var(--odf-card); border: 0; border-radius: 0; box-shadow: none; padding: var(--odf-sp-4); }
/* 24px, not the 28px stat default - at full width these are supporting numbers
   next to a 42px H1, and the founder read them as shouting. */
.odf-hero__stats .odf-stat__value { font-size: var(--odf-fs-xl); }
.odf-hero__stats .odf-stat__label { letter-spacing: .04em; }
.odf-hero__stats .odf-stat__viz   { margin-top: 6px; }

/* With the tiles gone the side column holds only the logo, so it no longer needs
   340px - a narrower column pulls the logo closer to the copy it belongs to. */
.odf-hero--entity .odf-hero__grid { grid-template-columns: minmax(0, 1fr) minmax(200px, 260px); }

/* ==========================================================================
   Search + branding wave (theme 0.6.0) - APPEND ONLY below this line.
   ========================================================================== */

/* --- Header search panel (icon toggles it; hidden = display:none via [hidden]) --- */
.odf-hsearch { border-top: 1px solid var(--odf-line); background: var(--odf-card); padding-block: var(--odf-sp-3); }
.odf-hsearch__form { max-width: 640px; margin-inline: auto; }

/* --- Compact variant of the shared search box (header panel, empty states) --- */
.odf-search--compact { padding: var(--odf-sp-1); border-radius: var(--odf-radius-lg); box-shadow: var(--odf-shadow-xs); }
.odf-search--compact input { padding: 0.6rem 0.9rem 0.6rem 2.4rem; font-size: var(--odf-fs-md); }
/* .odf-emptystate__search retired - odf_empty_state()'s extra slot
   (.odf-emptystate__extra) carries the search form now. */

/* --- Footer branding (logo variant, description, social row) --- */
.odf-footer__brandimg { height: 30px; width: auto; max-width: 230px; object-fit: contain; display: block; }
.odf-footer__desc { margin-top: var(--odf-sp-3); max-width: 40ch; line-height: 1.6; }
.odf-footer__social { list-style: none; display: flex; flex-wrap: wrap; gap: var(--odf-sp-2); margin: var(--odf-sp-4) 0 0; padding: 0; }
.odf-footer__social a {
	display: inline-flex; align-items: center; justify-content: center;
	width: 38px; height: 38px; padding: 0; border-radius: var(--odf-radius-pill);
	color: rgba(231, 242, 237, .78); background: rgba(255, 255, 255, .08);
	transition: background var(--odf-dur) var(--odf-ease), color var(--odf-dur) var(--odf-ease);
}
.odf-footer__social a:hover { color: #fff; background: rgba(255, 255, 255, .16); }
.odf-footer__social svg { width: 18px; height: 18px; }

/* --- 404 search --- */
.odf-404__search { max-width: 560px; margin-inline: auto; }
.odf-404__search .odf-search { margin-inline: auto; }

/* --- Grouped suggest dropdown (theme module: assets/js/search.js) ---
   Sits inside .odf-search__field (position:relative), full width under the
   input. Options are >=44px tall (touch target rule). */
.odf-sg {
	position: absolute; top: calc(100% + 6px); left: 0; right: 0; z-index: var(--odf-z-popover);
	background: var(--odf-card); border: 1px solid var(--odf-line);
	border-radius: var(--odf-radius); box-shadow: var(--odf-shadow);
	padding: var(--odf-sp-1); max-height: min(420px, 60vh); overflow: auto;
	text-align: left;
}
/* Mobile-only close button for the type-ahead panel. Desktop already has
   Escape + click-outside; on a phone the panel covers the screen and needs a
   visible way out. Sits over the panel's top-right corner. */
.odf-sg__close { display: none; }
@media (max-width: 700px) {
	.odf-sg__close {
		display: grid; place-items: center;
		position: absolute; z-index: calc(var(--odf-z-popover) + 1);
		top: calc(100% + 10px); right: 8px;
		width: 34px; height: 34px; padding: 0;
		font-size: 22px; line-height: 1;
		color: var(--odf-ink-2); background: var(--odf-card);
		border: 1px solid var(--odf-line); border-radius: var(--odf-radius-pill);
		cursor: pointer;
	}
	/* Keep the first group heading clear of the button. */
	.odf-sg { padding-top: var(--odf-sp-2); }
	.odf-sg__head:first-child { padding-right: 44px; }}

.odf-sg__head {
	font-size: var(--odf-fs-xs); font-weight: 700; text-transform: uppercase;
	letter-spacing: var(--odf-tracking-wide); color: var(--odf-ink-3);
	padding: var(--odf-sp-2) var(--odf-sp-3) var(--odf-sp-1);
}
.odf-sg__head + .odf-sg__head { margin-top: var(--odf-sp-1); }
.odf-sg__opt {
	display: flex; align-items: center; gap: var(--odf-sp-3);
	min-height: 44px; padding: var(--odf-sp-2) var(--odf-sp-3);
	border-radius: var(--odf-radius-sm); color: var(--odf-ink); cursor: pointer;
}
.odf-sg__opt.is-active, .odf-sg__opt:hover { background: var(--odf-green-soft); color: var(--odf-ink); }
.odf-sg__main { display: flex; flex-direction: column; min-width: 0; gap: 1px; }
.odf-sg__label { font-size: var(--odf-fs-md); font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.odf-sg__meta { font-size: var(--odf-fs-xs); color: var(--odf-ink-3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.odf-sg__hl { background: var(--odf-gold-soft); color: inherit; border-radius: 3px; padding: 0 1px; }
.odf-sg__score {
	flex: none; width: 32px; height: 32px; border-radius: var(--odf-radius-pill);
	display: inline-grid; place-items: center;
	background: var(--odf-band, var(--odf-line)); color: #fff;
	font-family: var(--odf-font-display); font-weight: 700; font-size: var(--odf-fs-sm);
	font-variant-numeric: tabular-nums;
}
.odf-sg__score--none { background: var(--odf-tint); color: var(--odf-ink-3); border: 1px solid var(--odf-line); }
/* Suggestion thumbnail slot: product packshot / brand logo. Fixed size keeps rows
   aligned; empty slot shows the tint (packshot) or a white chip (logo). */
.odf-sg__thumb { flex: none; width: 34px; height: 34px; border-radius: var(--odf-radius-sm, 8px); overflow: hidden; background: var(--odf-tint); display: grid; place-items: center; }
.odf-sg__thumb img { width: 100%; height: 100%; object-fit: contain; display: block; }
.odf-sg__thumb--logo { background: #fff; border: 1px solid var(--odf-line); }
.odf-sg .odf-dot { flex: none; margin-inline: 11px; }
.odf-sg__state { padding: var(--odf-sp-3); font-size: var(--odf-fs-sm); color: var(--odf-ink-3); text-align: center; }
.odf-sg__opt--all { justify-content: center; border-top: 1px solid var(--odf-line); border-radius: 0 0 var(--odf-radius-sm) var(--odf-radius-sm); margin-top: var(--odf-sp-1); }
.odf-sg__opt--all .odf-sg__label { color: var(--odf-green); font-weight: 700; }

/* --- Search results page (/search/) --- */
.odf-serp__group { margin-bottom: var(--odf-sp-8); }
.odf-serp__group:last-of-type { margin-bottom: var(--odf-sp-6); }
/* .odf-serp__h / .odf-serp__count retired - the result groups render
   odf_section_header() with a count (.odf-sechead / .odf-sechead__count). */
.odf-serp__note { font-size: var(--odf-fs-sm); color: var(--odf-ink-2); margin: var(--odf-sp-4) 0; }
.odf-serp__brand { display: flex; align-items: center; gap: var(--odf-sp-3); padding: var(--odf-sp-4); }
.odf-serp__brand .odf-logobox { flex: 0 0 auto; }
.odf-serp__brandtext { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.odf-serp__brandname { font-weight: 800; font-size: var(--odf-fs-base); color: var(--odf-ink); }
.odf-serp__brandmeta { font-size: var(--odf-fs-sm); color: var(--odf-ink-3); }
.odf-serp__brand .odf-tile__arrow { margin-left: auto; flex: 0 0 auto; }
.odf-serp__ings { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 2px; max-width: 720px; }
.odf-serp__guides { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--odf-sp-2); }
.odf-serp__guides a { display: inline-flex; align-items: center; gap: var(--odf-sp-2); font-weight: 700; color: var(--odf-green); min-height: 44px; }
.odf-serp__guides a:hover { color: var(--odf-ink); }
.odf-serp__popular { justify-content: center; }
.odf-serp__all { display: flex; justify-content: center; margin-top: var(--odf-sp-2); }

/* Mobile: the dropdown stays inside the viewport under narrow heroes. */
@media (max-width: 560px) {
	.odf-sg { max-height: 50vh; }}

/* --- Header currency switcher (display-only GBP/EUR/USD; theme.js) ---------
   The button ships disabled (a plain GBP badge) and is enabled by JS only
   when fresh FX rates exist - disabled must read as a quiet chip, never as a
   broken control. Converted prices get a dotted underline: "hover for the
   real GBP price" (the span carries a title tooltip). */
.odf-curr { position: relative; }
.odf-curr__btn {
	display: inline-flex; align-items: center; gap: 6px; height: 40px; padding: 0 12px;
	background: transparent; border: 1px solid var(--odf-line); border-radius: var(--odf-radius-pill);
	font: inherit; font-size: var(--odf-fs-sm); font-weight: 700; font-variant-numeric: tabular-nums;
	color: var(--odf-ink-2); cursor: pointer; white-space: nowrap;
	transition: border-color var(--odf-dur) var(--odf-ease), color var(--odf-dur) var(--odf-ease);
}
.odf-curr__btn:hover:not(:disabled) { border-color: var(--odf-green); color: var(--odf-ink); }
.odf-curr__btn:focus-visible { outline: none; box-shadow: var(--odf-ring); }
.odf-curr__btn:disabled { cursor: default; }
.odf-curr__btn:disabled .odf-curr__chev { display: none; }
.odf-curr__chev { color: var(--odf-ink-3); flex: 0 0 auto; transition: transform var(--odf-dur) var(--odf-ease); }
.odf-curr.is-open .odf-curr__chev { transform: rotate(180deg); }
.odf-curr__menu {
	position: absolute; top: calc(100% + 6px); right: 0; min-width: 132px;
	margin: 0; padding: 6px; list-style: none;
	background: var(--odf-card); border: 1px solid var(--odf-line); border-radius: var(--odf-radius);
	box-shadow: var(--odf-shadow); z-index: var(--odf-z-nav);
}
.odf-curr__opt {
	display: flex; align-items: center; gap: 8px; padding: 9px 12px;
	border-radius: var(--odf-radius-sm); font-size: var(--odf-fs-sm); color: var(--odf-ink);
	cursor: pointer; white-space: nowrap;
}
.odf-curr__opt:hover { background: var(--odf-green-soft); }
.odf-curr__opt:focus-visible { outline: none; box-shadow: var(--odf-ring); background: var(--odf-green-soft); }
.odf-curr__opt[aria-selected="true"] { background: var(--odf-green-soft); color: var(--odf-green-deep); font-weight: 700; }
.odf-price[data-odf-fx] { text-decoration: underline dotted; text-decoration-color: var(--odf-ink-3); text-underline-offset: 2px; }
@media (max-width: 480px) { .odf-curr__btn { padding: 0 9px; gap: 4px; }}

/* ==========================================================================
   /best/{topic}/ - editorial live ranking (appended by the best-of redesign).
   Washed hero + #1 feature block + dense ranked rows + "how it's built" strip.
   Tokens only - no new colours (color-mix on tokens for tints/emphasis).
   ========================================================================== */

/* --- Washed hero: .odf-besthero retired - the page now rides the shared
       .odf-hero--entity primitive (see the design-backbone block). Only the
       best-of-specific methodology line stays here. --- */
.odf-best-method { display: flex; align-items: flex-start; gap: var(--odf-sp-2); margin: var(--odf-sp-3) 0 0; font-size: var(--odf-fs-sm); color: var(--odf-ink-2); }
.odf-best-method__ico { flex: none; color: var(--odf-green); margin-top: 1px; }
.odf-best-method a { color: var(--odf-green-deep); font-weight: 700; text-decoration: underline; text-underline-offset: 2px; }
.odf-best-method a:hover { color: var(--odf-ink); }

/* --- Tail: sibling chips + facet link --- */
.odf-bestlinks { display: flex; flex-wrap: wrap; gap: var(--odf-sp-2); margin-top: var(--odf-sp-3); }
.odf-bestlinks__facet { margin: var(--odf-sp-4) 0 0; }
.odf-bestlinks__facet a { display: inline-flex; align-items: center; gap: 6px; color: var(--odf-green-deep); font-weight: 700; }
.odf-bestlinks__facet a:hover { color: var(--odf-ink); }
.odf-bestlinks__facet svg { width: 15px; height: 15px; }
.odf-section__cta .odf-btn svg, .odf-emptystate .odf-btn svg { margin-left: 4px; }

/* "Embed this list" - bottom corner of each verdict card. Inherits --odf-cde
   from .odf-cdegroup--{key}, so the button carries that card's verdict colour
   without a per-verdict rule. */
.odf-cdeembed { display: flex; flex-direction: column; align-items: flex-end; margin-top: var(--odf-sp-3); }
.odf-cdeembed__btn { display: inline-flex; align-items: center; gap: 6px; padding: 6px 12px; border: 1px solid color-mix(in srgb, var(--odf-cde) 35%, #fff); border-radius: var(--odf-radius-pill); background: var(--odf-card); color: var(--odf-ink-2); font-size: var(--odf-fs-xs); font-weight: 700; cursor: pointer; }
.odf-cdeembed__btn:hover { color: var(--odf-ink); border-color: var(--odf-cde); }
.odf-cdeembed__btn svg { color: var(--odf-cde); }
.odf-cdeembed__panel { width: 100%; margin-top: var(--odf-sp-3); padding: var(--odf-sp-4); background: var(--odf-card); border: 1px solid var(--odf-line); border-radius: var(--odf-radius-lg); text-align: left; }
.odf-cdeembed__lead { margin: 0 0 var(--odf-sp-3); font-size: var(--odf-fs-sm); color: var(--odf-ink-2); }
.odf-cdeembed__code { width: 100%; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: var(--odf-fs-xs); line-height: 1.5; padding: var(--odf-sp-3); border: 1px solid var(--odf-line); border-radius: var(--odf-radius); background: var(--odf-tint); color: var(--odf-ink); resize: vertical; }
.odf-cdeembed__note { margin: var(--odf-sp-3) 0 0; font-size: var(--odf-fs-xs); color: var(--odf-ink-3); }
@media (max-width: 560px) {
	.odf-cdeembed { align-items: stretch; }
	.odf-cdeembed__btn { justify-content: center; }}

/* ==========================================================================
   Design backbone primitives (12-LAYOUT-LANGUAGE Phase 1) - appended by the
   design-backbone workstream. THE CSS contract the template re-lay pass
   builds against; helpers live in inc/components.php. Tokens only.
   ========================================================================== */

/* --- Layout utilities: one rhythm, one feature band. The .odf-prose column
       already exists further up and resolves through --odf-measure, which
       now aliases --odf-w-prose - same 68ch, one token. --------------------- */
.odf-stack > * + * { margin-top: var(--odf-section-gap); }
.odf-featureband { background: var(--odf-green-soft); border-block: 1px solid var(--odf-line); padding-block: var(--odf-section-gap); }
.odf-featureband--deep { background: var(--odf-green-grad); border-block: none; color: #fff; }
.odf-featureband--deep h2, .odf-featureband--deep h3 { color: #fff; }

/* --- Hero system: odf_hero() emits .odf-hero--home (centered base rules),
       .odf-hero--hub (left, shares the legacy --page rules) and
       .odf-hero--entity (green wash), plus --split for two-column entity
       heroes. Split heroes stack media-first on phones. ------------------- */
.odf-hero--entity { background: var(--odf-green-soft); border-bottom: 1px solid var(--odf-line); padding-block: var(--odf-sp-5) var(--odf-sp-6); }
.odf-hero--entity h1 { max-width: 24ch; text-wrap: balance; }
.odf-hero--entity .odf-breadcrumbs { margin-bottom: var(--odf-sp-4); }
.odf-hero--entity .odf-breadcrumbs::after { background: linear-gradient(to right, transparent, var(--odf-green-soft)); }
.odf-hero--entity .odf-hero__lead { max-width: 60ch; margin: var(--odf-sp-4) 0 0; font-size: var(--odf-fs-lg); line-height: var(--odf-lh-snug); color: var(--odf-ink); }
.odf-hero--entity .odf-hero__chips { margin-top: var(--odf-sp-4); }
/* On the wash, plain pills get a card surface so they read as chips not fills. */
.odf-hero--entity .odf-pill { background: var(--odf-card); border: 1px solid var(--odf-line); }
.odf-hero--entity .odf-pill--green { background: var(--odf-card); color: var(--odf-green-deep); border-color: color-mix(in srgb, var(--odf-green) 30%, #fff); font-weight: 700; }

/* Live-browse item 5: split heroes top-align (no content drowning mid-air in
   a hero sized by its taller side) and the media card fits its content - no
   giant mostly-empty box around a logo. */
.odf-hero__grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(240px, 340px); gap: var(--odf-sp-5); align-items: start; }
.odf-hero__body { min-width: 0; }
.odf-hero__side { display: flex; flex-direction: column; gap: var(--odf-sp-3); min-width: 0; }
.odf-hero__media {
	position: relative; background: var(--odf-card); border: 1px solid var(--odf-line);
	border-radius: var(--odf-radius-lg); box-shadow: var(--odf-shadow-card);
	display: flex; align-items: center; justify-content: center;
	padding: var(--odf-sp-3); min-height: 0;
}
.odf-hero__media img { max-height: 160px; width: auto; }
.odf-hero__stats { margin-top: var(--odf-sp-5); }
@media (max-width: 760px) {
	.odf-hero__grid { grid-template-columns: 1fr; gap: var(--odf-sp-5); }
	/* Entity hero (brand page, best hub, price index) sets a 2-col grid at a
	   HIGHER specificity (.odf-hero--entity .odf-hero__grid) than the base
	   collapse above, so it must be re-collapsed at the same specificity or the
	   logo column keeps squeezing the title on phones. */
	.odf-hero--entity .odf-hero__grid { grid-template-columns: 1fr; }
	.odf-hero__side { order: -1; } /* media/dial first on phones */
	.odf-hero__media { max-width: 260px; min-height: 0; margin-inline: auto; }
	.odf-hero__media img { max-height: 150px; }}

/* --- Section header: .odf-sechead is THE header (odf_section_header());
       base rules live with the homepage block, extras here. ---------------- */
.odf-sechead__text { min-width: 0; }
.odf-sechead__sub { max-width: 62ch; }
.odf-sechead__count {
	display: inline-block; font-size: var(--odf-fs-sm); font-weight: 800; color: var(--odf-ink-2);
	background: var(--odf-tint); border: 1px solid var(--odf-line);
	border-radius: var(--odf-radius-pill); padding: 2px 10px; margin-left: 2px;
	font-variant-numeric: tabular-nums; vertical-align: 2px;
}

/* --- Stat tiles + stat row + bento (the auto-stat surface) -----------------
   DENSITY pass rule 3: one value size (28px token; --big 34px), tile padding
   sp-4, grid gap sp-3, value+label+context left-aligned in one column - and
   grid stretch keeps every tile in a row the same height. */
.odf-stat {
	display: flex; flex-direction: column; gap: 2px; min-width: 0;
	background: var(--odf-card); border: 1px solid var(--odf-line);
	border-radius: var(--odf-radius-card); box-shadow: var(--odf-shadow-card);
	padding: var(--odf-sp-4);
}
.odf-stat__value {
	font-family: var(--odf-font-display); font-weight: var(--odf-display-weight);
	font-size: var(--odf-fs-stat); line-height: var(--odf-lh-tight); color: var(--odf-ink);
	font-variant-numeric: tabular-nums; letter-spacing: var(--odf-tracking-tight);
}
.odf-stat__value--none { font-size: var(--odf-fs-base); font-weight: 700; color: var(--odf-ink-3); }
.odf-stat__label { font-size: var(--odf-fs-xs); font-weight: 700; text-transform: uppercase; letter-spacing: .05em; color: var(--odf-ink-3); }
.odf-stat__context { font-size: var(--odf-fs-sm); color: var(--odf-ink-2); }
.odf-stat__viz { margin-top: var(--odf-sp-2); }
.odf-stat--big .odf-stat__value { font-size: var(--odf-fs-stat-big); }
/* Range values ("82 - 89") never wrap onto two lines (live-browse item 5). */
.odf-stat--nowrap .odf-stat__value { white-space: nowrap; }

.odf-statrow { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: var(--odf-sp-3); align-items: stretch; }
/* On a phone the auto-fit lands on TWO columns, which leaves an odd number of
   tiles orphaned in the last row next to a much taller neighbour (the
   ingredients hub tile carries a bar chart + legend). Stack them instead. */
@media (max-width: 560px) {
	.odf-statrow { grid-template-columns: 1fr; }}

.odf-bento { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--odf-sp-3); }
.odf-bento__2x1, .odf-bento__2x2 { grid-column: span 2; }
.odf-bento__2x2 { grid-row: span 2; }
.odf-bento__full { grid-column: 1 / -1; }
@media (max-width: 900px) {
	.odf-bento { grid-template-columns: repeat(2, minmax(0, 1fr)); }}
@media (max-width: 560px) {
	.odf-bento__2x2 { grid-row: auto; }
	.odf-stat__value { font-size: var(--odf-fs-xl); }
	.odf-stat--big .odf-stat__value { font-size: var(--odf-fs-stat); }}

/* --- Stat strip (odf_stat_strip(); DENSITY pass rule 6): ONE bordered
       container, equal-width cells, internal hairline dividers - never
       floating stat cards of different heights with a void beside them. --- */
.odf-statstrip {
	display: grid; grid-auto-flow: column; grid-auto-columns: 1fr;
	background: var(--odf-card); border: 1px solid var(--odf-line);
	border-radius: var(--odf-radius-card); box-shadow: var(--odf-shadow-card);
	overflow: hidden;
}
.odf-statstrip .odf-stat { background: none; border: 0; border-radius: 0; box-shadow: none; }
.odf-statstrip .odf-stat + .odf-stat { border-left: 1px solid var(--odf-line); }
@media (max-width: 760px) {
	.odf-statstrip { grid-auto-flow: row; grid-auto-columns: auto; }
	.odf-statstrip .odf-stat + .odf-stat { border-left: 0; border-top: 1px solid var(--odf-line); }}

/* --- Score badge family: everything smaller than the hero dial ------------ */
.odf-scorebadge {
	display: inline-grid; place-items: center; flex: none;
	border-radius: var(--odf-radius-pill);
	background: var(--odf-band, var(--odf-line)); color: #fff;
	font-family: var(--odf-font-display); font-weight: 700;
	font-variant-numeric: tabular-nums;
}
.odf-scorebadge--sm { width: 30px; height: 30px; font-size: var(--odf-fs-xs); font-weight: 800; }
.odf-scorebadge--md { width: 46px; height: 46px; font-size: var(--odf-fs-md); }
.odf-scorebadge--lg { width: 56px; height: 56px; font-size: var(--odf-fs-lg); }
.odf-scorebadge--xl {
	width: auto; height: auto; display: inline-flex; align-items: baseline; justify-content: center; gap: 2px;
	border-radius: var(--odf-radius-lg); padding: var(--odf-sp-3) var(--odf-sp-4);
	font-size: var(--odf-fs-2xl); font-weight: 800; line-height: 1;
}
.odf-scorebadge__per { font-size: 0.45em; font-weight: 700; opacity: .85; }
/* gap:0 so the "/100" sits flush against the number the way the old ::after did;
   the optional trailing LABEL re-adds its own spacing below. */
.odf-scorebadge--text { display: inline-flex; align-items: baseline; gap: 0; background: none; color: var(--odf-band, var(--odf-ink)); font-weight: 800; }
.odf-scorebadge--text .odf-scorebadge__label { margin-left: 6px; font-size: var(--odf-fs-xs); font-weight: 700; text-transform: uppercase; letter-spacing: .04em; }
/* "/100" in the TEXT badge: neutral dark grey, full opacity - NOT the band
   colour. The small "/100" needs 4.5:1, but the mid/low band colours only reach
   2.6-3.9:1 on white and the old opacity:.75 made it worse. The big number keeps
   its band colour (large + bold, so 3:1 is enough); only the tiny suffix moves
   to ink-2 (6.9:1), which reads as "92" in colour, "/100" in grey - cleaner and
   compliant in every band. */
.odf-scorebadge--text .odf-scorebadge__per { font-size: .58em; font-weight: 700; opacity: 1; color: var(--odf-ink-2); }
.odf-scorebadge--none { background: var(--odf-tint); color: var(--odf-ink-3); border: 1px solid var(--odf-line); }
.odf-scorebadge--text.odf-scorebadge--none { background: none; border: none; }

/* --- Inline no-data state (odf_no_data()) ---------------------------------- */
.odf-nodata {
	display: inline-flex; align-items: center; padding: 2px 10px;
	border-radius: var(--odf-radius-pill); background: var(--odf-tint);
	border: 1px solid var(--odf-line); font-size: var(--odf-fs-xs);
	font-weight: 600; color: var(--odf-ink-3); white-space: nowrap;
}

/* --- Empty state extra slot (search form between body and CTAs) ----------- */
.odf-emptystate__extra { margin-bottom: var(--odf-sp-4); }
.odf-emptystate__extra .odf-search { margin-inline: auto; }

/* --- One brand-logo box (odf_logo_box(); size via --odf-logobox) ----------- */
.odf-logobox {
	flex: none; width: var(--odf-logobox, 44px); height: var(--odf-logobox, 44px);
	border-radius: var(--odf-radius-sm);
	background: var(--odf-card); display: grid; place-items: center; overflow: hidden;
}
/* Brand-page hero (and the other --entity heroes): the logo already reads as a
   framed mark on the tinted hero, so the extra card border + shadow round it
   just looked boxy. Scoped to the entity hero - the logo boxes in listings,
   search results and the "Brands worth trusting" cards keep their border. */
.odf-hero--entity .odf-hero__media { border: 0; box-shadow: none; }

.odf-logobox__img { max-width: 100%; max-height: 100%; object-fit: contain; }
.odf-logobox__ph {
	font-family: var(--odf-font-display); font-weight: 800; line-height: 1;
	font-size: calc(var(--odf-logobox, 44px) * .42); color: var(--odf-green);
}

/* --- Min-avg-max range bar (odf_range_bar()) ------------------------------- */
.odf-rangebar { display: flex; flex-direction: column; gap: var(--odf-sp-2); min-width: 0; }
.odf-rangebar__track { position: relative; display: block; height: 8px; border-radius: var(--odf-radius-pill); background: var(--odf-tint); border: 1px solid var(--odf-line); }
.odf-rangebar__span { position: absolute; inset: 1px; border-radius: var(--odf-radius-pill); background: linear-gradient(to right, var(--odf-green-soft), var(--odf-green)); opacity: .55; }
.odf-rangebar__avg { position: absolute; top: 50%; left: var(--pos, 50%); width: 3px; height: 14px; transform: translate(-50%, -50%); border-radius: 2px; background: var(--odf-ink); }
.odf-rangebar__ends { display: flex; align-items: baseline; justify-content: space-between; gap: var(--odf-sp-2); font-size: var(--odf-fs-sm); color: var(--odf-ink-2); font-variant-numeric: tabular-nums; }
.odf-rangebar__min, .odf-rangebar__max { font-weight: 700; color: var(--odf-ink); }
.odf-rangebar__avglabel { font-size: var(--odf-fs-xs); color: var(--odf-ink-3); }
/* Food-type categorical palette (odf_type_seg_class()): the segment + its
   legend dot both read --odf-band, so setting it once colours both. Distinct,
   on-brand, legible in light mode - the sanctioned place for category colour. */
.odf-type--dry           { --odf-band: var(--odf-type-dry); }
.odf-type--cold-pressed  { --odf-band: var(--odf-type-cold-pressed); }
.odf-type--wet           { --odf-band: var(--odf-type-wet); }
.odf-type--fresh-cooked  { --odf-band: var(--odf-type-fresh-cooked); }
.odf-type--raw           { --odf-band: var(--odf-type-raw); }
.odf-type--veterinary    { --odf-band: var(--odf-type-veterinary); }
.odf-type--air-dried     { --odf-band: var(--odf-type-air-dried); }
.odf-type--freeze-dried  { --odf-band: var(--odf-type-freeze-dried); }
.odf-type--mixer         { --odf-band: var(--odf-type-mixer); }
.odf-type--complementary { --odf-band: var(--odf-type-complementary); }
.odf-type--treat         { --odf-band: var(--odf-type-treat); }

/* --- Directory / facet / hub stat header: the authority strip between the
       hero and the filters+grid. A bento on the directory, a stat row on
       facets - both just need breathing room, the tiles style themselves. --- */
.odf-dirstats { margin-bottom: var(--odf-sp-5); }

/* --- Directory hero (odf-directory.php): the money-page split hero - H1 +
       live summary on the left, the gradient stat card (average ODF Score,
       price range, top scorer) top-right. Unlike the product entity hero the
       H1 leads on phones, so the card stacks BELOW it. --------------------- */
@media (max-width: 760px) {
	.odf-hero--dir .odf-hero__side { order: 0; }}

/* --- Modular /best/ internal-link tiles (odf_bestof_links) ------------------- */
.odf-bestlinks { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: var(--odf-sp-2); margin-top: var(--odf-sp-5); }
.odf-bestlinks__item { display: flex; align-items: center; gap: var(--odf-sp-3); padding: var(--odf-sp-3) var(--odf-sp-4); background: var(--odf-card); border: 1px solid var(--odf-line); border-radius: var(--odf-radius); color: var(--odf-ink); font-weight: 700; font-size: var(--odf-fs-sm); transition: background .12s ease, border-color .12s ease, transform .12s ease; }
.odf-bestlinks__item:hover { transform: translateY(-1px); background: var(--odf-green-soft); border-color: color-mix(in srgb, var(--odf-green) 38%, var(--odf-line)); color: var(--odf-ink); }
.odf-bestlinks__icowrap { flex: 0 0 auto; width: 34px; height: 34px; border-radius: var(--odf-radius-sm, 8px); background: var(--odf-green-soft); display: grid; place-items: center; color: var(--odf-green-deep); }
.odf-bestlinks__item:hover .odf-bestlinks__icowrap { background: var(--odf-card); }
.odf-bestlinks__label { flex: 1; min-width: 0; line-height: var(--odf-lh-snug, 1.3); }
.odf-bestlinks__go { flex: 0 0 auto; color: var(--odf-green); opacity: .55; }
.odf-bestlinks__item:hover .odf-bestlinks__go { opacity: 1; }

/* --- Methodology band (approved copy: "We score the food. Not the price
       tag.") - the full-bleed green-soft feature moment. ------------------- */
.odf-methband { text-align: center; }
.odf-methband h2 { font-size: var(--odf-fs-3xl); max-width: 22ch; margin-inline: auto; text-wrap: balance; }
.odf-methband p { max-width: 56ch; margin: var(--odf-sp-3) auto 0; font-size: var(--odf-fs-lg); line-height: var(--odf-lh-snug); color: var(--odf-ink-2); }
.odf-methband .odf-btn { margin-top: var(--odf-sp-4); }
@media (max-width: 560px) { .odf-methband h2 { font-size: var(--odf-fs-2xl); }}

/* --- Ingredients hub: the avoid strip rides the full-bleed feature band;
       the inner card chrome comes off (the band IS the emphasis). ---------- */
.odf-featureband .odf-avoidstrip { background: none; border: none; box-shadow: none; padding: 0; margin: 0; }

/* --- Brand page: split-hero facts sit right under the H1 as compact fact
       chips (live-browse item 5) - not a lone text line drowning in space.
       The report card band holds the card without double chrome. ----------- */
.odf-hero--entity .odf-brandfacts { margin-top: var(--odf-sp-3); }
.odf-hero--entity .odf-brandfacts__list { gap: var(--odf-sp-2); }
.odf-hero--entity .odf-brandfacts__list > span {
	display: inline-flex; align-items: baseline; gap: 4px;
	background: var(--odf-card); border: 1px solid var(--odf-line);
	border-radius: var(--odf-radius-pill); padding: 4px 12px;
	font-size: var(--odf-fs-sm); color: var(--odf-ink-2); white-space: nowrap;
}
.odf-hero--entity .odf-brandfacts__list > span.odf-dtc { color: var(--odf-green-deep); background: var(--odf-green-soft); border-color: color-mix(in srgb, var(--odf-green) 30%, #fff); }
.odf-featureband .odf-brandverdict { box-shadow: var(--odf-shadow-card); }

/* ==========================================================================
   TC-VIBE WAVE (12-LAYOUT-LANGUAGE, founder directives 2026-07-17b) -
   appended by the TC-vibe workstream. TreatmentCosts-pattern heroes, the
   gradient stats band, the money-page byline + sticky gradient stat card,
   the deep #1 feature / how-we-rate hero, live-filter states and the chart
   enhancer tooltip + focus states. Tokens only, light mode only.
   ========================================================================== */

/* --- H1 emphasis words: <em> = identity green (rule exists on .odf-hero h1
       em), <strong> = gold. The strike-through is homepage-hero only (the
       "not adverts" joke) - money pages use plain gold emphasis. ----------- */
.odf-hero h1 strong { color: var(--odf-gold-deep); font-weight: inherit; }
.odf-hero--tc h1 strong {
	text-decoration: line-through;
	text-decoration-thickness: .07em;
	text-decoration-color: color-mix(in srgb, var(--odf-gold) 75%, #fff);
}

/* --- Homepage TC hero: left copy column + the floating hand-drawn review
       card (inc/hero-art.php) right. Collapses to the copy column alone on
       phones - the art is a desktop brand moment, not a scroll tax. -------- */
.odf-hero--tc { text-align: left; padding-block: var(--odf-sp-6) var(--odf-sp-7); }
.odf-hero__tcgrid { display: grid; grid-template-columns: minmax(0, 1fr) 380px; gap: var(--odf-sp-8); align-items: center; }
.odf-hero__tcbody { min-width: 0; }
.odf-hero--tc h1 { margin-inline: 0; max-width: 20ch; }
.odf-hero--tc .odf-hero__lead { margin-inline: 0; max-width: 52ch; }
.odf-hero--tc .odf-search { margin-inline: 0; }
.odf-hero--tc .odf-trust-strip, .odf-hero--tc .odf-popular { justify-content: flex-start; }
.odf-hero--tc .odf-trust-strip { margin-top: var(--odf-sp-4); }
.odf-popular__chip { display: inline-flex; align-items: center; gap: 6px; }
.odf-popular__chip .odf-foodicon { flex: none; color: var(--odf-green); }
@media (max-width: 900px) {
	.odf-hero__tcgrid { grid-template-columns: 1fr; gap: var(--odf-sp-5); }}

/* --- Quick facet tiles: the hand-drawn type/category icon above the name. -- */
.odf-tile__ico { display: flex; justify-content: center; color: var(--odf-green); }
.odf-tiles-quick .odf-card:hover .odf-tile__ico { color: var(--odf-green-deep); }

/* --- Byline row (money-page E-E-A-T): By {author} - Updated {date} -
       How we rate. Segments join on plain-hyphen separators; any missing
       segment simply drops out. -------------------------------------------- */
.odf-byline { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px var(--odf-sp-2); margin: var(--odf-sp-2) 0 0; font-size: var(--odf-fs-sm); color: var(--odf-ink-3); }
.odf-byline b { color: var(--odf-ink); font-weight: 600; }
.odf-byline a { font-weight: 600; }
.odf-byline__sep { color: var(--odf-line); }

/* --- The gradient stat card (odf_money_stat_card()): white text, ONE gold
       accent (the top-score callout), the reserved embed slot. ------------- */
.odf-statcard {
	background: var(--odf-green-grad); color: #fff;
	border-radius: var(--odf-radius-xl); box-shadow: var(--odf-shadow);
	padding: var(--odf-sp-5); display: flex; flex-direction: column; gap: var(--odf-sp-3);
}
.odf-statcard__head {
	display: flex; align-items: center; gap: var(--odf-sp-2); margin: 0;
	font-size: var(--odf-fs-xs); font-weight: 700; text-transform: uppercase;
	letter-spacing: var(--odf-tracking-wide); color: rgba(255, 255, 255, .8);
}
.odf-statcard__head .odf-foodicon { flex: none; color: #fff; }
.odf-statcard__big { display: flex; align-items: baseline; gap: 2px; margin: 0; }
.odf-statcard__big b {
	font-family: var(--odf-font-display); font-weight: 800; font-size: 2.6rem;
	line-height: 1; color: #fff; letter-spacing: var(--odf-tracking-tight);
	font-variant-numeric: tabular-nums;
}
.odf-statcard__big span { font-size: var(--odf-fs-base); font-weight: 700; color: rgba(255, 255, 255, .65); }
.odf-statcard__biglabel { margin: -6px 0 0; font-size: var(--odf-fs-xs); font-weight: 700; text-transform: uppercase; letter-spacing: .05em; color: rgba(255, 255, 255, .65); }
.odf-statcard__rows { list-style: none; margin: 0; padding: 0; }
.odf-statcard__rows li {
	display: flex; justify-content: space-between; align-items: baseline; gap: var(--odf-sp-3);
	padding: 8px 0; border-top: 1px solid rgba(255, 255, 255, .16);
	font-size: var(--odf-fs-sm); color: rgba(255, 255, 255, .78);
}
.odf-statcard__rows b { color: #fff; font-weight: 700; font-variant-numeric: tabular-nums; white-space: nowrap; }
.odf-statcard__rows .odf-price { color: #fff; }
.odf-statcard__callout {
	margin: 0; padding-top: var(--odf-sp-3); border-top: 1px solid rgba(255, 255, 255, .16);
	font-size: var(--odf-fs-sm); line-height: 1.5;
	color: color-mix(in srgb, var(--odf-gold) 55%, #fff);
}
.odf-statcard__callout b { color: color-mix(in srgb, var(--odf-gold) 40%, #fff); font-weight: 800; font-variant-numeric: tabular-nums; }
/* The top scorer is now a link. On the green card an underline reads better than
   a colour shift, which would fight the gold already used for the score. */
.odf-statcard__callout a { color: inherit; text-decoration: underline; text-underline-offset: 2px; text-decoration-thickness: 1px; }
.odf-statcard__callout a:hover { color: #fff; text-decoration-thickness: 2px; }
[data-odf-results] { transition: opacity var(--odf-dur) var(--odf-ease); }
[data-odf-results][aria-busy="true"] { opacity: .55; pointer-events: none; }

/* --- Chart enhancer (theme.js initChartStrips): one shared tooltip +
       keyboard-focusable segments on the server-rendered strips. ------------ */
.odf-charttip {
	position: fixed; z-index: var(--odf-z-toast); pointer-events: none; white-space: nowrap;
	background: var(--odf-ink); color: #fff; font-size: var(--odf-fs-xs); font-weight: 600;
	padding: 5px 10px; border-radius: 7px; box-shadow: var(--odf-shadow);
	transform: translate(-50%, calc(-100% - 8px));
}

/* ==========================================================================
   Related guides (attach-to-pages) - odf_related_guides() + [odf_guides].
   Auto-block at the foot of product + facet pages and the manual shortcode.
   Reuses the card tokens; the only feature-specific styles live here.
   ========================================================================== */
.odf-relguides { margin-top: var(--odf-sp-6, 2rem); }
.odf-guidecards { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: var(--odf-sp-3); }
.odf-guidecard {
	display: flex; flex-direction: column; overflow: hidden;
	background: var(--odf-card); border: 1px solid var(--odf-line);
	border-radius: var(--odf-radius-card); box-shadow: var(--odf-shadow-card);
	text-decoration: none; color: inherit;
	transition: box-shadow var(--odf-dur) var(--odf-ease), transform var(--odf-dur) var(--odf-ease);
}
.odf-guidecard:hover { box-shadow: var(--odf-shadow); transform: translateY(-2px); }
.odf-guidecard:focus-visible { outline: 2px solid transparent; box-shadow: var(--odf-ring); }
.odf-guidecard__media { display: block; aspect-ratio: 16 / 9; background: var(--odf-green-soft); overflow: hidden; }
.odf-guidecard__img { width: 100%; height: 100%; object-fit: cover; display: block; }
.odf-guidecard__body { display: flex; flex-direction: column; gap: var(--odf-sp-2); padding: var(--odf-sp-3) var(--odf-sp-4) var(--odf-sp-4); }
.odf-guidecard__title { font-size: var(--odf-fs-md); font-weight: 800; line-height: var(--odf-lh-snug); color: var(--odf-ink); }
.odf-guidecard__excerpt { font-size: var(--odf-fs-sm); line-height: var(--odf-lh-snug); color: var(--odf-ink-2); }
.odf-guidecard__more { margin-top: auto; font-size: var(--odf-fs-sm); font-weight: 700; color: var(--odf-green); display: inline-flex; align-items: center; gap: 5px; }
.odf-guidecard:hover .odf-guidecard__more { color: var(--odf-ink); }

/* Tight related-guides strip (product page): boxed + tinted so it stops being
   scrolled past, 3 compact image+title cards, no excerpt. "More visible" was the
   brief - the panel lifts it off the cream page; "very compact" - one short band. */
.odf-relguides--tight { margin-top: var(--odf-sp-6); padding: var(--odf-sp-4) var(--odf-sp-5) var(--odf-sp-5);
	background: var(--odf-green-soft); border: 1px solid var(--odf-line); border-radius: var(--odf-r-lg); }
.odf-relguides--tight .odf-relguides__title { margin: 0 0 var(--odf-sp-3); font-size: var(--odf-fs-lg); }
.odf-relguides--tight .odf-guidecards { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--odf-sp-3); }
.odf-guidecard--tight .odf-guidecard__media { aspect-ratio: 16 / 10; }
.odf-guidecard--tight .odf-guidecard__body { padding: var(--odf-sp-3); gap: 6px; }
.odf-guidecard--tight .odf-guidecard__title { font-size: var(--odf-fs-sm); }
.odf-guidecard--tight .odf-guidecard__more { font-size: var(--odf-fs-xs); }
@media (max-width: 760px) { .odf-relguides--tight .odf-guidecards { grid-template-columns: 1fr 1fr; }}
@media (max-width: 460px) { .odf-relguides--tight .odf-guidecards { grid-template-columns: 1fr; }}

/* --- Brand page rail polish (2026-07-17 brand sidebar restructure) --------
   The brand page reuses the product .odf-player rail. Three refinements the
   restructure flagged: secondary details sit BELOW the range table on mobile
   (unlike the product page, where the score rail leads); the gold-edged offer
   card gets its padding back inside the rail; retailer rows get a hairline. */
@media (max-width: 900px) {
	.odf-brand-page .odf-player__rail { order: 2; margin-top: var(--odf-sp-6); }
	.odf-brand-page .odf-player__main { order: 1; }}

/* --- Sponsored ad slots (2026-07-17 monetisation) -------------------------
   Admin-managed banners rendered by the plugin's Ads::slot(). Every slot is
   clearly labelled "Sponsored" (trust guardrail + ASA), reserves its height so
   creatives never cause layout shift, and hides oversized formats on small
   screens so a 728x90 leaderboard or 160x600 skyscraper never squashes. Ads are
   display content only - they never touch a score or ranking. */
.odf-ad {
	display: block; margin: var(--odf-sp-4) auto; text-align: center;
	max-width: 100%;
}
.odf-ad__label {
	display: block; font-size: 10px; font-weight: 700; letter-spacing: .08em;
	text-transform: uppercase; color: var(--odf-ink-2); margin-bottom: 6px;
}
.odf-ad__link { display: inline-block; max-width: 100%; line-height: 0; text-decoration: none; }
.odf-ad__img { display: block; max-width: 100%; height: auto; margin: 0 auto; border-radius: var(--odf-radius-card); }
/* HTML creatives get a card frame so a bare snippet still reads as a unit. */
.odf-ad__link > :not(img), .odf-ad > :not(.odf-ad__label):not(.odf-ad__link) {
	max-width: 100%;
}

/* Format boxes reserve their slot height (no CLS). */
.odf-ad--leaderboard { max-width: 728px; }
.odf-ad--leaderboard .odf-ad__link { min-height: 90px; }
.odf-ad--mpu { max-width: 300px; }
.odf-ad--mpu .odf-ad__link { min-height: 250px; }
.odf-ad--card { max-width: 300px; }
.odf-ad--card .odf-ad__link { min-height: 340px; }
.odf-ad--skyscraper { max-width: 160px; }
.odf-ad--skyscraper .odf-ad__link { min-height: 600px; }
.odf-ad--responsive { max-width: 100%; }

/* Sidebar slots sit flush in the rail. */

/* Mobile: hide oversized formats rather than squash them. */
@media (max-width: 782px) {
	.odf-ad--leaderboard, .odf-ad--skyscraper { display: none; }}

/* --- Sticky bottom ad bar (global_sticky) ---------------------------------
   Dismissible; theme.js remembers the dismiss in a cookie (cache-safe: the bar
   is always rendered server-side and hidden client-side once dismissed). */
.odf-adsticky {
	position: fixed; left: 0; right: 0; bottom: 0; z-index: var(--odf-z-stickybar);
	background: var(--odf-card, #fff); border-top: 1px solid var(--odf-line);
	box-shadow: 0 -2px 12px rgba(0, 0, 0, .08);
}
.odf-adsticky__inner {
	display: flex; align-items: center; justify-content: center; gap: var(--odf-sp-3);
	max-width: var(--odf-container-w, 1200px); margin: 0 auto;
	padding: 8px var(--odf-sp-4); position: relative;
}
.odf-adsticky .odf-ad__label { margin: 0; flex: 0 0 auto; }
.odf-adsticky .odf-ad__link { line-height: 0; }
.odf-adsticky .odf-ad__img { max-height: 90px; width: auto; border-radius: 4px; }
.odf-adsticky__close {
	flex: 0 0 auto; margin-left: auto; display: inline-flex; align-items: center; justify-content: center;
	width: 30px; height: 30px; padding: 0; border: 1px solid var(--odf-line);
	background: var(--odf-card, #fff); color: var(--odf-ink-2); border-radius: 50%; cursor: pointer;
}
.odf-adsticky__close:hover { color: var(--odf-ink); }
.odf-adsticky__close:focus-visible { outline: 2px solid transparent; box-shadow: var(--odf-ring); }
.odf-adsticky[hidden] { display: none; }
@media (max-width: 640px) {
	.odf-adsticky .odf-ad__img { max-height: 60px; }
	.odf-adsticky__inner { padding: 6px var(--odf-sp-3); }}

/* Feeding calculator (/tools/feeding-calculator/) */
.odf-fc { display: grid; grid-template-columns: 1.4fr 1fr; gap: var(--odf-sp-5); align-items: start; margin-bottom: var(--odf-sp-7); }
.odf-fc__form { background: var(--odf-card); border: 1px solid var(--odf-line); border-radius: var(--odf-radius); padding: var(--odf-sp-5); }
.odf-fc__grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--odf-sp-4); }
.odf-fc__field { display: flex; flex-direction: column; gap: 6px; }
.odf-fc__field:first-child { grid-column: 1 / -1; }
.odf-fc__label { font-size: var(--odf-fs-sm); font-weight: 700; color: var(--odf-ink); }
.odf-fc__hint { font-weight: 500; color: var(--odf-ink-3); font-size: var(--odf-fs-xs); }
.odf-fc__inputwrap { display: flex; align-items: center; gap: 6px; background: var(--odf-surface, #fff); border: 1px solid var(--odf-line); border-radius: var(--odf-radius-sm); padding: 0 12px; }
.odf-fc__inputwrap:focus-within { border-color: var(--odf-green); box-shadow: var(--odf-ring); }
.odf-fc__inputwrap input { flex: 1 1 auto; min-width: 0; border: 0; background: transparent; padding: 11px 0; font: inherit; font-weight: 700; color: var(--odf-ink); }
.odf-fc__inputwrap input:focus { outline: none; }
.odf-fc__unit { flex: 0 0 auto; font-size: var(--odf-fs-sm); font-weight: 700; color: var(--odf-ink-3); }
.odf-fc__unit--pre { order: -1; }
.odf-fc__field select { width: 100%; padding: 11px 12px; font: inherit; font-weight: 700; color: var(--odf-ink); background: var(--odf-card); border: 1px solid var(--odf-line); border-radius: var(--odf-radius-sm); }
.odf-fc__field select:focus { outline: none; border-color: var(--odf-green); box-shadow: var(--odf-ring); }
.odf-fc__result { position: sticky; top: 88px; background: var(--odf-green-soft); border: 1px solid var(--odf-line); border-radius: var(--odf-radius); padding: var(--odf-sp-5); }
.odf-fc__headline { display: flex; flex-direction: column; align-items: center; text-align: center; padding-bottom: var(--odf-sp-4); border-bottom: 1px solid var(--odf-line); }
.odf-fc__big { font-size: 2.6rem; font-weight: 800; line-height: 1; color: var(--odf-green-deep, #0f4a37); letter-spacing: -.02em; font-variant-numeric: tabular-nums; }
.odf-fc__biglabel { font-size: var(--odf-fs-sm); font-weight: 700; color: var(--odf-ink-2); margin-top: 6px; }
.odf-fc__stats { list-style: none; margin: var(--odf-sp-4) 0 0; padding: 0; display: grid; grid-template-columns: 1fr 1fr; gap: var(--odf-sp-3); }
.odf-fc__stats li { display: flex; flex-direction: column; gap: 2px; }
.odf-fc__statv { font-size: var(--odf-fs-lg); font-weight: 800; color: var(--odf-ink); font-variant-numeric: tabular-nums; }
.odf-fc__statl { font-size: var(--odf-fs-xs); font-weight: 600; color: var(--odf-ink-3); }
.odf-fc__note { font-size: var(--odf-fs-xs); color: var(--odf-ink-2); line-height: 1.55; margin: var(--odf-sp-4) 0 0; }
.odf-fc__prose { max-width: 68ch; margin: 0 0 var(--odf-sp-6); }
@media (max-width: 820px) {
	.odf-fc { grid-template-columns: 1fr; }
	.odf-fc__result { position: static; }}
@media (max-width: 440px) {
	.odf-fc__grid { grid-template-columns: 1fr; }
	.odf-fc__stats { grid-template-columns: 1fr 1fr; }}

/* ==========================================================================
   About page (page-about.php). Everything here is composed from shared
   primitives (.odf-hero, .odf-section, .odf-panel, .odf-grid, .odf-howband,
   .odf-btn); these are the only About-specific pieces: the story/team split,
   ONE icon feature card reused by both the "problem" and "values" grids, and
   the closing CTA band.
   ========================================================================== */

/* Founding story: prose measure on the left, a "who's behind it" card right. */
.odf-about-story { display: grid; grid-template-columns: minmax(0, 1.55fr) minmax(0, 1fr); gap: var(--odf-sp-7); align-items: start; }
.odf-about-story__prose { max-width: 62ch; }
.odf-about-story__prose p { color: var(--odf-ink-2); }
.odf-about-story__prose p:first-child { font-size: var(--odf-fs-lg); color: var(--odf-ink); } /* lead-in paragraph */
.odf-about-story__prose p:last-child { margin-bottom: 0; }
@media (max-width: 860px) { .odf-about-story { grid-template-columns: 1fr; gap: var(--odf-sp-5); }}

/* Who's behind it - a compact people list inside a shared .odf-panel. */

/* Icon feature card - ONE design, used by the problem grid AND the values grid
   (build once, reuse). Green ico by default; --warn tints it gold for the
   "what's wrong today" cards. */
.odf-iconcard { background: var(--odf-card); border: 1px solid var(--odf-line); border-radius: var(--odf-radius-lg); box-shadow: var(--odf-shadow-xs); padding: var(--odf-sp-5); }
.odf-iconcard__ico { display: inline-flex; align-items: center; justify-content: center; width: 44px; height: 44px; border-radius: var(--odf-radius); background: var(--odf-green-soft); color: var(--odf-green); margin-bottom: var(--odf-sp-3); }
.odf-iconcard--warn .odf-iconcard__ico { background: var(--odf-gold-soft); color: var(--odf-gold-deep); }
.odf-iconcard__title { font-size: var(--odf-fs-base); font-weight: 800; color: var(--odf-ink); letter-spacing: -.01em; margin: 0 0 var(--odf-sp-2); line-height: var(--odf-lh-snug); }
.odf-iconcard__text { font-size: var(--odf-fs-md); color: var(--odf-ink-2); line-height: 1.55; margin: 0; }

/* Closing CTA band. */
.odf-about-cta { text-align: center; background: var(--odf-tint); border: 1px solid var(--odf-line); border-radius: 20px; padding: var(--odf-sp-8) var(--odf-sp-5); }
.odf-about-cta h2 { margin-bottom: var(--odf-sp-2); }
.odf-about-cta p { max-width: 48ch; margin: 0 auto var(--odf-sp-5); color: var(--odf-ink-2); font-size: var(--odf-fs-lg); }
.odf-about-cta__actions { display: flex; gap: var(--odf-sp-3); justify-content: center; flex-wrap: wrap; }
.home,
.home input,
.home button,
.home select,
.home textarea { font-family: var(--odf-font-sans); }
@keyframes odf-herofloat { 0%,100% { transform: translateY(0) rotate(2.2deg); } 50% { transform: translateY(-9px) rotate(2.2deg); } }

/* Compact related-guides list for the rail: titles only, no media, no excerpt.
   Reuses the .odf-guidenav card shell so it matches the TOC block above it. */
.odf-guidelist__list {
	margin: 0;
	padding: 0;
	list-style: none;
	display: flex;
	flex-direction: column;
}
.odf-guidelist__item + .odf-guidelist__item {
	border-top: 1px solid var(--odf-line);
}
.odf-guidelist__link {
	display: block;
	padding: var(--odf-sp-2) 0;
	color: var(--odf-ink);
	font-size: var(--odf-fs-sm);
	font-weight: 600;
	line-height: 1.35;
	text-decoration: none;
	text-wrap: pretty;
}
.odf-guidelist__link:hover,
.odf-guidelist__link:focus-visible {
	color: var(--odf-green);
	text-decoration: underline;
}

/* About story with the team panel removed (founder's call, 19 Jul): the grid was
   prose + panel, so without the panel it must collapse to a single column rather
   than leaving a dead 1fr gap on the right. The .odf-team rules below are kept
   deliberately - the markup is gone, not the styling, so restoring the panel is a
   template edit rather than a rebuild. */
.odf-about-story--solo { grid-template-columns: minmax(0, 1fr); }
.odf-about-story--solo .odf-about-story__prose { max-width: 68ch; }

/* =========================================================================
   THEMED SELECTS - custom chevron (founder 2026-07-19: the native arrow sat
   hard against the right border and read as cramped).
   MUST live at the END of the file: several of these selectors (.odf-dirsort,
   .odf-reviews__sort, .odf-fc__field) set the `background` SHORTHAND further up,
   which would wipe our background-image if we declared it earlier. We restate
   background-color here for the same reason.
   ========================================================================= */
.odf-fld select,
.odf-dirsort select,
.odf-reviews__sort select,
.odf-fc__field select {
	-webkit-appearance: none; -moz-appearance: none; appearance: none;
	background-color: var(--odf-card);
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%238a8d95' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
	background-repeat: no-repeat;
	background-position: right 14px center;
	background-size: 15px;
	padding-right: 40px;
}

/* =========================================================================
   "Also compare" contextual link row (facet + directory heroes). Replaces the
   auto stats sentence that used to sit here restating the card beside it:
   sibling formats / stages / properties, the matching best-of list, the hub.
   ========================================================================= */
.odf-jump {
	display: flex; flex-wrap: wrap; align-items: center; gap: var(--odf-sp-2);
	margin-top: var(--odf-sp-4);
}
.odf-jump__label {
	font-size: var(--odf-fs-xs); font-weight: 700; text-transform: uppercase;
	letter-spacing: var(--odf-tracking-wide); color: var(--odf-ink-3);
}
.odf-jump__link {
	display: inline-flex; align-items: center; gap: 6px;
	padding: 6px 13px; border-radius: var(--odf-radius-pill);
	background: var(--odf-card); border: 1px solid var(--odf-line);
	font-size: var(--odf-fs-sm); font-weight: 600; color: var(--odf-ink-2);
	text-decoration: none;
	transition: border-color var(--odf-dur) var(--odf-ease), color var(--odf-dur) var(--odf-ease);
}
.odf-jump__link:hover { border-color: var(--odf-green); color: var(--odf-green); }
/* Food-type icon on the "Also compare" chips - matches the "Narrow by format"
   drill-down so the two rows read as one system. Green like the typechips. */
.odf-jump__ico { width: 15px; height: 15px; color: var(--odf-green); flex: none; }
.odf-jump__link--strong { color: var(--odf-green); border-color: color-mix(in srgb, var(--odf-green) 35%, var(--odf-line)); }
/* The parent-hub chip ("All dog food"): filled, not outlined, so it reads as a
   level-up shortcut rather than one more sibling category. A leading arrow does
   the same job the fill does - "back up". */
.odf-jump__link--all { background: var(--odf-green); border-color: var(--odf-green); color: #fff; }
.odf-jump__link--all::before { content: "\2039"; font-weight: 700; line-height: 0; }
.odf-jump__link--all:hover { background: var(--odf-green-deep); border-color: var(--odf-green-deep); color: #fff; }

/* Search placeholders: one size down from the input text, site-wide (founder
   2026-07-19 - the full-size placeholder crowded every search box, especially
   on mobile where it truncated mid-word). Applies to the search inputs only,
   so form fields elsewhere keep their normal placeholder size. */
input[type="search"]::placeholder,
.odf-search input::placeholder,
.odf-cde-search__field input::placeholder,
.odf-gtools__search input::placeholder,
.odf-cpick__search input::placeholder {
	font-size: var(--odf-fs-sm);
	opacity: 1; /* Firefox dims placeholders by default; colour already handles it. */
}

/* Best-of pages: the below-list sections (how-to-choose, FAQ, more lists) were
   capped at the 68ch reading measure, which left the FAQ cards and the link
   tiles squeezed into a narrow column with half the page empty beside them.
   The SECTION goes full width; the running prose inside it keeps its own
   measure via .odf-prose, because 110-character lines of body copy are hard to
   read no matter how much room there is. */
.odf-dirseo--wide { max-width: none; }

/* Two-up inside the 70% column. The base .odf-tiles-quick is an auto-fit grid
   with a 360px minimum, which would drop to ONE column here - explicit two. */
.odf-tiles-quick--two { grid-template-columns: repeat(2, minmax(0, 1fr)); }

@media (max-width: 900px) {
	.odf-tiles-quick--two { grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); }}


/* --- Text & search fields: ONE focus system ------------------------------
   These had FOUR different treatments: a translucent ring outside a green
   border (read as a double border), a bare 2px outline with an offset on the
   directory box, a green border with no ring in the header, and a ring with
   no border change elsewhere. They now all do the same thing - the border
   turns green and a soft tint halo sits flush against it - so every field on
   the site focuses identically and none of them look doubled. */
.odf-input:focus,
.odf-fld input:focus,
.odf-fld textarea:focus,
.odf-fld select:focus,
.odf-search input:focus,
.odf-gtools__search input:focus,
.odf-brandix__search input:focus,
.odf-guidefilter__search input:focus,
.odf-dirsearch input[type="search"]:focus,
.odf-dirsearch input[type="search"]:focus-visible,
.odf-cde-search__field:focus-within {
	outline: none;
	border-color: var(--odf-green);
	box-shadow: var(--odf-ring-field);
}
/* A wrapper that owns the focus halo must not let its inner control draw a
   second one on top. */
.odf-cde-search__field input:focus,
.odf-cde-search__field input:focus-visible,
.odf-search__field input:focus-visible { box-shadow: none; outline: none; }

/* ==========================================================================
   /for-brands/ - the brand-accounts pitch page ([odf_for_brands]).
   Page-scoped (.odf-fb) like the homepage block, so nothing leaks out.
   ========================================================================== */
.odf-fb { display: flex; flex-direction: column; gap: var(--odf-sp-8, 56px); padding-bottom: var(--odf-sp-8, 56px); }
.odf-fb__hero { text-align: center; max-width: 720px; margin: 0 auto; padding-top: var(--odf-sp-5); }
.odf-fb__hero h1 { margin: 6px 0 var(--odf-sp-3); }
.odf-fb__lead { font-size: var(--odf-fs-md); color: var(--odf-ink-2); line-height: 1.6; margin: 0 0 var(--odf-sp-4); }
.odf-fb__ctas { display: flex; gap: var(--odf-sp-2); justify-content: center; flex-wrap: wrap; margin-bottom: var(--odf-sp-4); }
.odf-fb__ticks { list-style: none; margin: 0; padding: 0; display: flex; gap: var(--odf-sp-4); justify-content: center; flex-wrap: wrap; font-size: var(--odf-fs-sm); color: var(--odf-ink-2); }
.odf-fb__ticks li { display: inline-flex; align-items: center; gap: 6px; }
.odf-fb__ticks svg { color: var(--odf-green); }
.odf-fb__section h2, .odf-fb__soon h2 { text-align: center; margin: 0 0 var(--odf-sp-5); }
.odf-fb__grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: var(--odf-sp-3); }
.odf-fb__card { background: var(--odf-card); border: 1px solid var(--odf-line); border-radius: var(--odf-radius-card); box-shadow: var(--odf-shadow-soft); padding: var(--odf-sp-4); }
.odf-fb__cardicon { display: inline-grid; place-items: center; width: 40px; height: 40px; border-radius: 12px; background: var(--odf-green-soft); color: var(--odf-green-deep); margin-bottom: var(--odf-sp-2); }
.odf-fb__card h3 { margin: 0 0 6px; font-size: var(--odf-fs-base); }
.odf-fb__card p { margin: 0; font-size: var(--odf-fs-sm); color: var(--odf-ink-2); line-height: 1.5; }
.odf-fb__trust { text-align: center; max-width: 680px; margin: 0 auto; background: var(--odf-green-soft); border-radius: var(--odf-radius-card); padding: var(--odf-sp-5); }
.odf-fb__trust h2 { margin: 0 0 var(--odf-sp-2); }
.odf-fb__trust p { margin: 0 0 var(--odf-sp-2); color: var(--odf-ink-2); line-height: 1.6; }
.odf-fb__trustlink { margin: 0; }
.odf-fb__trustlink a { font-weight: 700; color: var(--odf-green-deep); }
.odf-fb__steps { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: var(--odf-sp-4); counter-reset: fbstep; }
.odf-fb__steps li { display: flex; gap: var(--odf-sp-3); align-items: flex-start; }
.odf-fb__stepnum { flex: none; width: 34px; height: 34px; display: grid; place-items: center; border-radius: 50%; background: var(--odf-green); color: #fff; font-weight: 800; }
.odf-fb__steps h3 { margin: 4px 0 4px; font-size: var(--odf-fs-base); }
.odf-fb__steps p { margin: 0; font-size: var(--odf-fs-sm); color: var(--odf-ink-2); line-height: 1.5; }
.odf-fb__soonrow { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: var(--odf-sp-3); max-width: 680px; margin: 0 auto; }
.odf-fb__sooncard { position: relative; background: var(--odf-tint); border: 1px dashed var(--odf-line); border-radius: var(--odf-radius-card); padding: var(--odf-sp-4); }
.odf-fb__soonchip { position: absolute; top: 12px; right: 12px; font-size: 10px; font-weight: 800; letter-spacing: .05em; text-transform: uppercase; color: var(--odf-ink-3); background: var(--odf-card); border: 1px solid var(--odf-line); border-radius: var(--odf-radius-pill); padding: 2px 8px; }
.odf-fb__sooncard h3 { margin: 0 0 6px; font-size: var(--odf-fs-base); }
.odf-fb__sooncard p { margin: 0; font-size: var(--odf-fs-sm); color: var(--odf-ink-2); }
.odf-fb__soonnote { text-align: center; margin: var(--odf-sp-4) 0 0; font-size: var(--odf-fs-sm); color: var(--odf-ink-3); }
.odf-fb__band { text-align: center; background: var(--odf-ink); color: #fff; border-radius: var(--odf-radius-card); padding: var(--odf-sp-6, 40px) var(--odf-sp-5); }
.odf-fb__band h2 { color: #fff; margin: 0 0 var(--odf-sp-3); }

/* /for-brands/ request form */
.odf-fb__request { max-width: 620px; margin: 0 auto; scroll-margin-top: 90px; }
.odf-fb__request h2 { text-align: center; margin: 0 0 var(--odf-sp-4); }
.odf-fb__form { background: var(--odf-card); border: 1px solid var(--odf-line); border-radius: var(--odf-radius-card); box-shadow: var(--odf-shadow-card); padding: var(--odf-sp-5); }
.odf-fb__form label { display: block; font-weight: 700; font-size: var(--odf-fs-sm); margin-bottom: var(--odf-sp-3); }
.odf-fb__form input, .odf-fb__form textarea { width: 100%; margin-top: 6px; border: 1.5px solid var(--odf-line); border-radius: 10px; padding: 11px 14px; font: inherit; font-size: var(--odf-fs-sm); font-weight: 400; background: var(--odf-card); }
.odf-fb__form input:focus, .odf-fb__form textarea:focus { outline: 2px solid var(--odf-green); outline-offset: 1px; border-color: var(--odf-green); }
.odf-fb__formrow { display: grid; grid-template-columns: 1fr 1fr; gap: var(--odf-sp-3); }
@media (max-width: 560px) { .odf-fb__formrow { grid-template-columns: 1fr; }}
.odf-fb__formnote { margin: var(--odf-sp-3) 0 0; font-size: var(--odf-fs-xs); color: var(--odf-ink-3); }

/* /site-map/ - the live human site map */
.odf-sitemap h2 { margin: var(--odf-sp-5) 0 var(--odf-sp-2); font-size: var(--odf-fs-lg); }
.odf-sitemap__list { list-style: none; margin: 0; padding: 0; columns: 3 220px; column-gap: var(--odf-sp-5); }
.odf-sitemap__list li { break-inside: avoid; padding: 3px 0; font-size: var(--odf-fs-sm); }
.odf-sitemap__list a { color: var(--odf-ink-2); }
.odf-sitemap__list a:hover { color: var(--odf-green-deep); }

/* Legal-page footnote under an embedded form ("Prefer email? ...") */
.odf-legal__altnote { text-align: center; margin-top: var(--odf-sp-3); font-size: var(--odf-fs-sm); color: var(--odf-ink-3); }
.odf-legal__altnote a { font-weight: 700; color: var(--odf-green-deep); }
