/* ==========================================================================
   Commodities.tz Network — Design System
   Principles: trust, data, trade, origin, quality. High information density,
   restrained palette, no gradients/pills/unnecessary motion. Body/heading
   copy stays on system fonts (performance + zero licensing risk); the two
   webfonts below are self-hosted (no external request) and scoped ONLY to
   the portal brand lockup (.czn-logo) — see docs/BRAND-IDENTITY.md.
   ========================================================================== */

@font-face {
	font-family: "Fraunces";
	src: url("../fonts/fraunces-600.woff2") format("woff2");
	font-weight: 600;
	font-style: normal;
	font-display: swap;
}
@font-face {
	font-family: "Fraunces";
	src: url("../fonts/fraunces-700.woff2") format("woff2");
	font-weight: 700;
	font-style: normal;
	font-display: swap;
}
@font-face {
	font-family: "Archivo";
	src: url("../fonts/archivo-500.woff2") format("woff2");
	font-weight: 500;
	font-style: normal;
	font-display: swap;
}
@font-face {
	font-family: "Archivo";
	src: url("../fonts/archivo-600.woff2") format("woff2");
	font-weight: 600;
	font-style: normal;
	font-display: swap;
}
@font-face {
	font-family: "Archivo";
	src: url("../fonts/archivo-700.woff2") format("woff2");
	font-weight: 700;
	font-style: normal;
	font-display: swap;
}

:root {
	/* Neutral scale */
	--czn-ink-900: #16201b;
	--czn-ink-700: #33413a;
	--czn-ink-500: #5b6b62;
	--czn-ink-300: #97a69c;
	--czn-ink-100: #e4e9e3;
	--czn-paper: #faf9f5;
	--czn-paper-raised: #ffffff;
	--czn-border: #d8ddd2;

	/* Brand */
	--czn-primary: #0f5132;
	--czn-primary-dark: #0a3a23;
	--czn-primary-tint: #e7f0ea;
	--czn-accent: var(--czn-primary);
	--czn-accent-tint: var(--czn-primary-tint);
	/* Dedicated token (not --czn-primary-dark) so the commodity nav's white
	   text keeps sufficient contrast in dark mode, where --czn-primary-dark
	   is swapped to a light green that fails against #fff. */
	--czn-commodity-nav-bg: var(--czn-primary-dark);

	/* Semantic */
	--czn-success: #256d3b;
	--czn-warning: #8a5a00;
	--czn-danger: #9b2c2c;
	--czn-focus: #1c6dd0;

	/* Type */
	--czn-font-serif: Georgia, "Iowan Old Style", Cambria, "Times New Roman", serif;
	--czn-font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
	--czn-font-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
	/* Brand lockup only (.czn-logo) — see docs/BRAND-IDENTITY.md section on
	   typography. Not used for site-wide headings (those stay on the serif
	   stack above; this project's scope is the brand area, not a full
	   type-system replacement). */
	--czn-font-wordmark: "Fraunces", Georgia, "Iowan Old Style", Cambria, serif;
	--czn-font-wordmark-support: "Archivo", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;

	/* Spacing scale (4px base) */
	--czn-space-1: 0.25rem;
	--czn-space-2: 0.5rem;
	--czn-space-3: 0.75rem;
	--czn-space-4: 1rem;
	--czn-space-5: 1.5rem;
	--czn-space-6: 2rem;
	--czn-space-7: 3rem;
	--czn-space-8: 4.5rem;

	--czn-radius: 3px;
	--czn-radius-lg: 6px;
	--czn-shadow: 0 1px 2px rgba(22, 32, 27, 0.06), 0 1px 1px rgba(22, 32, 27, 0.04);
	--czn-shadow-raised: 0 4px 16px rgba(22, 32, 27, 0.10);
	--czn-max-width: 1240px;

	/* Supplier Pro (launch, 2026-09-28): a warm gold/bronze accent,
	   deliberately distinct from --czn-primary (green, used by the
	   verification-status axis) and from every existing badge color pair
	   above — Pro is a subscription tier, never to be visually confused
	   with an evidence/verification signal. */
	--czn-pro-accent: #96690d;
	--czn-pro-accent-dark: #6f4d09;
	--czn-pro-tint: #fbf1de;

	/* Sponsored ads (Sponsored Supplier Advertising launch, 2026-09-28):
	   deliberately a NEUTRAL, muted disclosure-label color — never the gold
	   Pro-accent — so "Sponsored" (a disclosure requirement) is never
	   visually confused with "Supplier Pro" (a product-tier badge), even
	   though today every launch advertiser happens to be a Pro supplier and
	   both badges render side by side. */
	--czn-ad-label-bg: var(--czn-ink-100);
	--czn-ad-label-color: var(--czn-ink-500);
}

@media (prefers-color-scheme: dark) {
	:root {
		--czn-ink-900: #eef2ea;
		--czn-ink-700: #cbd6c8;
		--czn-ink-500: #9aab9f;
		--czn-ink-300: #56645b;
		--czn-ink-100: #263229;
		--czn-paper: #131a15;
		--czn-paper-raised: #1a231c;
		--czn-border: #2d3a30;
		--czn-primary: #4bad78;
		--czn-primary-dark: #7ecba0;
		--czn-primary-tint: #1c2e22;
		--czn-accent-tint: #1c2e22;
		/* --czn-primary-dark inverts to a light green here (correct for the
		   text/link uses it has elsewhere), so the commodity nav needs its
		   own genuinely-dark background to keep white text legible. */
		--czn-commodity-nav-bg: var(--czn-ink-100);
		--czn-pro-accent: #e0ab52;
		--czn-pro-accent-dark: #f0c273;
		--czn-pro-tint: #332608;
	}
}

/* Reset --------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }
html {
	-webkit-text-size-adjust: 100%;
	/* Defends against off-canvas mobile-nav / unwrapped-table regressions
	   introducing page-level horizontal scroll; overflow-y intentionally
	   untouched so it never interferes with position:sticky. */
	overflow-x: hidden;
}
body {
	margin: 0;
	background: var(--czn-paper);
	color: var(--czn-ink-900);
	font-family: var(--czn-font-sans);
	font-size: 16px;
	line-height: 1.55;
	-webkit-font-smoothing: antialiased;
	overflow-x: hidden;
}
img, svg { max-width: 100%; display: block; height: auto; }
a { color: var(--czn-accent); text-decoration: none; }
a:hover { text-decoration: underline; }
/* Links inside a block of running text must be distinguishable by more than
   color alone (WCAG 1.4.1) — nav/card/button links are exempt since they're
   already structurally distinct as a list/component, not prose. */
p a, li.czn-prose-link a, .czn-prose a, .czn-lede a, .czn-source-note a, .czn-empty-state p a, .czn-commodity-nav > .czn-container > span:first-child a {
	text-decoration: underline;
	text-underline-offset: 0.15em;
}
h1, h2, h3, h4 { font-family: var(--czn-font-serif); line-height: 1.2; margin: 0 0 var(--czn-space-4); color: var(--czn-ink-900); font-weight: 600; }
h1 { font-size: clamp(1.9rem, 1.5rem + 1.6vw, 2.75rem); }
h2 { font-size: clamp(1.5rem, 1.3rem + 0.8vw, 2rem); }
h3 { font-size: 1.25rem; }
p { margin: 0 0 var(--czn-space-4); }
ul, ol { padding-left: 1.25em; }
table { border-collapse: collapse; width: 100%; }
button, input, select, textarea { font-family: inherit; font-size: 1rem; }

:focus-visible {
	outline: 3px solid var(--czn-focus);
	outline-offset: 2px;
}

.czn-skip-link {
	position: absolute;
	left: -9999px;
	top: 0;
	background: var(--czn-primary);
	color: #fff;
	padding: 0.75em 1.25em;
	z-index: 1000;
}
.czn-skip-link:focus { left: 0; }

/* The header is sticky, so a bare fragment jump (skip-link, or any future
   in-page #anchor) lands content right under it, hidden behind the pinned
   bar. scroll-margin-top reserves space so the target actually becomes
   visible. Value covers the tallest observed sticky header (mobile,
   wrapped logo/tagline, ~129px) plus a small buffer. */
#czn-main { scroll-margin-top: 140px; }

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

/* Layout ---------------------------------------------------------------- */
.czn-container {
	max-width: var(--czn-max-width);
	margin: 0 auto;
	padding: 0 var(--czn-space-5);
}
.czn-section { padding: var(--czn-space-7) 0; }
.czn-section-tight { padding: var(--czn-space-6) 0; }
.czn-section-alt { background: var(--czn-paper-raised); border-top: 1px solid var(--czn-border); border-bottom: 1px solid var(--czn-border); }
.czn-grid { display: grid; gap: var(--czn-space-5); }
.czn-grid-2 { grid-template-columns: repeat(2, 1fr); }
.czn-grid-3 { grid-template-columns: repeat(3, 1fr); }
.czn-grid-4 { grid-template-columns: repeat(4, 1fr); }
@media (max-width: 900px) { .czn-grid-3, .czn-grid-4 { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 620px) { .czn-grid-2, .czn-grid-3, .czn-grid-4 { grid-template-columns: 1fr; } }

.czn-eyebrow {
	font-family: var(--czn-font-mono);
	font-size: 0.72rem;
	letter-spacing: 0.09em;
	text-transform: uppercase;
	color: var(--czn-primary);
	font-weight: 600;
	display: block;
	margin-bottom: var(--czn-space-2);
}
.czn-lede { font-size: 1.1rem; color: var(--czn-ink-700); max-width: 62ch; }

/* Header ------------------------------------------------------------- */
.czn-header {
	border-bottom: 1px solid var(--czn-border);
	background: var(--czn-paper-raised);
	position: sticky;
	top: 0;
	z-index: 100;
}
/* --czn-header-brand-gap is the protected minimum space between the brand
   block and the nav group — set explicitly rather than left to whatever
   justify-content: space-between happens to have left over, which shrank to
   12px (space-3) below 1400px and let long wordmarks/nav crowd the brand
   (Network-Wide Header Spacing Correction, 2026-09-30). */
:root { --czn-header-brand-gap: 40px; }
.czn-header-inner { display: flex; align-items: center; justify-content: space-between; gap: var(--czn-header-brand-gap); padding: var(--czn-space-4) 0; flex-wrap: nowrap; }
/* The header row gets a wider budget than the shared 1240px reading-width
   .czn-container (BlackPepper header responsive-regression fix, 2026-09-30):
   at >=1400px viewport there's real spare screen width the 1240px content
   cap was leaving unused, and BlackPepper/Cardamom/CoffeeBean's full-size
   brand+nav+utilities (no longer shrunk below 1400px — see the removed
   block further down) need up to ~1268px to render with a real 60-80px
   brand-nav gap. Compound selector (.czn-header-inner.czn-container) beats
   plain .czn-container on specificity regardless of source order, so this
   doesn't require !important and doesn't touch .czn-container anywhere else
   on the page (hero/body sections keep the normal 1240px reading width). */
/* 1320px -> 1460px (2026-10-06): the "Opportunities" nav item added network-
   wide for Events/Training/MARKUP II discovery consumed nearly all of the
   headroom the 2026-10-01/2026-10-05 nav-wrap fixes built in (several
   portals measured at or past their old budget with the new item added,
   re-triggering the hamburger fallback at 1440px — see
   qa_events_training_playwright.py's nav-wrap findings). 1460px restores a
   comfortable ~130-140px margin, matching this project's existing headroom
   convention (commodities.tz/BlackPepper/Cardamom/CoffeeBean's per-host
   overrides below get the same treatment). Portals already on a per-host
   override are unaffected by this fallback value. */
.czn-header-inner.czn-container { max-width: var(--czn-header-max-width, 1460px); }
.czn-header-nav-group { display: flex; align-items: center; gap: var(--czn-space-5); }
.czn-commodity-nav {
	background: var(--czn-commodity-nav-bg);
	color: #fff;
	font-size: 0.78rem;
}
.czn-commodity-nav .czn-container {
	display: flex;
	align-items: center;
	gap: var(--czn-space-3);
	padding-top: var(--czn-space-1);
	padding-bottom: var(--czn-space-1);
	flex-wrap: nowrap; /* a bar that wraps to 2 lines is exactly what this component must avoid — horizontal scroll (below) replaces wrapping */
	position: relative;
}
.czn-commodity-nav-intro { flex-shrink: 0; white-space: nowrap; padding: 0.4em 0; opacity: 0.9; }
/* Was text-only at ~20px tall (under the 24px WCAG 2.5.8 AA minimum);
   vertical padding grows the tap target without disturbing the bar's gap-driven horizontal spacing. */
.czn-commodity-nav a { display: inline-block; padding: 0.4em 0.5em; color: #fff; opacity: 0.9; white-space: nowrap; }
.czn-commodity-nav a:hover { opacity: 1; }
.czn-commodity-nav a[aria-current="page"] { opacity: 1; font-weight: 600; text-decoration: underline; text-underline-offset: 0.2em; }
/* Wraps just the scrollable commodity list (not the whole bar) so the
   edge-fade below tracks the list's own right edge, not a network-level
   link (e.g. Export.tz) that may sit after it — see .czn-commodity-nav-network. */
.czn-commodity-nav-scroll { position: relative; min-width: 0; flex: 1 1 auto; }
/* Edge-fades signal "more content to scroll" and are gated on .has-overflow
   (set by app.js from actual scrollWidth/clientWidth) plus .is-at-start /
   .is-at-end (also app.js, from scrollLeft) so a fade never shows toward a
   direction there's nothing left to scroll to. Opacity-only + a transition,
   not display, so toggling never shifts layout. */
.czn-commodity-nav-scroll::before,
.czn-commodity-nav-scroll::after {
	content: '';
	position: absolute;
	top: 0; bottom: 0;
	width: 24px;
	pointer-events: none;
	opacity: 0;
	transition: opacity 0.15s ease;
}
.czn-commodity-nav-scroll::before { left: 0; background: linear-gradient(to left, transparent, var(--czn-commodity-nav-bg)); }
.czn-commodity-nav-scroll::after { right: 0; background: linear-gradient(to right, transparent, var(--czn-commodity-nav-bg)); }
.czn-commodity-nav.has-overflow .czn-commodity-nav-scroll:not(.is-at-start)::before { opacity: 1; }
.czn-commodity-nav.has-overflow .czn-commodity-nav-scroll:not(.is-at-end)::after { opacity: 1; }
/* Prev/next controls flanking the scroll strip. Hidden by default (and
   `disabled` in the markup) so a no-JS visitor never sees a dead control;
   app.js reveals them only once it measures real overflow, and keeps them
   in sync with scroll position — see assets/js/app.js. */
.czn-commodity-nav-arrow {
	display: none;
	flex-shrink: 0;
	align-items: center;
	justify-content: center;
	width: 26px;
	height: 26px;
	padding: 0;
	border: 1px solid rgba(255, 255, 255, 0.35);
	border-radius: 999px;
	background: rgba(255, 255, 255, 0.08);
	color: #fff;
	cursor: pointer;
	transition: background-color 0.15s ease, opacity 0.15s ease;
}
.czn-commodity-nav.has-overflow .czn-commodity-nav-arrow { display: inline-flex; }
.czn-commodity-nav-arrow svg { pointer-events: none; }
.czn-commodity-nav-arrow:hover:not(:disabled) { background: rgba(255, 255, 255, 0.2); }
.czn-commodity-nav-arrow:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }
.czn-commodity-nav-arrow:disabled { opacity: 0.3; cursor: default; }
/* Network-level destinations (Export.tz), visually separated from the
   commodity list by a divider so they read as a network service rather
   than another commodity. Never shrinks/scrolls — always fully visible,
   including on narrow phones, where it's what keeps the commodity list
   (which scrolls instead of compressing) from swallowing the only way to
   find Export.tz. */
.czn-commodity-nav-network {
	flex-shrink: 0;
	display: flex;
	align-items: center;
	gap: var(--czn-space-1);
	padding-left: var(--czn-space-3);
	border-left: 1px solid rgba(255, 255, 255, 0.3);
}
.czn-commodity-nav-network a { display: inline-flex; align-items: center; gap: 0.3em; }
.czn-commodity-nav-network a svg { opacity: 0.75; flex-shrink: 0; }
@media (max-width: 480px) {
	.czn-commodity-nav-intro { display: none; } /* full width for the scroll strip on phones */
	.czn-commodity-nav-network { padding-left: var(--czn-space-2); }
	/* Smaller/subtler on phones, where touch/swipe is the primary way to move
	   the strip — the arrows are still a discoverability cue, just not the
	   main interaction, so they shouldn't eat into the scroll strip's width. */
	.czn-commodity-nav-arrow { width: 22px; height: 22px; }
	/* The arrows add two more flex items (and gaps) to .czn-container. At
	   this width every reclaimed pixel matters for the longest commodity
	   labels (e.g. "Black Pepper") staying reasonably in view once centered
	   on load — tightening the row gap here costs no readability (arrows and
	   the Export.tz link still have a clear gap, just a smaller one). */
	.czn-commodity-nav .czn-container { gap: var(--czn-space-2); }
}

/* Brand lockup (Single-Row Header Redesign, 2026-09-30) --------------------
   .czn-logo is the shared emblem+wordmark unit, used in two contexts:
     .czn-logo-hero    — the single-row sticky header (below): emblem large
                          and clearly recognizable, wordmark + tagline
                          stacked beside it (name on top, tagline under it),
                          nav/CTA/search/account sitting to its right in the
                          same row. Not a separate masthead — there is only
                          one portal-identity element on the page now.
     .czn-logo-compact — the footer only. Wayfinding-scale mark, no tagline.
   Both share the same row layout (mark left, text right) and the same
   typographic rules below; only size differs per context. */
.czn-logo { display: flex; align-items: center; gap: 0.65em; color: var(--czn-ink-900); text-decoration: none; }
.czn-logo-mark { display: flex; flex-shrink: 0; }
.czn-logo-mark svg.czn-brand-mark { display: block; }
.czn-logo-word { display: flex; flex-direction: column; line-height: 1.05; }
.czn-logo-name {
	font-family: var(--czn-font-wordmark);
	font-weight: 600;
	font-size: 1.9rem;
	letter-spacing: -0.01em;
	color: var(--czn-ink-900);
	/* The primary wordmark never wraps, at any width — only the tagline
	   below is allowed to grow to two lines (brief section 10). */
	white-space: nowrap;
}
/* .tz set in the support sans, smaller and in the portal accent color —
   a deliberate typographic unit (brief section 3), not hidden or an
   afterthought the way a plain heading style would render it. */
.czn-logo-tz {
	font-family: var(--czn-font-wordmark-support);
	font-weight: 600;
	font-size: 0.62em;
	color: var(--czn-accent);
	letter-spacing: 0.01em;
}
.czn-logo-compact .czn-logo-name { font-size: 1.15rem; }
/* Footer sits on a dark background; the marks are multi-tone illustrations
   (not currentColor-dependent silhouettes) so they read correctly as-is —
   only the wordmark needs the light-on-dark override. */
.czn-footer .czn-logo-name { color: #fff; }
.czn-footer .czn-logo-tz { color: var(--czn-accent); }

/* .czn-logo-hero: the header's brand block — emblem left, name+tagline
   stacked to its right, sized to hold its own next to the nav/CTA/search
   sharing the same row (brief: large enough to read at a glance, without
   crowding out the navigation). */
.czn-logo-hero { gap: 0.9em; }
.czn-logo-hero .czn-logo-mark svg.czn-brand-mark { height: 72px; width: auto; }
.czn-logo-hero .czn-logo-name { font-size: 1.9rem; }
/* align-items: center (not the default stretch) lets the shorter element —
   almost always the tagline, once bounded by max-width below — sit centered
   under the wider one, so a wrapped two-line tagline reads as a balanced
   block under the wordmark rather than left-heavy (brief sections 7-8). */
.czn-logo-text { display: flex; flex-direction: column; align-items: center; gap: 0.15em; justify-content: center; }
.czn-header-tagline {
	font-family: var(--czn-font-wordmark-support);
	font-weight: 600;
	font-size: 0.72rem;
	letter-spacing: 0.13em;
	text-transform: uppercase;
	color: var(--czn-ink-500);
	/* Bounded + centered instead of nowrap: a short tagline (e.g. Honey.tz,
	   21 chars) fits this comfortably on one line; a long one (Chocolate.tz
	   53 chars, Markets.tz 58) wraps to a balanced two-line block instead of
	   growing indefinitely into nav territory (Network-Wide Header Spacing
	   Correction, 2026-09-30 — brief sections 6-9). text-wrap: balance
	   degrades to plain wrapping on browsers that don't support it. */
	white-space: normal;
	text-align: center;
	/* 36ch keeps every active one-line-worthy tagline on one line (up to
	   Vanilla.tz's 34 chars) and only wraps the genuinely long ones —
	   Export.tz (40), Commodities.tz (52), Chocolate.tz (53), Markets.tz
	   (58). A tighter cap (26ch, tried first) wrapped short taglines like
	   Honey.tz's 21-char one for no reason — exactly what brief section 39
	   warns against. */
	max-width: 36ch;
	text-wrap: balance;
}
/* REMOVED 2026-09-30 (BlackPepper header responsive-regression fix): this
   block used to shrink the logo/nav/actions at <=1400px as a fixed-viewport
   alternative to overflow. It predates (or was never reconciled with)
   app.js's updateHeaderNavOverflow(), which measures REAL overflow
   continuously and is explicitly designed to be the only such mechanism
   ("Rather than shrink text to unreadable sizes or hardcode a per-portal
   breakpoint..." — see app.js). With both active, brand/nav rendered at
   full (large) size above 1400px and shrunk below it — two DIFFERENT
   required-content-widths either side of one pixel, so whichever side had
   less container slack could flip independently of the other, producing a
   non-monotonic result: BlackPepper (and Cardamom/CoffeeBean, the next-
   longest wordmarks) genuinely didn't fit at >=1401px (hamburger), fit fine
   at 1280-1400px (shrunk tier had slack), then didn't fit again at
   ~1024-1100px (shrunk tier's own fixed floor exceeded the container) —
   nav appearing, disappearing, and reappearing as the viewport narrowed.
   Removing this makes brand/nav/actions ONE constant size at every desktop
   width; updateHeaderNavOverflow() is now the single source of truth for
   the nav-vs-hamburger switch, which is therefore strictly monotonic (the
   required content width no longer changes with viewport, so overflow can
   only ever increase as the container narrows). See also the widened
   .czn-header-inner.czn-container max-width above, which is the other half
   of this fix — without it, the full-size content (needs ~1268px for
   BlackPepper's 64px brand-nav gap) would never fit even at 1920px, since
   .czn-container alone caps every viewport's content width at 1240px. */
@media (max-width: 480px) {
	.czn-header-inner { padding: var(--czn-space-3) 0; }
	.czn-logo-hero { gap: 0.6em; }
	.czn-logo-hero .czn-logo-mark svg.czn-brand-mark { height: 40px; width: auto; }
	.czn-logo-hero .czn-logo-name { font-size: 1.2rem; }
	.czn-header-tagline { font-size: 0.58rem; letter-spacing: 0.08em; max-width: 22ch; }
}

/* Gap tightened from var(--czn-space-5) (24px) to a fixed 14px (2026-10-05,
   Services & Testing network-wide fix): the .czn-header-inner.czn-container
   max-width cap (1320px, or the per-host override above) is a constant
   content-width budget independent of viewport — measured via headless
   Chromium across all 18 active portals x 6 desktop widths (1920-1024px),
   wrapping Services & Testing at 1920px was just as common as at 1366px,
   since nothing about a wider viewport grants this row any more room once
   the container cap is already the binding constraint. 24px x ~9 nav gaps
   was costing ~70-90px that bought nothing visually (confirmed via
   side-by-side screenshot at 1440px: 14px still reads as clearly separated,
   clickable items) but was exactly the slack needed to let the one
   multi-word item (now also joined via czn_nav_label_html() in
   functions.php) sit on one line instead of wrapping. Only .czn-nav's own
   base rule changes — both the >=900px JS-measured .is-nav-compact fallback
   and the <=900px off-canvas media query re-declare their own gap
   (var(--czn-space-4)) and are untouched by this. */
.czn-nav { display: flex; gap: 0.875rem; align-items: center; }
/* Vertical-only padding: grows the tap target (was ~23px tall, under the
   24px WCAG 2.5.8 AA minimum) without touching the horizontal gaps the
   parent flex `gap` already controls, so desktop bar width is unaffected. */
.czn-nav a { color: var(--czn-ink-700); font-size: 0.94rem; font-weight: 500; line-height: 1.2; white-space: nowrap; }
/* nowrap (2026-10-05, supersedes the controlled-2-line approach from the
   same morning's czn_nav_label_html() session): a multi-word label is no
   longer allowed to wrap internally at all. Previously, as a flex item with
   default flex-shrink:1/min-width:auto, a nav link's min-content floor sits
   far below its full width — the browser would shrink it down to that floor
   before ever triggering the row's own overflow check, so a long label
   silently fragmented into 2 lines while headerInner.scrollWidth still
   read <= clientWidth (app.js never saw a reason to fall back to the
   hamburger). With nowrap, a link's min-content width == its full width, so
   once the row genuinely can't fit every item on one line,
   updateHeaderNavOverflow()'s scrollWidth/clientWidth measurement (app.js)
   correctly detects it and the WHOLE nav drops to the existing off-canvas
   hamburger menu — no more intermediate "some items start wrapping" state.
   czn_nav_label_html()'s nbsp-join is now a no-op for line-breaking (nowrap
   forbids all breaks) but still harmless to leave in place. */
.czn-nav a:not(.czn-btn) { display: inline-block; padding: 0.55em 0; }
.czn-nav a:hover, .czn-nav a[aria-current="page"] { color: var(--czn-accent); text-decoration: none; }
/* .czn-nav a's specificity (class+element) otherwise beats .czn-btn-primary's
   (class only), silently dropping its white text onto a dark accent
   background — a real WCAG contrast failure caught by axe-core. */
.czn-nav a.czn-btn-primary { color: #fff; }
.czn-nav a.czn-btn-primary:hover { color: #fff; }

.czn-header-actions { display: flex; align-items: center; gap: var(--czn-space-3); }
/* Search icon link: was a raw 20px icon plus inline padding:0.4em (~31px
   box, below the 44px touch-target guideline); sized here instead of via
   an inline style so both axes get a consistent, larger tap area. */
.czn-header-actions a[aria-label="Search"] { display: inline-flex; align-items: center; justify-content: center; width: 44px; height: 44px; padding: 0; }
.czn-nav-toggle { display: none; align-items: center; justify-content: center; width: 44px; height: 44px; background: none; border: 1px solid var(--czn-border); border-radius: var(--czn-radius); padding: 0; }

/* JS-measured fallback (app.js updateHeaderNavOverflow) for portals whose
   nav genuinely doesn't fit the row at a given width (e.g. Markets.tz,
   Commodities.tz) — same off-canvas treatment as the @media rule below,
   just triggered by real overflow instead of a fixed viewport width. */
.czn-header.is-nav-compact .czn-nav { position: fixed; inset: 0 0 0 30%; background: var(--czn-paper-raised); flex-direction: column; align-items: flex-start; padding: var(--czn-space-7) var(--czn-space-5); gap: var(--czn-space-4); transform: translateX(100%); transition: transform 0.2s ease; box-shadow: var(--czn-shadow-raised); z-index: 110; }
.czn-header.is-nav-compact .czn-nav.is-open { transform: translateX(0); }
.czn-header.is-nav-compact .czn-nav-toggle { display: inline-flex; }

@media (max-width: 900px) {
	.czn-nav { position: fixed; inset: 0 0 0 30%; background: var(--czn-paper-raised); flex-direction: column; align-items: flex-start; padding: var(--czn-space-7) var(--czn-space-5); gap: var(--czn-space-4); transform: translateX(100%); transition: transform 0.2s ease; box-shadow: var(--czn-shadow-raised); }
	.czn-nav.is-open { transform: translateX(0); }
	.czn-nav-toggle { display: inline-flex; }
}

/* Buttons -------------------------------------------------------------- */
.czn-btn {
	display: inline-flex;
	align-items: center;
	gap: 0.5em;
	padding: 0.65em 1.25em;
	border-radius: var(--czn-radius);
	font-weight: 600;
	font-size: 0.95rem;
	border: 1px solid transparent;
	cursor: pointer;
	white-space: nowrap;
}
.czn-btn-primary { background: var(--czn-accent); color: #fff; }
.czn-btn-primary:hover { background: var(--czn-primary-dark); text-decoration: none; }
.czn-btn-secondary { background: transparent; color: var(--czn-ink-900); border-color: var(--czn-border); }
.czn-btn-secondary:hover { border-color: var(--czn-accent); color: var(--czn-accent); text-decoration: none; }
.czn-btn-sm { padding: 0.4em 0.9em; font-size: 0.85rem; white-space: nowrap; }
/* .czn-btn-long: for standalone CTAs whose label includes dynamic content
   (a commodity name, a data-point count) that can push a nowrap button past
   a narrow viewport — found 2026-10-07 overflowing on three portals whose
   commodity name + fixed phrase happened to be long enough to trip it.
   Unlike the base .czn-btn, these are single buttons on their own line (not
   siblings in a tight row), so wrapping the label is safe here in a way it
   wouldn't be for every .czn-btn use. */
@media (max-width: 480px) {
	.czn-btn-long { white-space: normal; text-align: center; }
}

/* Cards ------------------------------------------------------------------ */
.czn-card {
	background: var(--czn-paper-raised);
	border: 1px solid var(--czn-border);
	border-radius: var(--czn-radius-lg);
	padding: var(--czn-space-5);
}
/* Card section headings are sometimes h2 (e.g. supplier-profile "Profile" /
   "Processing capability", correctly following the page's single h1 with no
   level skipped) and sometimes h3 elsewhere; keep them visually consistent
   with the rest of the card system regardless of which level is correct. */
.czn-card h2 { font-family: var(--czn-font-serif); font-size: 1.25rem; }
.czn-card-link { display: block; color: inherit; transition: border-color 0.15s ease, box-shadow 0.15s ease; }
.czn-card-link:hover { text-decoration: none; border-color: var(--czn-accent); box-shadow: var(--czn-shadow); }

.czn-commodity-card { text-align: left; }
.czn-commodity-card .czn-eyebrow { margin-bottom: var(--czn-space-1); }

/* Badges ------------------------------------------------------------------ */
.czn-badge {
	display: inline-block;
	font-size: 0.72rem;
	font-weight: 600;
	padding: 0.2em 0.6em;
	border-radius: 999px;
	background: var(--czn-ink-100);
	color: var(--czn-ink-700);
	white-space: nowrap;
}
.czn-badge-verified { background: var(--czn-primary-tint); color: var(--czn-primary); }
.czn-badge-source_confirmed { background: #eef3fb; color: var(--czn-focus); }
.czn-badge-listed { background: var(--czn-ink-100); color: var(--czn-ink-500); }

/* Supplier Pro badge — a subscription-tier label, deliberately never reusing
   a verification-status color (section 3: Pro must never read as "verified
   because Pro"). Restrained: no gradient, no icon beyond a plain diamond
   glyph, same pill shape as every other badge on the network. */
.czn-badge-pro { background: var(--czn-pro-tint); color: var(--czn-pro-accent-dark); font-weight: 700; letter-spacing: 0.03em; }
.czn-badge-pro-glyph { margin-right: 0.3em; }

/* Redistribution-status badges (Phase 6 legal review, /sources/ page). */
.czn-badge-redistribution.czn-badge-redistribution_allowed,
.czn-badge-redistribution.czn-badge-redistribution_allowed_attribution { background: #eaf5ea; color: #276b27; }
.czn-badge-redistribution.czn-badge-display_only { background: var(--czn-ink-100); color: var(--czn-ink-500); }
.czn-badge-redistribution.czn-badge-link_only { background: #fdeaea; color: #9c2b2b; }
.czn-badge-redistribution.czn-badge-unclear_pending_review { background: #fdf3e0; color: #8a5a00; }
@media (prefers-color-scheme: dark) {
	.czn-badge-redistribution.czn-badge-redistribution_allowed,
	.czn-badge-redistribution.czn-badge-redistribution_allowed_attribution { background: #1c3320; color: #a8dba8; }
	.czn-badge-redistribution.czn-badge-link_only { background: #3a1f1f; color: #e3a3a3; }
	.czn-badge-redistribution.czn-badge-unclear_pending_review { background: #332409; color: #e3b464; }
}

/* Reliability-tier badges (Phase 15 source register, /sources/ page). A
   separate axis from redistribution above — deliberately reuses none of its
   colors so the two are never visually conflated. */
.czn-badge-reliability.czn-badge-tier-a { background: #eaf5ea; color: #276b27; }
.czn-badge-reliability.czn-badge-tier-b { background: #eef3fb; color: #1f4e8c; }
.czn-badge-reliability.czn-badge-tier-c { background: var(--czn-ink-100); color: var(--czn-ink-500); }
.czn-badge-reliability.czn-badge-tier-d { background: #fdf3e0; color: #8a5a00; }
.czn-badge-reliability.czn-badge-unclassified { background: #fdeaea; color: #9c2b2b; }

/* Official-source badge (Tanzania Trade Portal integration, 2026-10-05) —
   a sixth independent axis, same reasoning as redistribution/reliability
   above: distinguishes "published by a government body" from any other
   citation without implying a partnership/endorsement (deliberately not
   reusing czn-badge-verified's color, which signals OUR evidentiary review,
   not the SOURCE's own government status). */
.czn-badge-official { background: #eaf5ea; color: #1f5c33; }
@media (prefers-color-scheme: dark) {
	.czn-badge-official { background: #1c3320; color: #9fd9af; }
}
.czn-source-official .czn-badge-official { margin-right: 0.5em; }
.czn-source-attribution-note { font-size: 0.82rem; color: var(--czn-ink-500); margin-top: 0.75rem; }

/* Geography-scope badges (International Benchmarks brief, section 13) — a
   fifth independent axis from price_type/redistribution/reliability above.
   Deliberately its own color pair so it's never confused with price-type's
   existing teal 'international' badge (that one is about auction/export/
   etc — this one is Tanzania vs. everywhere else). */
.czn-badge-geo.czn-badge-geo-tanzania { background: #eef3e3; color: #4a6b1f; }
.czn-badge-geo.czn-badge-geo-international { background: #eef0fb; color: #38408c; }
@media (prefers-color-scheme: dark) {
	.czn-badge-geo.czn-badge-geo-tanzania { background: #223018; color: #b7d98c; }
	.czn-badge-geo.czn-badge-geo-international { background: #201f3a; color: #a9b1e8; }
}
@media (prefers-color-scheme: dark) {
	.czn-badge-reliability.czn-badge-tier-a { background: #1c3320; color: #a8dba8; }
	.czn-badge-reliability.czn-badge-tier-b { background: #1c2a3d; color: #a9c6ef; }
	.czn-badge-reliability.czn-badge-tier-d { background: #332409; color: #e3b464; }
	.czn-badge-reliability.czn-badge-unclassified { background: #3a1f1f; color: #e3a3a3; }
}

/* Events — two independent axes (Network-Wide Events Intelligence, Phase 1,
   2026-10-05). czn-badge-event-region is deliberately a 4-way split (adds
   'online' to the existing geo badge's tanzania/international) rather than
   reusing czn-badge-geo directly — an event can genuinely have no physical
   location, a news item never can. czn-badge-event-status surfaces the
   computed UPCOMING/ONGOING/PAST/CANCELLED/POSTPONED status (never stored,
   see CZN_Events::event_status()) -- cancelled/postponed get a distinct
   warning color so they're never mistaken for a normal live listing. */
.czn-badge-event-region.czn-badge-event-region-tanzania { background: #eef3e3; color: #4a6b1f; }
.czn-badge-event-region.czn-badge-event-region-east_africa { background: #fdf3e0; color: #8a5a00; }
.czn-badge-event-region.czn-badge-event-region-international { background: #eef0fb; color: #38408c; }
.czn-badge-event-region.czn-badge-event-region-online { background: var(--czn-ink-100); color: var(--czn-ink-500); }
.czn-badge-event-status.czn-badge-event-status-upcoming { background: var(--czn-primary-tint); color: var(--czn-primary-dark); }
.czn-badge-event-status.czn-badge-event-status-ongoing { background: #eaf5ea; color: #276b27; }
.czn-badge-event-status.czn-badge-event-status-past { background: var(--czn-ink-100); color: var(--czn-ink-500); }
.czn-badge-event-status.czn-badge-event-status-cancelled,
.czn-badge-event-status.czn-badge-event-status-postponed { background: #fdeaea; color: #9c2b2b; }
@media (prefers-color-scheme: dark) {
	.czn-badge-event-region.czn-badge-event-region-tanzania { background: #223018; color: #b7d98c; }
	.czn-badge-event-region.czn-badge-event-region-east_africa { background: #332409; color: #e3b464; }
	.czn-badge-event-region.czn-badge-event-region-international { background: #201f3a; color: #a9b1e8; }
	.czn-badge-event-status.czn-badge-event-status-ongoing { background: #1c3320; color: #a8dba8; }
	.czn-badge-event-status.czn-badge-event-status-cancelled,
	.czn-badge-event-status.czn-badge-event-status-postponed { background: #3a1f1f; color: #e3a3a3; }
}

/* Training — reuses czn-badge-event-region for geography (Network-Wide
   Training & Capacity Building, Phase 1, 2026-10-06; see virtual-training.php
   for the region-bucket mapping). czn-badge-training-status covers the
   training-specific status set computed by CZN_Training::training_status()
   — open_for_application/upcoming/ongoing/closed/completed share the same
   semantic weight as Events' upcoming/ongoing/past, cancelled/postponed
   reuse the same warning treatment. */
.czn-badge-training-status.czn-badge-training-status-open_for_application,
.czn-badge-training-status.czn-badge-training-status-upcoming { background: var(--czn-primary-tint); color: var(--czn-primary-dark); }
.czn-badge-training-status.czn-badge-training-status-ongoing { background: #eaf5ea; color: #276b27; }
.czn-badge-training-status.czn-badge-training-status-closed,
.czn-badge-training-status.czn-badge-training-status-completed,
.czn-badge-training-status.czn-badge-training-status-archived { background: var(--czn-ink-100); color: var(--czn-ink-500); }
.czn-badge-training-status.czn-badge-training-status-cancelled,
.czn-badge-training-status.czn-badge-training-status-postponed { background: #fdeaea; color: #9c2b2b; }
@media (prefers-color-scheme: dark) {
	.czn-badge-training-status.czn-badge-training-status-ongoing { background: #1c3320; color: #a8dba8; }
	.czn-badge-training-status.czn-badge-training-status-cancelled,
	.czn-badge-training-status.czn-badge-training-status-postponed { background: #3a1f1f; color: #e3a3a3; }
}

/* Forms -------------------------------------------------------------- */
.czn-field { margin-bottom: var(--czn-space-4); }
.czn-field label { display: block; font-weight: 600; margin-bottom: var(--czn-space-1); font-size: 0.92rem; }
.czn-field .czn-hint { font-size: 0.82rem; color: var(--czn-ink-500); margin-top: 0.25em; }
.czn-field input[type="text"], .czn-field input[type="email"], .czn-field input[type="tel"],
.czn-field input[type="number"], .czn-field input[type="date"], .czn-field select, .czn-field textarea {
	width: 100%;
	padding: 0.65em 0.8em;
	border: 1px solid var(--czn-border);
	border-radius: var(--czn-radius);
	background: var(--czn-paper-raised);
	color: var(--czn-ink-900);
}
.czn-field textarea { min-height: 7em; }
.czn-form-row { display: grid; grid-template-columns: 1fr 1fr; gap: var(--czn-space-4); }
@media (max-width: 620px) { .czn-form-row { grid-template-columns: 1fr; } }
.czn-hp-field { position: absolute; left: -9999px; opacity: 0; }
.czn-sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0; }

/* Weekly Intelligence Digest signup (Phase 8E) ------------------------- */
.czn-digest-form-row { display: flex; gap: var(--czn-space-2); flex-wrap: wrap; }
.czn-digest-form-row input[type="email"] { flex: 1 1 220px; padding: 0.55em 0.8em; border: 1px solid var(--czn-border); border-radius: var(--czn-radius); background: var(--czn-paper); color: var(--czn-ink-900); font-size: 0.92rem; }
.czn-digest-callout { background: var(--czn-paper-raised); border: 1px solid var(--czn-border); border-radius: var(--czn-radius-lg); padding: var(--czn-space-5); margin-top: var(--czn-space-6); }
.czn-digest-callout h3 { margin-bottom: var(--czn-space-2); }
.czn-digest-callout p { color: var(--czn-ink-700); font-size: 0.92rem; }
.czn-form-message { padding: var(--czn-space-3) var(--czn-space-4); border-radius: var(--czn-radius); margin-bottom: var(--czn-space-4); display: none; }
.czn-form-message.is-visible { display: block; }
.czn-form-message.is-success { background: var(--czn-primary-tint); color: var(--czn-primary-dark); }
.czn-form-message.is-error { background: #fbeaea; color: var(--czn-danger); }

/* Phase 7 accessible form validation (brief section 17) */
.czn-error-summary { padding: var(--czn-space-3) var(--czn-space-4); border-radius: var(--czn-radius); margin-bottom: var(--czn-space-4); background: #fbeaea; color: var(--czn-danger); border: 1px solid var(--czn-danger); }
.czn-error-summary p { font-weight: 600; margin: 0 0 0.4em; }
.czn-error-summary ul { margin: 0; padding-left: 1.2em; }
.czn-error-summary a { color: var(--czn-danger); text-decoration: underline; }
.czn-field-error { display: block; font-size: 0.82rem; color: var(--czn-danger); margin-top: 0.25em; }
.czn-field [aria-invalid="true"], .czn-field input[aria-invalid="true"], .czn-field select[aria-invalid="true"], .czn-field textarea[aria-invalid="true"] { border-color: var(--czn-danger); }

/* Tables ------------------------------------------------------------- */
/* overflow-x:auto already makes a too-wide table scrollable; the background-attachment
   fade is purely a discoverability cue (Stage A visual audit: a table cut off
   flush at the container edge gives no hint more columns exist off-screen). */
.czn-table-wrap {
	overflow-x: auto;
	border: 1px solid var(--czn-border);
	border-radius: var(--czn-radius-lg);
	background:
		linear-gradient(to right, var(--czn-paper-raised) 30%, rgba(255,255,255,0)),
		linear-gradient(to right, rgba(255,255,255,0), var(--czn-paper-raised) 70%) right,
		linear-gradient(to right, rgba(22,32,27,0.12), rgba(255,255,255,0) 8px),
		linear-gradient(to left, rgba(22,32,27,0.12), rgba(255,255,255,0) 8px) right;
	background-repeat: no-repeat;
	background-color: var(--czn-paper-raised);
	background-size: 40px 100%, 40px 100%, 8px 100%, 8px 100%;
	background-attachment: local, local, scroll, scroll;
}
.czn-price-table, .czn-data-table { font-size: 0.92rem; }
.czn-price-table th, .czn-price-table td, .czn-data-table th, .czn-data-table td {
	padding: 0.65em 0.9em;
	text-align: left;
	border-bottom: 1px solid var(--czn-border);
	white-space: nowrap;
}
.czn-price-table thead th, .czn-data-table thead th { background: var(--czn-ink-100); font-family: var(--czn-font-mono); font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.05em; }
.czn-price-table tbody tr:last-child td, .czn-data-table tbody tr:last-child td { border-bottom: none; }

/* Per-observation Source column (Market Snapshot source-links brief): a
   compact link to the exact source backing that row's figure, not a
   decorative icon — kept short so a sixth/eighth column doesn't blow out
   the table width on top of the existing horizontal-scroll fallback. */
.czn-text-muted { color: var(--czn-ink-500); }
.czn-source-cell, .czn-price-table td:last-child, .czn-data-table td:last-child { white-space: nowrap; }
.czn-source-link { color: var(--czn-accent); font-weight: 600; text-decoration: none; }
.czn-source-link:hover { text-decoration: underline; }
.czn-source-link-glyph { font-weight: 400; }
.czn-source-link-internal { color: var(--czn-ink-500); font-weight: 500; font-style: italic; }
.czn-source-link-internal:hover { text-decoration: underline; }

@media (max-width: 480px) {
	.czn-price-table th, .czn-price-table td, .czn-data-table th, .czn-data-table td { padding: 0.5em 0.6em; font-size: 0.85rem; }
}

/* Visually hidden but screen-reader-accessible text (WP core convention).
   Not previously defined in this theme; added for the harvest calendar's
   per-month status labels below. */
.screen-reader-text {
	position: absolute !important;
	width: 1px; height: 1px;
	padding: 0; margin: -1px;
	overflow: hidden;
	clip: rect(0, 0, 0, 0);
	white-space: nowrap;
	border: 0;
}

/* Harvest Seasonality calendar (Commodity Knowledge Enrichment, 2026-10-08):
   one reusable 12-month grid, data-driven per commodity via
   CZN_Commodity_Harvest -- never a hardcoded image or one-off per portal. */
.czn-harvest-grid {
	display: grid;
	grid-template-columns: repeat(12, 1fr);
	gap: var(--czn-space-2);
	list-style: none;
	margin: var(--czn-space-3) 0;
	padding: 0;
}
@media (max-width: 900px) { .czn-harvest-grid { grid-template-columns: repeat(6, 1fr); } }
@media (max-width: 480px) { .czn-harvest-grid { grid-template-columns: repeat(4, 1fr); } }
.czn-harvest-month {
	text-align: center;
	padding: var(--czn-space-2) var(--czn-space-1);
	border-radius: var(--czn-radius);
	background: var(--czn-ink-100);
	color: var(--czn-ink-500);
	font-family: var(--czn-font-mono);
	font-size: 0.72rem;
	letter-spacing: 0.03em;
	border: 1px solid transparent;
}
.czn-harvest-month-peak { background: var(--czn-primary); color: #fff; font-weight: 700; }
.czn-harvest-month-secondary { background: var(--czn-primary-tint); color: var(--czn-primary-dark); font-weight: 600; }
.czn-harvest-month-processing { background: var(--czn-ink-100); color: var(--czn-ink-700); border-style: dashed; border-color: var(--czn-ink-300); }
.czn-harvest-month-current { outline: 2px solid var(--czn-focus); outline-offset: 1px; }
.czn-harvest-legend { display: flex; gap: var(--czn-space-4); flex-wrap: wrap; font-size: 0.82rem; color: var(--czn-ink-500); margin-top: var(--czn-space-2); }
.czn-harvest-legend span { display: inline-flex; align-items: center; gap: 0.4em; }
.czn-harvest-legend-swatch { width: 0.85em; height: 0.85em; border-radius: 2px; display: inline-block; }
.czn-harvest-legend-swatch-peak { background: var(--czn-primary); }
.czn-harvest-legend-swatch-secondary { background: var(--czn-primary-tint); }
.czn-harvest-legend-swatch-processing { background: var(--czn-ink-100); border: 1px dashed var(--czn-ink-300); }

/* Mobile-only scroll affordance for horizontally scrollable market-data
   tables (post-enrichment visual QA, 2026-10-05) — supplements the
   .czn-table-wrap edge-fade above, doesn't replace it. Plain static text,
   never a floating/fixed overlay, so it can't obscure table data. */
.czn-scroll-hint {
	display: none;
	margin: 0.4em 0 0;
	text-align: center;
	font-size: 0.72rem;
	color: var(--czn-ink-500);
}
@media (max-width: 640px) {
	.czn-scroll-hint { display: block; }
}

/* Tanzania / International grouped price tables (International Benchmarks
   brief, section 9) — [czn_price_table] output. */
.czn-price-group { margin-bottom: var(--czn-space-6); }
.czn-price-group:last-child { margin-bottom: 0; }
.czn-price-group-heading { margin: 0 0 0.4em; font-size: 1rem; }
.czn-price-group-caveat { margin: 0 0 0.75em; font-size: 0.85rem; color: var(--czn-ink-500); }

/* Empty / error states -------------------------------------------------- */
.czn-empty-state {
	border: 1px dashed var(--czn-border);
	border-radius: var(--czn-radius-lg);
	padding: var(--czn-space-6);
	text-align: center;
	color: var(--czn-ink-500);
	background: var(--czn-paper-raised);
}
.czn-empty-state h3 { margin-bottom: var(--czn-space-2); }

/* Supplier grid (Phase 8B rebuild, brief sections 11-14) --------------- */
/* auto-fill/minmax instead of a rigid 3-up: a column only ever narrows to
   accommodate MORE cards, never below 260px, so a long registered name like
   "Kilimanjaro Native Co-operative Union (1984) Ltd" always gets a column
   wide enough to wrap across 2-3 natural lines instead of one-word-per-line. */
.czn-supplier-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: var(--czn-space-4); align-items: stretch; }

/* Homepage supplier preview cap (Nav/Homepage brief, 2026-10-05) — the
   directory and single-commodity supplier grids above stay on fluid
   auto-fill (a column only narrows to fit MORE cards), but a homepage
   preview needs a hard two-row ceiling regardless of how many suppliers
   a commodity has, so CoffeeBean.tz-style portals don't end a 4-up grid
   with one orphaned card on its own row. auto-fill can't be row-limited
   directly (its column count isn't knowable in CSS), so this modifier
   switches the preview instance to the SAME column counts auto-fill
   already produces at these widths (4/3/2, derived from the 1240px
   --czn-max-width container and the 260px card minimum) and hides
   anything past 2 rows' worth via :nth-child. The PHP side only needs to
   fetch enough suppliers for the richest breakpoint (4 cols x 2 rows = 8,
   see CZN_SUPPLIER_PREVIEW_LIMIT) — narrower breakpoints just hide more
   of what's already rendered. If a portal has fewer suppliers than a
   breakpoint's cap, nth-child simply has nothing past the real count to
   hide, so short supplier lists are never padded or clipped.

   The sub-600px single-column phone tier intentionally keeps the SAME
   4-card cap as the 2-column tablet tier above it rather than halving
   it again to a literal "2 rows = 2 cards" — a portal with 3 or 4
   suppliers (chilli.tz, cardamom.tz, honey.tz...) must keep showing all
   of them everywhere, and a phone is exactly where that single-column
   math would otherwise cut a real supplier that every wider breakpoint
   still shows. 4 single-column rows is still a short, intentional
   preview next to the uncapped alternative (e.g. coffeebean.tz's 20),
   so it still satisfies "sensible, not excessively long" on mobile. */
.czn-supplier-grid--capped { grid-template-columns: repeat(4, 1fr); }
.czn-supplier-grid--capped > .czn-supplier-card:nth-child(n+9) { display: none; }
@media (max-width: 1135px) {
	.czn-supplier-grid--capped { grid-template-columns: repeat(3, 1fr); }
	.czn-supplier-grid--capped > .czn-supplier-card:nth-child(n+7) { display: none; }
}
@media (max-width: 859px) {
	.czn-supplier-grid--capped { grid-template-columns: repeat(2, 1fr); }
	.czn-supplier-grid--capped > .czn-supplier-card:nth-child(n+5) { display: none; }
}
@media (max-width: 599px) {
	.czn-supplier-grid--capped { grid-template-columns: 1fr; }
}
.czn-supplier-card {
	display: flex; flex-direction: column; gap: var(--czn-space-3); height: 100%;
	padding: var(--czn-space-5); border: 1px solid var(--czn-border); border-radius: var(--czn-radius-lg);
	background: var(--czn-paper-raised); color: var(--czn-ink-900);
}
.czn-supplier-card:hover { border-color: var(--czn-accent); text-decoration: none; box-shadow: var(--czn-shadow); }
/* Name is the primary hierarchy element (brief section 13) — full-width,
   generous line-height, never sharing a flex row with the status badge. */
.czn-supplier-name { font-family: var(--czn-font-serif); font-weight: 700; font-size: 1.05rem; line-height: 1.35; margin: 0; color: var(--czn-ink-900); }
.czn-supplier-meta { font-size: 0.82rem; color: var(--czn-ink-500); margin: 0; }
.czn-supplier-desc { font-size: 0.88rem; color: var(--czn-ink-700); margin: 0; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
/* Status badge pinned to a footer row, secondary to the name (brief section
   13) — never interrupts headline reading, and the "View profile" affordance
   lives in the same row so the card doesn't read as a bare status chip. */
.czn-supplier-card-foot { margin-top: auto; padding-top: var(--czn-space-3); border-top: 1px solid var(--czn-border); display: flex; align-items: center; justify-content: space-between; gap: var(--czn-space-2); }
.czn-supplier-cta { font-size: 0.82rem; font-weight: 600; color: var(--czn-accent); white-space: nowrap; }

/* Supplier brand identity (Phase 14 logo brief, sections 4/6/10) — a fixed-
   height strip bled to the card's outer edge via negative margins (the card
   itself keeps one uniform padding value everywhere else) so every card in
   the grid lines up regardless of whether a given supplier has a verified
   logo, a banner, or the neutral fallback. Logos always render with
   object-fit:contain + padding — cropping a brand mark with `cover` is
   exactly what section 4 prohibits — while a banner (a real photo that
   depicts the company, not stock imagery) uses `cover` since it's meant to
   fill the frame like the site's other editorial photography. */
.czn-supplier-logo-frame, .czn-supplier-logo-fallback {
	height: 108px;
	margin: calc(-1 * var(--czn-space-5)) calc(-1 * var(--czn-space-5)) 0;
	border-radius: var(--czn-radius-lg) var(--czn-radius-lg) 0 0;
	border-bottom: 1px solid var(--czn-border);
	display: flex; align-items: center; justify-content: center; overflow: hidden;
	flex-shrink: 0;
}
.czn-supplier-logo-frame { background: var(--czn-paper-raised); }
.czn-supplier-logo-frame.czn-fit-contain { padding: var(--czn-space-4); }
.czn-supplier-logo-frame img { display: block; }
.czn-supplier-logo-frame.czn-fit-contain img { max-width: 100%; max-height: 100%; width: auto; height: auto; object-fit: contain; }
.czn-supplier-logo-frame.czn-fit-cover img { width: 100%; height: 100%; object-fit: cover; }
.czn-supplier-logo-fallback { background: var(--czn-ink-100); }
.czn-supplier-logo-fallback span { font-family: var(--czn-font-serif); font-weight: 700; font-size: 1.6rem; letter-spacing: 0.04em; color: var(--czn-ink-300); }
/* Profile header uses a smaller, inline variant — reinforces identity next
   to the name without dominating the page (brief section 11: "not
   excessively large"). */
.czn-supplier-profile-logo { width: 96px; height: 72px; flex-shrink: 0; border: 1px solid var(--czn-border); border-radius: var(--czn-radius); background: var(--czn-paper-raised); display: flex; align-items: center; justify-content: center; overflow: hidden; }
.czn-supplier-profile-logo.czn-fit-contain { padding: var(--czn-space-2); }
.czn-supplier-profile-logo img { max-width: 100%; max-height: 100%; object-fit: contain; }
.czn-supplier-profile-logo.czn-fit-cover img { width: 100%; height: 100%; object-fit: cover; }
@media (max-width: 600px) {
	.czn-supplier-logo-frame, .czn-supplier-logo-fallback { height: 84px; }
	.czn-supplier-profile-logo { width: 72px; height: 54px; }
}

/* Supplier Pro directory card (Supplier Pro launch) ---------------------
   A noticeably richer card without reordering the grid or resembling a paid
   placement: a top accent bar (color, not motion/gradient), the Pro badge
   sitting alongside verification status (never replacing it), and one more
   line of description visible. Insertion/DOM order is untouched — this is
   styling on top of whatever CZN_Suppliers::query() already returned, so
   ranking (evidence-based only, see that method's docblock) is unaffected. */
.czn-supplier-card--pro { border-top: 3px solid var(--czn-pro-accent); }
.czn-supplier-card--pro .czn-supplier-desc { -webkit-line-clamp: 3; }
.czn-supplier-card-badges { display: flex; align-items: center; gap: 0.4em; flex-wrap: wrap; }

/* Supplier Pro profile banner (section 4B) — the strongest Pro treatment,
   profile page only. Text always sits on solid ground (never overlaid on
   the photo) so contrast/accessibility never depends on a given company's
   photography — the photo strip is purely a decorative top band when one
   exists (see CZN_Suppliers::banner_for()); when it doesn't, the tinted
   HTML/CSS body alone still reads as a premium treatment (section 4B:
   "prefer HTML/CSS over baking important text into an image"). */
.czn-pro-banner { border: 1px solid var(--czn-border); border-radius: var(--czn-radius-lg); overflow: hidden; margin-bottom: var(--czn-space-6); background: var(--czn-paper-raised); }
.czn-pro-banner-media { aspect-ratio: 16 / 5; max-height: 260px; overflow: hidden; background: var(--czn-ink-100); }
.czn-pro-banner-media img { width: 100%; height: 100%; object-fit: cover; display: block; }
.czn-pro-banner-body {
	display: flex; align-items: center; gap: var(--czn-space-5); flex-wrap: wrap;
	padding: var(--czn-space-5) var(--czn-space-6);
	background: linear-gradient(135deg, var(--czn-pro-tint), var(--czn-paper-raised));
	border-top: 3px solid var(--czn-pro-accent);
}
.czn-pro-banner-logo { width: 88px; height: 88px; flex-shrink: 0; border-radius: var(--czn-radius); background: var(--czn-paper-raised); border: 1px solid var(--czn-border); display: flex; align-items: center; justify-content: center; overflow: hidden; padding: var(--czn-space-2); }
.czn-pro-banner-logo img { max-width: 100%; max-height: 100%; object-fit: contain; }
.czn-pro-banner-content { flex: 1 1 280px; min-width: 0; }
.czn-pro-banner-eyebrow { display: flex; align-items: center; gap: 0.6em; flex-wrap: wrap; margin-bottom: 0.35em; }
.czn-pro-banner-content h1, .czn-pro-banner-content h2 { margin: 0 0 0.25em; font-family: var(--czn-font-serif); }
.czn-pro-banner-descriptor { margin: 0; color: var(--czn-ink-700); max-width: 62ch; }
.czn-pro-banner-cta { flex-shrink: 0; }
@media (max-width: 640px) {
	.czn-pro-banner-body { flex-direction: column; align-items: flex-start; text-align: left; }
	.czn-pro-banner-cta { width: 100%; }
	.czn-pro-banner-cta .czn-btn { width: 100%; text-align: center; }
}

/* Supplier Pro showcase/promotion banner (section 4D) — advertises Supplier
   Pro itself, reused on the directory and on relevant commodity portals.
   Same accent language as the card/profile treatments above so all three
   read as one system, but visually simpler (no photo, no per-brand data). */
.czn-pro-promo {
	display: flex; align-items: center; justify-content: space-between; gap: var(--czn-space-5); flex-wrap: wrap;
	padding: var(--czn-space-5) var(--czn-space-6);
	border: 1px solid var(--czn-border); border-radius: var(--czn-radius-lg);
	background: linear-gradient(135deg, var(--czn-pro-tint), var(--czn-paper-raised));
	border-left: 3px solid var(--czn-pro-accent);
	margin: var(--czn-space-6) 0;
}
.czn-pro-promo-content { max-width: 60ch; }
.czn-pro-promo-content h3 { margin: 0 0 0.3em; font-family: var(--czn-font-serif); }
.czn-pro-promo-content p { margin: 0; color: var(--czn-ink-700); }
.czn-pro-promo-cta { flex-shrink: 0; }
@media (max-width: 600px) {
	.czn-pro-promo { flex-direction: column; align-items: flex-start; }
	.czn-pro-promo-cta { width: 100%; }
	.czn-pro-promo-cta .czn-btn { width: 100%; text-align: center; }
}

/* Supplier Pro comparison table (Free vs Pro, section 8) — reuses the
   network's existing data-table styling rather than inventing a new one. */
.czn-pro-compare th, .czn-pro-compare td { text-align: center; }
.czn-pro-compare th:first-child, .czn-pro-compare td:first-child { text-align: left; }
.czn-pro-compare .czn-pro-compare-yes { color: var(--czn-primary); font-weight: 700; }
.czn-pro-compare .czn-pro-compare-no { color: var(--czn-ink-300); }
.czn-pro-compare thead th:nth-child(3) { color: var(--czn-pro-accent-dark); }

/* Sponsored Supplier Advertising creatives — TWO-COLUMN network-wide
   redesign (2026-09-29), superseding the original single oversized banner
   (.czn-ad-feature/.czn-ad-inline, launch 2026-09-28). ONE unit shape now:
   .czn-ad-unit is a two-column grid of .czn-ad-card cells, real or house,
   equal height, ~250-350px tall on desktop — a deliberate density cut from
   the old hero treatment's ~400-500px single banner. Same design tokens as
   before (--czn-pro-accent, --czn-pro-tint, --czn-border, --czn-radius-lg,
   --czn-space-*) so it stays visually consistent with the still-live
   Supplier Pro profile/promo components without sharing their selectors. */
.czn-ad-label { display: inline-block; padding: 0.15em 0.6em; font-size: 0.72rem; font-weight: 700; letter-spacing: 0.05em; text-transform: uppercase; border-radius: var(--czn-radius); background: var(--czn-ad-label-bg); color: var(--czn-ad-label-color); }
.czn-ad-label--house { background: var(--czn-pro-tint); color: var(--czn-pro-accent-dark, var(--czn-pro-accent)); }

.czn-ad-unit { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--czn-space-5); margin: var(--czn-space-6) 0; align-items: stretch; }

.czn-ad-card { display: flex; flex-direction: column; border: 1px solid var(--czn-border); border-radius: var(--czn-radius-lg); overflow: hidden; background: var(--czn-paper-raised); border-top: 3px solid var(--czn-pro-accent); }
.czn-ad-card-media { position: relative; height: 110px; flex-shrink: 0; overflow: hidden; background: linear-gradient(135deg, var(--czn-pro-tint), var(--czn-paper-raised)); display: flex; align-items: center; justify-content: center; }
.czn-ad-card-media img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* Real photographic banner creatives (Supplier Pro multi-banner rotation,
   DB version 33) are designed at a 2.7:1 aspect ratio -- scale the media box
   to that ratio instead of the compact fixed 110px height used for the
   logo/initials fallback, so a full-width mobile card (one column under
   600px) doesn't crop the photo far more aggressively than desktop's narrower
   two-column card does. aspect-ratio reserves the box before the image loads
   (no layout shift); object-fit:cover above already guarantees no distortion. */
.czn-ad-card-media--banner { height: auto; aspect-ratio: 2.7 / 1; }
.czn-ad-card-media-logo { width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; padding: var(--czn-space-3); }
.czn-ad-card-media-logo img { max-width: 70%; max-height: 70%; width: auto; height: auto; object-fit: contain; }
.czn-ad-card-media-initials { font-family: var(--czn-font-serif); font-weight: 700; font-size: 1.6rem; color: var(--czn-pro-accent-dark, var(--czn-pro-accent)); }
.czn-ad-card-body { display: flex; flex-direction: column; flex: 1 1 auto; padding: var(--czn-space-4) var(--czn-space-5); gap: 0.3em; }
.czn-ad-card-eyebrow { display: flex; align-items: center; gap: 0.5em; flex-wrap: wrap; }
.czn-ad-card-body h3 { margin: 0.1em 0 0; font-family: var(--czn-font-serif); font-size: 1.05rem; line-height: 1.3; }
.czn-ad-card-body p { margin: 0; color: var(--czn-ink-700); font-size: 0.88rem; line-height: 1.4; }
.czn-ad-card-cta { margin-top: auto; padding-top: var(--czn-space-3); }
.czn-ad-card-cta .czn-btn { width: 100%; text-align: center; }

/* House-ad ("unsold inventory") variant — branded CSS graphic, never a
   blank photography area or a broken-looking placeholder (brief section 9):
   a diamond glyph on a tinted diagonal field, same visual family as the
   Supplier Pro badge glyph elsewhere in this theme. */
.czn-ad-card--house { border-top-color: var(--czn-pro-accent); border-style: dashed; }
.czn-ad-card-media--house { background: repeating-linear-gradient(135deg, var(--czn-pro-tint), var(--czn-pro-tint) 10px, var(--czn-paper-raised) 10px, var(--czn-paper-raised) 20px); }
.czn-ad-card-house-glyph { font-size: 1.8rem; color: var(--czn-pro-accent-dark, var(--czn-pro-accent)); opacity: 0.55; }

.czn-ad-unit-heading { margin-bottom: var(--czn-space-4); }
.czn-ad-unit-heading h2 { margin: 0.15em 0 0; }

.czn-ad-directory-section { margin: var(--czn-space-7) 0; }

@media (max-width: 600px) {
	.czn-ad-unit { grid-template-columns: 1fr; }
}

/* Organizations directory ---------------------------------------------- */
/* Reuses the supplier grid/card/logo-frame system wholesale — an organization
   card has the same anatomy (identity frame, name, meta, description, footer)
   and duplicating 40 lines of grid CSS under a second name would guarantee the
   two drift apart. Only the commodity tag chips are genuinely new: they carry
   no status, tier or score meaning, so they are deliberately the flattest
   possible neutral pill and must never be styled to read as a badge (see
   .czn-badge, which does encode an evidentiary tier). */
.czn-org-tags { display: flex; flex-wrap: wrap; gap: 0.35rem; margin: 0; }
.czn-org-tag {
	display: inline-block;
	font-size: 0.72rem;
	line-height: 1.6;
	padding: 0 0.5em;
	border: 1px solid var(--czn-border);
	border-radius: var(--czn-radius);
	background: var(--czn-paper);
	color: var(--czn-ink-500);
	white-space: nowrap;
}
/* Export.tz Service Directory category nav (DB version 19) reuses this same
   neutral pill as a clickable filter link — an :active/:focus-visible/hover
   state and a --active "currently selected" modifier are additive here since
   the base .czn-org-tag rule above still covers the plain non-interactive
   chip usage (organization/service-provider card tags) unchanged. */
a.czn-org-tag:hover, a.czn-org-tag:focus-visible { border-color: var(--czn-accent); color: var(--czn-accent); text-decoration: none; }
.czn-org-tag--active { background: var(--czn-accent); border-color: var(--czn-accent); color: #fff; }
a.czn-org-tag--active:hover, a.czn-org-tag--active:focus-visible { color: #fff; }
/* Initials fallback in the profile header, for a published organization with
   no sourced logo (ZIPA, AfDB) — same frame as the grid fallback so the header
   never collapses or looks like a broken image. Sized to hold a real
   abbreviation ("AfDB", "ZIPA") rather than only two letters, since that is
   what CZN_Organizations::display_initials() prefers; the shared wrap rule
   below keeps a long one inside the grid frame too. */
.czn-org-initials {
	font-family: var(--czn-font-serif);
	font-weight: 700;
	font-size: 1.15rem;
	letter-spacing: 0.02em;
	color: var(--czn-ink-300);
	background: var(--czn-ink-100);
	padding: var(--czn-space-2);
	text-align: center;
	overflow-wrap: anywhere;
}
.czn-supplier-logo-fallback span { overflow-wrap: anywhere; }

/* Breadcrumbs ---------------------------------------------------------- */
.czn-breadcrumbs { font-size: 0.85rem; color: var(--czn-ink-500); margin-bottom: var(--czn-space-4); }
.czn-breadcrumbs a { color: var(--czn-ink-500); }
.czn-breadcrumbs a:hover { color: var(--czn-accent); }

/* Hero ------------------------------------------------------------------- */
.czn-hero { padding: var(--czn-space-8) 0 var(--czn-space-7); }
.czn-hero h1 { max-width: 18ch; }
.czn-hero-actions { display: flex; gap: var(--czn-space-3); margin-top: var(--czn-space-5); flex-wrap: wrap; }
/* Compact stat cards (Network Counter Cards redesign, 2026-09-30) — one
   shared component (.czn-hero-stat) behind every "N price series / N
   listed suppliers / latest observation" chip network-wide (home-portal.php,
   home-chocolate.php, home-central.php). Deliberately restrained: a light
   card, a hairline border, no shadow, no oversized icon — the brief was
   explicit this should read as a refined information strip, not a
   dashboard tile, so keep the desktop card height in the ~80-100px band
   and resist the urge to grow it.
   justify-content:center centers the CARD GROUP (not just its text) inside
   the wide .czn-container — this is the actual centering fix (2026-09-30
   counter-centering pass). .czn-hero-stat previously used flex:1 1 180px
   with no cap, so a lone card (e.g. Cardamom's single "listed suppliers"
   stat) grew to fill the entire ~1240px container instead of staying a
   compact chip; max-width caps that growth so 1/2/3-up rows land in the
   ~260-340px band called for by the brief while still wrapping into a
   centered grid at 4+. */
.czn-hero-stats { display: flex; gap: var(--czn-space-3); margin-top: var(--czn-space-6); flex-wrap: wrap; justify-content: center; }
.czn-hero-stat {
	display: flex;
	align-items: center;
	gap: var(--czn-space-3);
	flex: 1 1 260px;
	max-width: 340px;
	min-width: 0;
	background: var(--czn-paper-raised);
	border: 1px solid var(--czn-border);
	border-radius: 12px;
	padding: var(--czn-space-3) var(--czn-space-4);
}
.czn-hero-stat-icon {
	flex: 0 0 auto;
	display: flex;
	align-items: center;
	justify-content: center;
	width: 38px;
	height: 38px;
	border-radius: 9px;
	background: var(--czn-primary-tint);
	color: var(--czn-primary);
}
.czn-hero-stat-icon svg { width: 21px; height: 21px; }
.czn-hero-stat-body { min-width: 0; }
.czn-hero-stat-body strong { display: block; font-family: var(--czn-font-serif); font-size: 1.7rem; line-height: 1.15; color: var(--czn-primary); }
.czn-hero-stat-body span { display: block; font-size: 0.78rem; line-height: 1.3; color: var(--czn-ink-500); }
/* Tablet: three-across starts to feel tight before a full mobile stack is
   needed, so let the row wrap into a 2-up + 1 arrangement first. */
@media (max-width: 760px) {
	.czn-hero-stat { flex-basis: calc(50% - var(--czn-space-3) / 2); }
}
/* Phones: stack one-per-row rather than truncating labels or shrinking the
   card below a comfortably tappable size. */
@media (max-width: 460px) {
	.czn-hero-stats { gap: var(--czn-space-2); }
	.czn-hero-stat { flex-basis: 100%; }
}
.czn-hero-split { display: grid; grid-template-columns: 1.1fr 0.9fr; gap: var(--czn-space-7); align-items: center; }
.czn-hero-figure { margin: 0; }
.czn-hero-figure img { max-height: 420px; }
.czn-container figure img { max-height: 440px; width: 100%; object-fit: cover; }
@media (max-width: 900px) { .czn-hero-split { grid-template-columns: 1fr; } .czn-hero-figure { order: -1; } }

/* Editorial full-bleed hero (Phase 8B visual correction, brief section 5) —
   image is the dominant element; headline/lede/actions sit on a scrim at the
   base of the photo, with a stats strip directly beneath on solid ground so
   the numbers stay legible over dark or light source photography alike. */
.czn-hero-editorial { padding: 0; }
.czn-hero-editorial-media { position: relative; min-height: clamp(440px, 58vw, 660px); max-height: 680px; overflow: hidden; background: var(--czn-ink-900); }
.czn-hero-editorial-media > img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: center 38%; }
.czn-hero-editorial-scrim { position: absolute; inset: 0; background: linear-gradient(190deg, rgba(10,17,13,0.05) 0%, rgba(10,17,13,0.18) 38%, rgba(8,14,11,0.88) 100%); }
.czn-hero-editorial-content { position: absolute; left: 0; right: 0; bottom: 0; z-index: 1; padding-bottom: var(--czn-space-6); color: #fff; }
.czn-hero-editorial-content .czn-eyebrow { color: #bfe6cc; }
.czn-hero-editorial-content h1 { color: #fff; max-width: 16ch; }
.czn-hero-editorial-content .czn-lede { color: rgba(255,255,255,0.88); max-width: 52ch; font-size: 1.15rem; }
.czn-hero-editorial-content .czn-btn-secondary { color: #fff; border-color: rgba(255,255,255,0.55); }
.czn-hero-editorial-content .czn-btn-secondary:hover { border-color: #fff; color: #fff; background: rgba(255,255,255,0.14); }
/* max-width forces long credit lines (real photographer name + license +
   the geography_confidence:'low' "illustrative, not Tanzania-specific"
   disclaimer can run 90-100+ chars) to wrap instead of growing left across
   the box — unconstrained width let a long credit's left edge reach under
   the CTA buttons on ~768-1024px viewports, since both are independently
   bottom-anchored with no shared layout. border-radius drops from a pill
   to a rounded box once wrapping is possible; a 999px pill on 2 lines of
   text looks like a mistake, not a design choice. */
.czn-hero-editorial-credit { position: absolute; right: var(--czn-space-5); bottom: var(--czn-space-3); z-index: 1; font-size: 0.72rem; color: rgba(255,255,255,0.75); background: rgba(8,14,11,0.45); padding: 0.35em 0.7em; border-radius: var(--czn-radius-lg); max-width: min(320px, 44vw); text-align: right; }
.czn-hero-editorial-credit a { color: rgba(255,255,255,0.9); }
.czn-hero-featured-link { display: inline-flex; align-items: center; gap: 0.5em; margin-top: var(--czn-space-5); padding: 0.5em 0.9em 0.5em 0; font-size: 0.88rem; color: #fff; border-bottom: 1px solid rgba(255,255,255,0.35); }
.czn-hero-featured-link:hover { border-color: #fff; text-decoration: none; }
.czn-hero-featured-link .czn-eyebrow { margin: 0; color: #bfe6cc; }
/* Background is the warm page tone (not white/paper-raised) specifically
   so the white .czn-hero-stat cards still read as lifted cards here, same
   as they do sitting on the plain hero's page background below. */
.czn-hero-stats-strip { background: var(--czn-paper); border-bottom: 1px solid var(--czn-border); }
.czn-hero-stats-strip .czn-hero-stats { margin: 0; padding-top: var(--czn-space-5); padding-bottom: var(--czn-space-5); justify-content: center; gap: var(--czn-space-3); }
/* Mobile: the overlay technique above assumes content is short enough to
   fit inside a fixed-height photo; a long headline + lede + featured-story
   chip is not, and overflow:hidden on the media box was clipping the top of
   the H1. Fall back to a stacked layout instead — photo on top at a fixed
   aspect ratio, content below on solid ground — so height is never guessed. */
@media (max-width: 620px) {
	.czn-hero-editorial-media { position: static; min-height: 0; max-height: none; overflow: visible; }
	.czn-hero-editorial-media > img { position: static; width: 100%; height: auto; aspect-ratio: 4/3; object-fit: cover; display: block; }
	.czn-hero-editorial-scrim { display: none; }
	.czn-hero-editorial-content { position: static; background: var(--czn-ink-900); padding: var(--czn-space-6) 0 var(--czn-space-7); }
	.czn-hero-editorial-content .czn-lede { font-size: 0.95rem; max-width: none; }
	.czn-hero-editorial-credit { position: static; display: block; text-align: right; background: none; color: var(--czn-ink-500); padding: var(--czn-space-2) var(--czn-space-5) 0; }
	.czn-hero-stats-strip .czn-hero-stats { gap: var(--czn-space-2); }
}

/* Profile feature (homepage Profile section background photo, brief
   2026-09-30) — reuses the same media+scrim+content overlay technique as
   .czn-hero-editorial above rather than inventing a new one (shared
   architecture). Two deliberate differences from that hero treatment:
   (1) shorter — clamp(360px, 42vw, 520px) vs the hero's 440-660px, since
   this is a mid-page content section, not a second hero; (2) the scrim is
   a diagonal gradient anchored bottom-left (where the constrained-width
   text column sits) rather than a full-width vertical one, so more of the
   photograph stays visible across the right two-thirds of the section per
   brief section 6 ("gradient strongest behind the text and lighter toward
   the photographic focal point"). */
/* position:relative here (not just on -media) because -content and -credit
   are its direct siblings, not children of -media — without this they'd
   anchor to whatever positioned ancestor happens to be further up the DOM
   instead of this section. */
.czn-profile-feature { position: relative; padding: 0; }
.czn-profile-feature-media { position: relative; min-height: clamp(360px, 42vw, 520px); overflow: hidden; background: var(--czn-ink-900); }
.czn-profile-feature-media > img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: center; }
.czn-profile-feature-scrim { position: absolute; inset: 0; background: linear-gradient(115deg, rgba(8,14,11,0.90) 0%, rgba(8,14,11,0.74) 30%, rgba(8,14,11,0.32) 55%, rgba(8,14,11,0.06) 78%); }
.czn-profile-feature-content { position: absolute; left: 0; right: 0; bottom: 0; z-index: 1; padding-bottom: var(--czn-space-6); color: #fff; }
/* ch-based max-width (brief section 9): the excerpt must not run the width
   of the photograph — constraining the text column both improves
   readability and keeps more of the image visible beside it. */
.czn-profile-feature-text { max-width: 46ch; }
.czn-profile-feature-content .czn-eyebrow { color: #bfe6cc; }
.czn-profile-feature-content h2 { color: #fff; }
.czn-profile-feature-content p { color: rgba(255,255,255,0.88); }
.czn-profile-feature-content .czn-btn-secondary { color: #fff; border-color: rgba(255,255,255,0.55); }
.czn-profile-feature-content .czn-btn-secondary:hover { border-color: #fff; color: #fff; background: rgba(255,255,255,0.14); }
.czn-profile-feature-credit { position: absolute; right: var(--czn-space-5); bottom: var(--czn-space-3); z-index: 1; font-size: 0.72rem; color: rgba(255,255,255,0.75); background: rgba(8,14,11,0.45); padding: 0.35em 0.7em; border-radius: var(--czn-radius-lg); max-width: min(320px, 44vw); text-align: right; }
.czn-profile-feature-credit a { color: rgba(255,255,255,0.9); }
/* Tablet (brief section 17): the diagonal gradient above assumes enough
   container width for the transparent end to clear the text column; below
   900px that margin shrinks, so switch to a full-width vertical scrim
   instead of tuning the diagonal's stops per breakpoint. */
@media (max-width: 900px) {
	.czn-profile-feature-scrim { background: linear-gradient(180deg, rgba(8,14,11,0.20) 0%, rgba(8,14,11,0.90) 100%); }
}
/* Mobile (brief section 16): same reasoning as .czn-hero-editorial's own
   mobile fallback above — a fixed-height overlay risks clipped text at
   narrow widths, so the photo becomes a static block at a fixed aspect
   ratio with content stacked below it on solid ground instead. */
@media (max-width: 620px) {
	.czn-profile-feature-media { position: static; min-height: 0; overflow: visible; }
	.czn-profile-feature-media > img { position: static; width: 100%; height: auto; aspect-ratio: 4/3; object-fit: cover; display: block; }
	.czn-profile-feature-scrim { display: none; }
	.czn-profile-feature-content { position: static; background: var(--czn-ink-900); padding: var(--czn-space-6) 0 var(--czn-space-7); }
	.czn-profile-feature-text { max-width: none; }
	.czn-profile-feature-credit { position: static; display: block; text-align: right; background: none; color: var(--czn-ink-500); padding: var(--czn-space-2) var(--czn-space-5) 0; }
}

/* Footer ----------------------------------------------------------------- */
.czn-footer { background: var(--czn-ink-900); color: var(--czn-ink-100); padding: var(--czn-space-6) 0 var(--czn-space-4); margin-top: var(--czn-space-7); }
.czn-footer a { color: #fff; opacity: 0.85; }
.czn-footer a:hover { opacity: 1; }
.czn-footer a[aria-current="page"] { opacity: 1; font-weight: 600; text-decoration: underline; text-underline-offset: 0.2em; }
.czn-footer h4 { color: #fff; font-family: var(--czn-font-sans); font-size: 0.82rem; text-transform: uppercase; letter-spacing: 0.06em; margin: 0 0 var(--czn-space-3); overflow-wrap: anywhere; }
.czn-footer ul { list-style: none; padding: 0; margin: 0; display: grid; gap: var(--czn-space-2); font-size: 0.88rem; line-height: 1.3; }
/* Portal hostnames (Commodities.tz, BlackPepper.tz, ...) are single
   unbreakable words — without this, a column narrower than the longest
   hostname lets the text spill visually into the next column instead of
   wrapping, since grid track sizing doesn't shrink a track's content for it
   (see the 680-1023px tier below, where columns get tight). */
.czn-footer-col-network a, .czn-footer-network-list-commodities a { overflow-wrap: anywhere; }

/* Footer redesign (2026-10-01, revised again): one horizontal band —
   identity + 3 narrow link columns + a narrow Network column + a wide
   Commodity Portals grid — via named grid areas so the breakpoint rules
   below can reshuffle/stack without touching the markup. Commodity Portals
   gets roughly a third of the row since it carries 15+ links where the
   others carry 3-5; Network (Commodities.tz/Markets.tz/Export.tz) is sized
   like Explore/Trust since it's also a short list. */
.czn-footer-grid {
	display: grid;
	grid-template-columns: minmax(200px, 2.1fr) minmax(85px, 1.1fr) minmax(95px, 1.2fr) minmax(85px, 1.1fr) minmax(85px, 1.0fr) minmax(300px, 3.1fr);
	grid-template-areas: "brand explore trade trust network commodities";
	gap: var(--czn-space-5);
	align-items: start;
}
.czn-footer-brand { grid-area: brand; }
.czn-footer-col-explore { grid-area: explore; }
.czn-footer-col-trade { grid-area: trade; }
.czn-footer-col-trust { grid-area: trust; }
.czn-footer-col-network { grid-area: network; }
.czn-footer-col-commodities { grid-area: commodities; }

.czn-footer-network-list-commodities { grid-template-columns: repeat(3, 1fr); column-gap: var(--czn-space-4); row-gap: var(--czn-space-2); }

/* 1024-1279: still one horizontal band, just tighter — the commodity grid
   drops to 2 columns so its rows don't get too cramped at this width. */
@media (max-width: 1279px) {
	.czn-footer-grid { gap: var(--czn-space-4); }
	.czn-footer-network-list-commodities { grid-template-columns: repeat(2, 1fr); }
}

/* 680-1023: one horizontal band stays the priority down through tablet
   widths — columns shrink instead of reflowing to a second row, so
   Explore/Trade/Trust/Network/Commodity Portals never drop below the brand
   block. Minimums are each column's actual measured longest unbroken token
   plus a small buffer (Trust: "Corrections" ~91px; Network: "Commodities.tz"
   ~110px; headings are all shorter than their column's longest link, except
   Commodity Portals' which can wrap at its word space) — too tight here lets
   content spill into the next column instead of wrapping (see
   .czn-footer-col-network a above). Verified via real measurement, NOT the
   rendered <h4> box width, which stretches to fill its track and so can't be
   used to size the track itself. */
@media (max-width: 1023px) {
	.czn-footer-grid {
		grid-template-columns: minmax(140px, 1.6fr) minmax(78px, 0.85fr) minmax(62px, 0.75fr) minmax(98px, 0.9fr) minmax(116px, 0.95fr) minmax(170px, 2.0fr);
		gap: var(--czn-space-3);
	}
}
/* Below 900px there isn't room left for a 2-col commodity grid without its
   own content clipping (each sub-column needs ~103-111px for the longest
   portal name) — drops to a single column instead of reflowing the whole
   band, same trade-off logic as the breakpoints above. Once it's 1-col, the
   Commodity Portals track itself only needs to fit one hostname (~111px),
   not two side by side, so its minmax (and the others') shrinks again here
   to keep the single row fitting down to 680px. */
@media (max-width: 899px) {
	.czn-footer-grid {
		grid-template-columns: minmax(120px, 1.5fr) minmax(82px, 0.8fr) minmax(60px, 0.7fr) minmax(98px, 0.9fr) minmax(116px, 0.95fr) minmax(113px, 1.6fr);
		gap: var(--czn-space-2);
	}
	.czn-footer-network-list-commodities { grid-template-columns: 1fr; }
}
/* Mobile (<680): a single row can no longer fit six columns without
   cramping link text past readability, so it stacks — reading order
   brand > explore > trade > trust > network > commodities preserved, no
   forced baseline alignment. */
@media (max-width: 679px) {
	.czn-footer-grid {
		grid-template-columns: 1fr;
		grid-template-areas: "brand" "explore" "trade" "trust" "network" "commodities";
		gap: var(--czn-space-5);
	}
	.czn-footer-network-list-commodities { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 599px) {
	.czn-footer-network-list-commodities { grid-template-columns: 1fr; }
}

.czn-footer-bottom { border-top: 1px solid rgba(255,255,255,0.15); margin-top: var(--czn-space-5); padding-top: var(--czn-space-4); display: flex; justify-content: space-between; flex-wrap: wrap; gap: var(--czn-space-3); font-size: 0.82rem; opacity: 0.75; }
.czn-commodity-nav-links {
	display: flex;
	gap: var(--czn-space-2);
	font-size: 0.82rem;
	overflow-x: auto;
	-webkit-overflow-scrolling: touch;
	scroll-snap-type: x proximity;
	scrollbar-width: none;
	min-width: 0; /* without this, the flex item's default min-width:auto blocks it shrinking below content width, which silently defeats overflow-x:auto */
}
.czn-commodity-nav-links::-webkit-scrollbar { display: none; }
.czn-commodity-nav-links a { scroll-snap-align: start; }

/* Media credit (Phase 8 Reboot media provenance, brief section 13) ------- */
.czn-media-credit { font-size: 0.78rem; color: var(--czn-ink-500); margin-top: var(--czn-space-2); }
.czn-media-credit a { color: var(--czn-ink-500); text-decoration: underline; }

/* Commodity card thumbnails (Phase 8 Reboot, brief section 60). A modifier,
   not a rewrite of .czn-commodity-card itself — that base class is shared by
   text-only listings (archive-czn_commodity.php, virtual-markets.php,
   home-markets.php) that must keep their plain padded layout. */
.czn-commodity-card--photo { display: flex; flex-direction: column; padding: 0; overflow: hidden; }
/* 1:1 square frame (Phase 8B, brief sections 9/10/30) — every tile in the
   commodity explorer grid gets identical geometry regardless of the source
   photo's native crop, so the grid reads as one deliberate system rather
   than mismatched card heights. */
.czn-commodity-card-thumb { aspect-ratio: 1/1; overflow: hidden; background: var(--czn-ink-100); }
.czn-commodity-card-thumb img { width: 100%; height: 100%; object-fit: cover; transition: transform 0.25s ease; }
.czn-card-link:hover .czn-commodity-card-thumb img { transform: scale(1.04); }
.czn-commodity-card-body { padding: var(--czn-space-4) var(--czn-space-5) var(--czn-space-5); }
.czn-commodity-card-body p { display: -webkit-box; -webkit-line-clamp: 1; -webkit-box-orient: vertical; overflow: hidden; }
/* A dedicated 16:9 frame for non-grid photo cards (e.g. the Tanzania Origins
   card) that intentionally keep a wider crop instead of the 1:1 grid rule. */
.czn-commodity-card-thumb--wide { aspect-ratio: 16/9; }

/* Editorial insights module (Phase 8B rebuild, brief sections 7/8/32) ---
   Adaptive to how many stories actually exist: 1 = single feature, 2 = even
   split, 3+ = one dominant lead plus a secondary grid. Every card carries a
   real image — no bordered text-only tiles. */
.czn-insights-feature { display: block; position: relative; border-radius: var(--czn-radius-lg); overflow: hidden; color: #fff; aspect-ratio: 16/9; }
.czn-insights-feature img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; transition: transform 0.3s ease; }
.czn-insights-feature:hover img { transform: scale(1.03); }
.czn-insights-feature-scrim { position: absolute; inset: 0; background: linear-gradient(0deg, rgba(8,14,11,0.88) 0%, rgba(8,14,11,0.25) 55%, rgba(8,14,11,0) 100%); }
.czn-insights-feature-body { position: absolute; left: 0; right: 0; bottom: 0; padding: var(--czn-space-6) var(--czn-space-6) var(--czn-space-5); z-index: 1; }
.czn-insights-feature-body .czn-eyebrow { color: #bfe6cc; }
.czn-insights-feature-body h3 { color: #fff; font-size: clamp(1.4rem, 1.1rem + 1vw, 2rem); max-width: 26ch; margin-bottom: var(--czn-space-2); }
.czn-insights-feature-body p { color: rgba(255,255,255,0.85); max-width: 60ch; margin: 0; }
.czn-insights-feature:hover { text-decoration: none; }

.czn-insights-split { display: grid; grid-template-columns: 1fr 1fr; gap: var(--czn-space-5); }
@media (max-width: 720px) { .czn-insights-split { grid-template-columns: 1fr; } }

.czn-insights-layout { display: grid; grid-template-columns: 1.3fr 1fr; gap: var(--czn-space-6); align-items: start; }
@media (max-width: 900px) { .czn-insights-layout { grid-template-columns: 1fr; } }
.czn-insights-secondary { display: grid; gap: var(--czn-space-4); }
.czn-insights-secondary-item { display: grid; grid-template-columns: 96px 1fr; gap: var(--czn-space-3); align-items: start; color: inherit; }
.czn-insights-secondary-item:hover { text-decoration: none; }
.czn-insights-secondary-item:hover h4 { text-decoration: underline; }
.czn-insights-secondary-thumb { aspect-ratio: 1/1; border-radius: var(--czn-radius); overflow: hidden; background: var(--czn-ink-100); }
.czn-insights-secondary-thumb img { width: 100%; height: 100%; object-fit: cover; }
.czn-insights-secondary-item h4 { font-family: var(--czn-font-serif); font-size: 0.98rem; line-height: 1.3; margin: 0 0 0.3em; color: var(--czn-ink-900); }
.czn-insights-secondary-item .czn-eyebrow { font-size: 0.66rem; margin: 0; }

/* Source citation ------------------------------------------------------- */
.czn-source-note { font-size: 0.82rem; color: var(--czn-ink-500); border-left: 3px solid var(--czn-border); padding-left: var(--czn-space-3); margin: var(--czn-space-5) 0; }
.czn-source-note a { color: var(--czn-ink-500); text-decoration: underline; }

/* Utility --------------------------------------------------------------- */
.czn-mt-0 { margin-top: 0; }
.czn-text-center { text-align: center; }
.czn-visually-hidden { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; }

/* Export.tz Phase 1 (DB version 20) ------------------------------------- */

/* Wide container: Export.tz's trade-intelligence content (guide sections,
   document tables, the Requirements Finder's multi-field form) reads
   cramped at the network's normal 1240px --czn-max-width — this is a
   second, wider container class layered alongside it, not a replacement,
   so every other portal's layout is completely unaffected.
   1440 -> 1560 (Export Guides Wide-Layout Redesign): guide pages still read
   as a narrow column with a large unused right-hand margin at 1920+ even at
   1440 — 1560 keeps a deliberate gutter at every desktop width tested
   (1920/1440) without ever running page content edge-to-edge. */
.czn-container--wide {
	max-width: 1560px;
	margin: 0 auto;
	padding: 0 var(--czn-space-5);
}

/* Step timeline: the numbered export-process journey (general /how-to-export/
   stages and each guide's own Step-by-Step Export Process section). A plain
   vertical list with a connecting rail rather than a horizontal stepper —
   stays legible at any step count and collapses naturally on mobile without
   a separate breakpoint layout. */
.czn-step-timeline { list-style: none; margin: var(--czn-space-6) 0; padding: 0; counter-reset: czn-step; }
.czn-step-timeline-item { position: relative; display: grid; grid-template-columns: 2.75rem 1fr; gap: var(--czn-space-4); padding-bottom: var(--czn-space-6); }
.czn-step-timeline-item:last-child { padding-bottom: 0; }
.czn-step-timeline-item::before {
	counter-increment: czn-step;
	content: counter(czn-step);
	grid-row: 1;
	grid-column: 1;
	width: 2.75rem;
	height: 2.75rem;
	border-radius: 50%;
	background: var(--czn-primary);
	color: #fff;
	display: flex;
	align-items: center;
	justify-content: center;
	font-family: var(--czn-font-serif);
	font-weight: 600;
	font-size: 1.05rem;
	z-index: 1;
}
.czn-step-timeline-item:not(:last-child)::after {
	content: '';
	position: absolute;
	left: 1.375rem;
	top: 2.75rem;
	bottom: calc(var(--czn-space-6) * -1 + var(--czn-space-6));
	width: 2px;
	background: var(--czn-border);
}
.czn-step-timeline-body h3 { margin: 0 0 var(--czn-space-2); font-size: 1.1rem; }
.czn-step-timeline-body p { margin: 0 0 var(--czn-space-2); color: var(--czn-ink-700); max-width: 68ch; }
.czn-step-timeline-authority { display: inline-flex; align-items: center; gap: 0.4em; font-size: 0.82rem; color: var(--czn-ink-500); margin-top: 0.3em; }
.czn-step-timeline-authority a { color: var(--czn-primary); }

/* Document checklist: a commodity guide's Document Checklist section.
   Requirement-level chips reuse the existing czn-badge color language
   (verified/source_confirmed/listed) so "Required" vs "Required in some
   cases" vs "Recommended" reads with the same visual weight convention a
   visitor already learned from verification badges elsewhere on the
   network, rather than inventing a fourth color system. */
/* auto-fill + minmax(360px,1fr): 1-2 columns depending on the section's
   available width (1 in a narrower container/viewport, 2 on the guide's
   wide canvas) rather than the single-column list this was before — the
   same self-collapsing pattern as .czn-agency-grid below, applied to a
   component that previously never used the width it was given. */
.czn-checklist { list-style: none; margin: var(--czn-space-5) 0; padding: 0; display: grid; grid-template-columns: repeat(auto-fill, minmax(360px, 1fr)); gap: var(--czn-space-3); }
.czn-checklist-item {
	display: flex;
	align-items: flex-start;
	gap: var(--czn-space-3);
	padding: var(--czn-space-4);
	background: var(--czn-paper-raised);
	border: 1px solid var(--czn-border);
	border-radius: var(--czn-radius-lg);
}
.czn-checklist-item-icon { flex: 0 0 auto; width: 1.5rem; height: 1.5rem; color: var(--czn-primary); margin-top: 0.1em; }
.czn-checklist-item-body { flex: 1 1 auto; }
.czn-checklist-item-body h4 { margin: 0 0 0.2em; font-size: 1rem; }
.czn-checklist-item-body h4 a { color: inherit; }
.czn-checklist-item-body p { margin: 0.2em 0 0; font-size: 0.9rem; color: var(--czn-ink-700); }
.czn-checklist-level { flex: 0 0 auto; font-size: 0.75rem; font-weight: 600; padding: 0.25em 0.7em; border-radius: 999px; white-space: nowrap; }
.czn-checklist-level--required { background: var(--czn-primary-tint); color: var(--czn-primary); }
.czn-checklist-level--conditional { background: #fdf3e0; color: #8a5a00; }
.czn-checklist-level--recommended { background: var(--czn-ink-100); color: var(--czn-ink-500); }

/* Agency cards: the "Authorities Involved" grid on a guide page and the
   Authorities & Agencies directory hub. Deliberately reuses czn-card's
   base look (same border/radius/shadow-on-hover as every other card on the
   network) rather than a bespoke visual language, per the brief's "use the
   network design system" instruction — this only adds the logo-plus-role
   layout on top. */
/* Agency cards ("Authorities Involved" grid on a guide, and the Authorities
   & Agencies directory hub). Redesigned from a single whole-card link to a
   structured card with two distinct, clearly-labelled actions — the
   internal directory profile and (when a verified official URL exists) the
   authority's own external website — rather than one ambiguous click
   target. minmax(320px,1fr) (widened from 280px alongside the Export
   Guides Wide-Layout Redesign's 1560px canvas, which would otherwise pack
   5 cramped columns into a row) keeps rows to a professional 3-4 cards;
   align-items:stretch (grid default) plus flex column + margin-top:auto on
   the footer keeps every card's action row aligned along the same baseline
   regardless of how much role-note text it has. */
.czn-agency-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); gap: var(--czn-space-5); margin: var(--czn-space-5) 0; }
.czn-agency-card { display: flex; flex-direction: column; gap: var(--czn-space-3); }
.czn-agency-card-logo, .czn-agency-card-logo-fallback {
	width: 100%; height: 72px;
	display: flex; align-items: center; justify-content: flex-start;
	padding: var(--czn-space-2) var(--czn-space-3);
	background: var(--czn-paper);
	border: 1px solid var(--czn-border);
	border-radius: var(--czn-radius);
	box-sizing: border-box;
}
.czn-agency-card-logo img { max-height: 100%; max-width: 100%; object-fit: contain; }
.czn-agency-card-logo-fallback {
	justify-content: center;
	font-family: var(--czn-font-serif); font-weight: 700; font-size: 1.1rem;
	letter-spacing: 0.02em; color: var(--czn-ink-500);
}
.czn-agency-card-name { flex: 1 1 auto; }
.czn-agency-card-name h3 { margin: 0 0 0.15em; font-size: 1.05rem; }
.czn-agency-card-name h3 a { color: inherit; }
.czn-agency-card-fullname { margin: 0; font-size: 0.78rem; color: var(--czn-ink-500); }
.czn-agency-card-role { margin: 0; font-size: 0.9rem; color: var(--czn-ink-700); }
.czn-agency-card-actions { margin-top: auto; padding-top: var(--czn-space-2); display: flex; flex-direction: column; gap: 0.4em; }
.czn-agency-card-actions a { font-size: 0.85rem; }
.czn-agency-card-actions .czn-btn { align-self: flex-start; }

/* Commercial next-steps close — the guide's one strong commercial CTA point
   (brief section 26): a quiet raised panel so it reads as the deliberate
   end of the reference document rather than another plain section. */
.czn-guide-cta { background: var(--czn-primary-tint); border-radius: var(--czn-radius-lg); padding: var(--czn-space-5); border-top: none; }
.czn-guide-cta h2 { margin-bottom: var(--czn-space-2); }
.czn-guide-cta .czn-guide-prose { margin-bottom: var(--czn-space-4); color: var(--czn-ink-700); }

.czn-guide-return-link { margin-top: var(--czn-space-6); padding-top: var(--czn-space-4); border-top: 1px solid var(--czn-border); font-size: 0.9rem; }

/* Jurisdiction switcher: Mainland / Zanzibar / Both toggle on a commodity
   guide page. */
.czn-jurisdiction-switch { display: inline-flex; border: 1px solid var(--czn-border); border-radius: 999px; overflow: hidden; margin: var(--czn-space-3) 0 var(--czn-space-5); }
.czn-jurisdiction-switch a { padding: 0.45em 1.1em; font-size: 0.85rem; color: var(--czn-ink-700); }
.czn-jurisdiction-switch a:hover { text-decoration: none; background: var(--czn-paper-raised); }
.czn-jurisdiction-switch a.is-active { background: var(--czn-accent); color: #fff; }
.czn-guide-meta-line { font-size: 0.85rem; margin: var(--czn-space-2) 0 0; }
.czn-jurisdiction-switch + .czn-guide-meta-line { margin-top: -0.5rem; }

/* Guide hero title (Export Guides Wide-Layout Redesign): the network's
   general `.czn-hero h1 { max-width: 18ch; }` (further up this file) is
   tuned for short punchy marketing headlines and wraps a factual guide
   title like "Exporting Spices from Tanzania (Cinnamon, Ginger & Others)"
   into an ugly narrow stack that makes the whole hero read as cramped even
   though the container underneath it is already wide. Same specificity as
   that rule, so source order (this comes later in the cascade) is what
   makes it win — scoped to `.czn-guide-hero` only, every other `.czn-hero`
   consumer network-wide is untouched. */
.czn-guide-hero h1 { max-width: 44ch; }

/* Requirements Finder form */
.czn-finder-form {
	display: grid;
	grid-template-columns: repeat(4, 1fr);
	gap: var(--czn-space-4);
	padding: var(--czn-space-5);
	background: var(--czn-paper-raised);
	border: 1px solid var(--czn-border);
	border-radius: var(--czn-radius-lg);
	margin: var(--czn-space-5) 0;
	align-items: end;
}
@media (max-width: 900px) { .czn-finder-form { grid-template-columns: 1fr 1fr; } }
@media (max-width: 560px) { .czn-finder-form { grid-template-columns: 1fr; } }
.czn-finder-form .czn-field { margin: 0; }
.czn-finder-form-submit { grid-column: 1 / -1; }

.czn-finder-result-section { margin: var(--czn-space-5) 0; padding-top: var(--czn-space-5); border-top: 1px solid var(--czn-border); }
.czn-finder-result-section:first-of-type { border-top: none; padding-top: 0; }
.czn-finder-result-section h2 { margin-bottom: var(--czn-space-3); }

/* Editorial reading column for a guide's prose fields (overview, quality
   standards, phytosanitary requirements, etc.) — tables, the step timeline,
   the document checklist and the authority grid are deliberately NOT
   wrapped in this, since those read better using the section's full
   available width. */
.czn-guide-prose { max-width: 68ch; }
.czn-guide-prose > :last-child { margin-bottom: 0; }

/* Guide table-of-contents (rendered only when a guide has enough sections
   to warrant one). Export Guides Wide-Layout Redesign: was a small 760px
   box centered inside the wide canvas — at 1560px that reads as a floating
   island with dead space either side, so it's now a full-width strip that
   wraps its link list across as many rows as the section list needs,
   styled like the rest of the network's small-caps wayfinding (nav,
   step-timeline-authority) rather than a plain link list. */
.czn-guide-toc { display: flex; flex-wrap: wrap; gap: var(--czn-space-3) var(--czn-space-6); margin: var(--czn-space-4) 0 var(--czn-space-5); padding: var(--czn-space-4) var(--czn-space-5); background: var(--czn-paper-raised); border: 1px solid var(--czn-border); border-radius: var(--czn-radius-lg); font-size: 0.8rem; }
.czn-guide-toc a { color: var(--czn-ink-700); font-family: var(--czn-font-mono); font-size: 0.78rem; letter-spacing: 0.03em; text-transform: uppercase; font-weight: 600; }
.czn-guide-toc a:hover { color: var(--czn-primary); }

/* Notice cards (Export.tz Visual & Authority Redesign): compact, centered,
   read-before-you-rely disclaimers and evidence caveats. Previously
   full-container-width yellow blocks that visually dominated the guide —
   these are now a deliberately small, centered card that stays legible and
   present without competing with the actual guide content for attention.
   `.czn-disclaimer-box` is kept as the base class (three existing templates
   already use it); `--caution` is an additive modifier for evidence-gap /
   scope-caveat notices, which are a documentation gap, not an error, and so
   deliberately don't get red/danger treatment. */
.czn-notice-stack { padding-top: var(--czn-space-2); }
.czn-disclaimer-box {
	max-width: 760px;
	margin: var(--czn-space-4) auto;
	padding: var(--czn-space-3) var(--czn-space-4);
	background: var(--czn-paper-raised);
	border: 1px solid var(--czn-border);
	border-radius: var(--czn-radius-lg);
	font-size: 0.85rem;
	line-height: 1.5;
	color: var(--czn-ink-700);
}
.czn-disclaimer-box strong { color: var(--czn-ink-900); }
.czn-disclaimer-box + .czn-disclaimer-box { margin-top: var(--czn-space-3); }
.czn-disclaimer-box-label {
	display: flex;
	align-items: center;
	gap: 0.4em;
	font-family: var(--czn-font-sans);
	font-size: 0.72rem;
	font-weight: 700;
	letter-spacing: 0.04em;
	text-transform: uppercase;
	color: var(--czn-ink-500);
	margin-bottom: 0.35em;
}
.czn-disclaimer-box-label-icon { font-size: 0.95em; line-height: 1; }
.czn-disclaimer-box p { margin: 0; }
.czn-disclaimer-box p + p { margin-top: 0.5em; }
.czn-disclaimer-box a { text-decoration: underline; }

.czn-disclaimer-box--caution {
	background: #fdf6e8;
	border-color: #e8d29a;
	color: #6b4d00;
}
.czn-disclaimer-box--caution strong { color: #5a3f00; }
.czn-disclaimer-box--caution .czn-disclaimer-box-label { color: #8a5a00; }

/* Guide notice panel (export guide only): the disclaimer + any evidence-gap
   caveats merged into ONE compact box instead of one `.czn-disclaimer-box`
   card per message — same information, far less vertical chrome. Rows are
   told apart by a leading icon/label and a single divider ahead of the
   caution rows, not by repeating box borders. */
.czn-guide-notice-panel {
	max-width: 760px;
	margin: var(--czn-space-3) auto;
	padding: var(--czn-space-3) var(--czn-space-4);
	background: var(--czn-paper-raised);
	border: 1px solid var(--czn-border);
	border-radius: var(--czn-radius-lg);
	font-size: 0.85rem;
	line-height: 1.45;
	color: var(--czn-ink-700);
}
.czn-guide-notice-panel-label {
	display: flex;
	align-items: center;
	gap: 0.4em;
	font-family: var(--czn-font-sans);
	font-size: 0.72rem;
	font-weight: 700;
	letter-spacing: 0.04em;
	text-transform: uppercase;
	color: var(--czn-ink-500);
	margin: 0 0 0.35em;
}
.czn-guide-notice-item { margin: 0; }
.czn-guide-notice-item strong { color: var(--czn-ink-900); }
.czn-guide-notice-item + .czn-guide-notice-item { margin-top: 0.4em; }
.czn-guide-notice-item a { text-decoration: underline; }
.czn-guide-notice-item--caution { color: #6b4d00; }
.czn-guide-notice-item--caution strong { color: #5a3f00; }
.czn-guide-notice-divider { border: none; border-top: 1px solid var(--czn-border); margin: 0.5em 0; }

/* Subtle external-link arrow, reused by authority cards / step timeline /
   official-sources / commercial CTAs — the network's existing convention
   (see virtual-organization-single.php) rather than a new icon system. */
.czn-ext { font-size: 0.9em; opacity: 0.7; margin-left: 0.15em; }

/* ------------------------------------------------------------------ */
/* Markets.tz Phase 2 (DB v21) — marketplace-specific components.      */
/* ------------------------------------------------------------------ */

/* Trade-scope badge (domestic/export/both) — same visual language as the
   existing .czn-badge-* variants, new colors so it reads distinctly from
   verification/reliability/redistribution badges on the same card. */
.czn-badge-scope-domestic { background: var(--czn-primary-tint); color: var(--czn-primary-dark); }
.czn-badge-scope-export { background: #eef0fb; color: #38408c; }
.czn-badge-scope-both { background: var(--czn-ink-100); color: var(--czn-ink-700); }
@media (prefers-color-scheme: dark) {
	.czn-badge-scope-export { background: #201f3a; color: #a9b1e8; }
}

/* Company-membership role badge (owner/admin/staff). */
.czn-role-badge {
	display: inline-block;
	padding: 0.2em 0.7em;
	border-radius: 999px;
	font-size: 0.75rem;
	font-weight: 700;
	letter-spacing: 0.03em;
	text-transform: uppercase;
}
.czn-role-badge-owner { background: var(--czn-pro-tint); color: var(--czn-pro-accent-dark); }
.czn-role-badge-admin { background: #eef3fb; color: var(--czn-focus); }
.czn-role-badge-staff { background: var(--czn-ink-100); color: var(--czn-ink-500); }

/* Marketplace listing card — built on top of .czn-card/.czn-card-link, no
   parallel card component. */
.czn-marketplace-listing-card { display: block; }
.czn-marketplace-listing-card h3 { font-family: var(--czn-font-serif); }

/* Tanzania Commodities Marketplace network-wide promotion band (Markets.tz
   nav + marketplace visibility fix, 2026-09-30). The section itself
   (czn_render_commodity_marketplace_section()/_central_/_export_ in
   inc/marketplace-helpers.php) already existed and was already wired into
   every commodity portal + commodities.tz + export.tz + chocolate.tz
   homepage — the owner's "I can't see it" report traced to this: it
   rendered as a plain .czn-section, visually identical to every other
   content block on the page, with only a small eyebrow label to distinguish
   it. This gives it its own fixed identity (Markets.tz's own brand navy,
   #1B3A5C — not the visiting portal's --czn-accent) so it reads as the same
   recognizable cross-network service everywhere it appears, rather than
   blending into whichever portal happens to host it. */
.czn-marketplace-promo {
	background: linear-gradient(135deg, #142a44, #1b3a5c);
	border-radius: var(--czn-radius-lg);
	padding: var(--czn-space-7) var(--czn-space-5);
	color: #fff;
}
/* Scoped with the > combinator on purpose, not a blanket ".czn-marketplace-promo
   .czn-eyebrow"/"h3": the reused .czn-marketplace-listing-card component
   (a .czn-card floating inside this band, deliberately kept light so it
   reads as a distinct tile) carries its own nested .czn-eyebrow commodity
   badge and h3 title several levels deep. A blanket descendant selector
   forced those white too -- invisible white-on-white text inside the white
   card, caught the same way as the .czn-checklist-item bug above (real
   rendered screenshots of Clove/Cashews/Cardamom.tz, the 3 commodities with
   a live demo listing card on their homepage; every commodity without one
   looked fine). These child-combinator selectors only ever reach this
   section's own top-level heading and its two column sub-headings
   ("Available Offers"/"Buyer Requirements"), never anything inside a card. */
.czn-marketplace-promo > .czn-container > .czn-eyebrow,
.czn-marketplace-promo.czn-container > .czn-eyebrow {
	display: inline-block;
	background: rgba(255, 255, 255, 0.16);
	color: #fff;
	padding: 0.3em 0.9em;
	border-radius: 999px;
	font-weight: 700;
}
.czn-marketplace-promo > .czn-container > h2,
.czn-marketplace-promo.czn-container > h2 { color: #fff; }
.czn-marketplace-promo .czn-lede { color: rgba(255, 255, 255, 0.85); }
.czn-marketplace-promo .czn-source-note { color: rgba(255, 255, 255, 0.7); }
.czn-marketplace-promo .czn-grid > div > h3 { color: #fff; }
.czn-marketplace-promo .czn-empty-state { background: rgba(255, 255, 255, 0.08); border: 1px solid rgba(255, 255, 255, 0.25); }
.czn-marketplace-promo .czn-empty-state h3, .czn-marketplace-promo .czn-empty-state p { color: #fff; }
/* .czn-checklist-item's base rule sets a light paper background (for its
   normal on-page-content use elsewhere) -- without this override here it
   silently produced invisible white-on-white text for any commodity with a
   real open RFQ shown in this band (caught via an actual rendered
   screenshot of Cotton.tz, which had one; every commodity screenshotted
   with zero open RFQs only exercised the .czn-empty-state branch above and
   looked fine, which is exactly the trap "HTML exists" verification
   without real rendering would have missed). */
.czn-marketplace-promo .czn-checklist-item { background: rgba(255, 255, 255, 0.08); border-color: rgba(255, 255, 255, 0.25); }
.czn-marketplace-promo .czn-checklist-item-body h4, .czn-marketplace-promo .czn-checklist-item-body h4 a { color: #fff; }
.czn-marketplace-promo .czn-checklist-item-body p { color: rgba(255, 255, 255, 0.75); }
.czn-marketplace-promo .czn-btn-secondary { background: transparent; border-color: rgba(255, 255, 255, 0.55); color: #fff; }
.czn-marketplace-promo .czn-btn-secondary:hover { border-color: #fff; color: #fff; }
@media (max-width: 480px) {
	.czn-marketplace-promo { padding: var(--czn-space-6) var(--czn-space-4); }
}

/* Company-workspace sub-navigation tabs. */
.czn-tab-nav {
	display: flex;
	gap: var(--czn-space-2);
	flex-wrap: wrap;
	border-bottom: 1px solid var(--czn-border);
	margin: var(--czn-space-5) 0;
}
.czn-tab-nav-link {
	padding: 0.6em 1em;
	font-size: 0.9rem;
	font-weight: 600;
	color: var(--czn-ink-500);
	border-bottom: 2px solid transparent;
	margin-bottom: -1px;
}
.czn-tab-nav-link:hover { color: var(--czn-ink-900); text-decoration: none; }
.czn-tab-nav-link.is-active { color: var(--czn-accent); border-bottom-color: var(--czn-accent); }

/* Message thread (buyer/seller conversation). */
.czn-message-thread {
	display: flex;
	flex-direction: column;
	gap: var(--czn-space-3);
	max-height: 60vh;
	overflow-y: auto;
	padding: var(--czn-space-4);
	background: var(--czn-paper-raised);
	border: 1px solid var(--czn-border);
	border-radius: var(--czn-radius-lg);
	margin-bottom: var(--czn-space-4);
}
.czn-message-bubble {
	max-width: 72%;
	padding: 0.6em 0.9em;
	border-radius: var(--czn-radius-lg);
	background: var(--czn-ink-100);
	align-self: flex-start;
}
.czn-message-bubble--mine {
	background: var(--czn-primary-tint);
	align-self: flex-end;
}
.czn-message-bubble .czn-message-meta {
	display: block;
	font-size: 0.72rem;
	color: var(--czn-ink-500);
	margin-bottom: 0.2em;
}
.czn-message-bubble p { margin: 0; white-space: pre-wrap; word-break: break-word; }

/* Conversation list row (unread state). */
.czn-conversation-row { border: 1px solid var(--czn-border); border-radius: var(--czn-radius-lg); padding: var(--czn-space-3) var(--czn-space-4); display: flex; align-items: center; justify-content: space-between; gap: var(--czn-space-3); }
.czn-conversation-row.is-unread { border-color: var(--czn-accent); background: var(--czn-primary-tint); }

/* Notification row (unread state). */
.czn-notification-row { border: 1px solid var(--czn-border); border-radius: var(--czn-radius-lg); padding: var(--czn-space-3) var(--czn-space-4); display: flex; align-items: center; justify-content: space-between; gap: var(--czn-space-3); }
.czn-notification-row.is-unread { border-left: 3px solid var(--czn-accent); background: var(--czn-primary-tint); }

/* MARKUP II coop-resources module (commodities-cooperation plugin) no longer
   self-centers at its own fixed max-width (2026-10-06 width-alignment fix) --
   every call site now supplies the width via a .czn-container ancestor
   (home-portal.php, home-export.php), the same as every other wide section
   network-wide, so no override is needed here. */
