/**
 * The Africa Missions Initiative — front-end presentation layer.
 *
 * WHAT THIS FILE IS
 * -------------------------------------------------------------------------
 * The visual design system for every public plugin page: region archives,
 * ministry singles and story singles. It layers on top of tami.css (the
 * token/base sheet) and is loaded AFTER the inline "style inheritance" block
 * that Core\Settings emits on the `tami` handle.
 *
 * Because it loads last, it must NEVER assign to any of the inherited tokens
 * listed in CONTRACTS-V2 §5 (--tami-color-*, --tami-font-*,
 * --tami-size-*, --tami-space-*, --tami-page-*, --tami-pad-*,
 * --tami-margin-*): doing so would silently overwrite the administrator's
 * settings and the per-region accent override. It only ever READS them, at
 * the point of use, with a sensible fallback — so the sheet also looks
 * finished when nothing at all has been configured.
 *
 * Any NEW token this sheet needs is given a new name (--tami-accent-ink,
 * --tami-flow, --tami-elev-*, …) so there is no collision. Those are
 * declared with var() references, which resolve per element at computed-value
 * time — that is why the per-region `.tami[data-region="12"]` accent
 * override still flows through into every derived colour below.
 *
 * RULES THIS FILE MUST NEVER BREAK
 * -------------------------------------------------------------------------
 * 1. Every selector is scoped under .tami. The documented exceptions are
 *    three rules that can only be written against <body>, and every one of
 *    them is gated on a body class this plugin sets itself, so off our own
 *    pages and outside our own overlays not one declaration applies:
 *      - §17   the theme-title suppression (CONTRACTS-V2 §8.1), scoped to
 *              body.tami-page — our own pages only;
 *      - §20.4 the theme-sidebar suppression, behind the same gate;
 *      - §30   `body.tami-lightbox-open, body.tami-modal-open
 *              { overflow: hidden }` (after the §30.5 lightbox rules), gated
 *              on the classes tami.js and tami-form.js add for exactly
 *              as long as their overlay is open and remove with it.
 *    Nothing else may leave .tami; a fourth exception needs a comment like
 *    the ones those three carry, saying why it cannot live inside the root.
 *
 * 2. LOGICAL PROPERTIES ONLY. margin-inline-start / padding-inline /
 *    border-inline-end / inset-inline / inset-block. Never the physical
 *    left/right equivalents. Six locales are live and fa_IR is RIGHT-TO-LEFT;
 *    logical properties mean /fa/ mirrors with no separate RTL stylesheet, and
 *    a physical property here is a bug that only ever shows up in Farsi.
 *    Where a property has no logical form (transform-origin, gradient angle)
 *    the direction is driven by :dir(rtl) or by the --tami-flow token.
 *
 *    THE HALF THIS RULE DOES NOT COVER. Writing only logical properties
 *    protects what we DECLARE. It says nothing about what we INHERIT, and
 *    text-align inherits: Divi declares `text-align: left` on `.container`,
 *    every plugin page renders inside one, and for a long time that physical
 *    value reached every element in this sheet — 175 of them across the region,
 *    country, ministry and submission pages, all still hard left in Farsi.
 *    The fix is one `text-align: start` on `.tami` in the BASE sheet, which
 *    severs the chain at the plugin boundary; read the comment there before
 *    touching it. Component-level alignment patches are not a substitute and
 *    are not welcome: if a component looks mis-aligned in Farsi, check the
 *    root rule is still there before adding anything.
 *
 * 3. No @keyframes. Motion is limited to transitions on transform / opacity /
 *    colour / shadow — properties that never trigger layout — so hover states
 *    cannot shift the page, and prefers-reduced-motion can neutralise them
 *    wholesale.
 *
 * 4. No !important except where countering the host theme is unavoidable, and
 *    then only with a comment naming the selector being countered.
 *
 * 5. ONE BREAKPOINT SCALE, MOBILE FIRST. Section 0 defines it; every media
 *    query in this file is taken from it. No component may invent a
 *    breakpoint inline. If a component genuinely needs a step the scale does
 *    not have, the scale is wrong — change it in §0 and re-check every
 *    consumer, so the whole page keeps reflowing as one piece of design
 *    rather than as a dozen components each guessing at a phone width.
 *
 * CONTRAST (WCAG 2.1 AA) with the default tokens
 * -------------------------------------------------------------------------
 *   text    #2b2b2b on #ffffff      13.5:1   body copy
 *   muted   #5f6b6d on #ffffff       4.9:1   meta lines, labels
 *   ink     #50792a on #ffffff       5.1:1   links, secondary buttons, focus rings
 *   #1a1a1a on #7cbb42               7.5:1   label text on a filled button
 *   #ffffff on the hero scrim       12.0:1+  scrim floor is rgba(9,14,11,.72)
 * Decorative-only colour (rules, underlines, tints) may use the raw accent;
 * anything that carries meaning uses the darkened "ink" derivation below.
 *
 * The two accent-derived rows are COMPUTED, not fixed: StyleInheritance
 * darkens whatever accent is in effect until it clears 4.5:1 on white (ink)
 * and picks near-black or white for text sitting ON it (contrast), then emits
 * both on `.tami` for every render. The numbers above are those
 * computations for the default #7cbb42; a different accent moves them but
 * cannot move them below AA. A raw accent must therefore NEVER be used for a
 * focus ring or for text — that is the whole reason ink exists.
 */

/* =========================================================================
 * 0. THE RESPONSIVE SYSTEM — READ THIS BEFORE ADDING ANY MEDIA QUERY
 * =========================================================================
 *
 * The client requirement is that these pages are "highly responsive" on PC,
 * laptop, Android and Apple devices at every screen size. That is not a set of
 * breakpoints, it is a set of promises: nothing overflows sideways, nothing is
 * too small to read or to tap, nothing jumps, and the layout answers to the
 * DEVICE (touch? notch? short landscape? printer?) as well as to the width.
 *
 * 0.1 THE SCALE
 * -------------------------------------------------------------------------
 * Eight tiers. Every width query in this file uses one of them and nothing
 * else. Written in rem, never px, because a rem media query is evaluated
 * against the USER'S root font size: somebody browsing at 20px reaches the
 * roomier layout one step earlier, which is precisely what they asked for by
 * enlarging their type. A px query silently ignores that preference.
 *
 *   name     min-width   ≈px   the device class it exists for
 *   -------  ---------  -----  -------------------------------------------
 *   (base)       —        320  Small phone, portrait — iPhone SE, compact
 *                             Android. NO QUERY: this is what the sheet
 *                             says by default, and it must be complete.
 *   sm         30rem      480  Large phone portrait (iPhone 14/15/16 Pro Max
 *                             is 430pt) and small phones in landscape.
 *   md         40rem      640  Phablet landscape, 7" tablet portrait. The
 *                             first width at which two cards side by side
 *                             are still worth looking at.
 *   lg         48rem      768  Tablet portrait — every iPad in portrait.
 *                             The proportional container starts here (§2).
 *   xl         64rem     1024  Tablet landscape (iPad Pro) and 11–13"
 *                             laptops. Three-across grids start here.
 *   xxl        80rem     1280  Laptop and small desktop.
 *   wide      100rem     1600  Desktop. Equals the default page_max_width,
 *                             so the container stops growing around here.
 *   ultra     120rem     1920  Ultra-wide and 4K.
 *
 * 0.2 THE RULES
 * -------------------------------------------------------------------------
 * 1. MOBILE FIRST. Every layout query is `min-width`. The unqualified rule is
 *    the phone rule. There is not one `max-width` layout query left in this
 *    file. The only max-* queries are the SHAPE queries in §21 (short
 *    landscape), which describe a viewport proportion rather than a step on
 *    the scale, and therefore cannot be expressed mobile-first.
 *
 * 2. 320px IS THE FLOOR. Nothing may overflow the inline axis at 320px. A
 *    page that scrolls sideways on a phone is the single most common mobile
 *    defect there is, and it is always caused by the same four things: a
 *    fixed width, an unwrapped table, an unbreakable string, or a replaced
 *    element with no max. §0.4 and §0.5 install blanket guards for all four,
 *    and every fixed size elsewhere in this file is wrapped in min() or
 *    clamp() so it can always collapse.
 *
 * 3. TYPE IS FLUID, NOT STEPPED. Sizes interpolate with clamp() between the
 *    tiers so nothing snaps at a breakpoint. Body copy never resolves below
 *    1rem on a phone: below 16px iOS Safari zooms the viewport when a field
 *    takes focus, and the visitor is dumped on a horizontally scrolled page
 *    they did not ask for. Where a size comes from an administrator token the
 *    floor is applied with max(), so the setting is honoured upward and only
 *    ever corrected downward on small screens (§3).
 *
 * 4. CAPABILITY, NOT SIZE, DECIDES INTERACTION. Hover affordances are turned
 *    off by `(hover: none)`, never by a width: a 1280px touch laptop is still
 *    a touch device, and a hover state that sticks after a tap is a bug that
 *    no width query can find (§21).
 *
 * 5. THE ADMINISTRATOR STILL OWNS THE VALUES. Responsiveness is expressed in
 *    the RELATIONSHIPS between things, not by overwriting the §5 settings
 *    tokens. The two new names introduced below are ours alone.
 *
 * 0.3 WHY THESE TIERS AND NOT THE OLD ONES
 * -------------------------------------------------------------------------
 * v0.3.0 mixed `max-width: 860px`, `max-width: 40rem`, `min-width: 640px` and
 * `min-width: 1024px` — two directions, two units, and a 860px step that
 * matched no device and no other rule in the file. Small phones, landscape
 * phones and very large screens had no coverage at all. Everything below is
 * that same design intent re-expressed on one scale; the visual result at
 * 640px and 1024px is deliberately unchanged, because those two steps were
 * already right.
 * ========================================================================= */

/* -------------------------------------------------------------------------
 * 0.4 THE 320px FLOOR — global overflow guards.
 *
 * Deliberately the first rules in the sheet so that every component rule
 * below can override them by source order without a specificity fight.
 * ------------------------------------------------------------------------- */

/* A long URL, a German compound, or a 40-character ministry name in a 288px
   column will punch a hole through the layout unless the root says otherwise.
   overflow-wrap inherits, so one declaration covers every descendant. */
.tami {
	overflow-wrap: break-word;
}

/* Replaced elements never exceed their column. This is the max only — the
   intrinsic ratio is handled just below — because several components (the
   64px featured thumbnail, the 100%-height card media) set their own size and
   must keep winning. */
.tami img,
.tami svg,
.tami video,
.tami canvas,
.tami iframe,
.tami embed,
.tami object {
	max-inline-size: 100%;
}

/*
 * CUMULATIVE LAYOUT SHIFT.
 *
 * WordPress prints width and height attributes on every image it renders.
 * Given those, `block-size: auto` alongside a constrained inline size makes
 * the browser reserve the correct box from the attributes before a single
 * byte of the image has arrived — the card does not reflow as photographs
 * load, which is what CLS actually measures.
 *
 * Wrapped in :where() so its specificity is zero-weighted: components that
 * deliberately set a block-size (card media, featured thumb, leader portrait)
 * keep theirs no matter where they sit in the file. The comma-free form is
 * intentional — one selector per line, each carrying .tami, so the scoping
 * test can read it.
 */
.tami :where(img),
.tami :where(video) {
	block-size: auto;
}

/* -------------------------------------------------------------------------
 * 0.5 WIDE CONTENT SCROLLS INSIDE ITSELF, NEVER SIDEWAYS
 *
 * The review queue renders a six-column table; an editor can paste a table or
 * a code block into any story. None of them may be allowed to widen the page.
 *
 * overflow-x rather than the logical overflow-inline: overflow-inline is still
 * unimplemented in Chromium, and the intent here is genuinely the physical
 * horizontal axis — a sideways scroll is sideways in Farsi too. Browsers start
 * an RTL scroll container at its inline start on their own, so this needs no
 * direction handling.
 * ------------------------------------------------------------------------- */

.tami__table-wrap {
	max-inline-size: 100%;
	/* Keeps a flung table scroll from chaining into the page scroll on iOS. */
	overscroll-behavior-x: contain;
	overflow-x: auto;
	/* Momentum scrolling on older iOS WebKit; a no-op everywhere else. */
	-webkit-overflow-scrolling: touch;
}

.tami__table {
	border-collapse: collapse;
	inline-size: 100%;
	/* Below this the six columns stop being legible, so the wrapper scrolls
	   instead of the columns crushing. Expressed in rem so it scales with the
	   user's type size. */
	min-inline-size: 38rem;
}

/* Alignment is NOT set here. §27.2 already declares `text-align: start` for
   `.tami th` / `.tami td` at higher specificity, so a copy at this
   selector never won anything — and a cell is one of the few places where the
   theme reaches past `.tami` and sets `left` directly, which is why that
   rule has to exist at all. One owner for the answer. */
.tami__table th,
.tami__table td {
	border-block-end: 1px solid var(--tami-line, #e3e6e8);
	padding-block: 0.6rem;
	padding-inline: 0.7rem;
	vertical-align: top;
}

.tami__table thead th {
	color: var(--tami-muted-ink, #5f6b6d);
	font-size: 0.75rem;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	white-space: nowrap;
}

/* The actions cell holds a note field and up to four buttons. It keeps
   table-cell display on purpose — a `display: flex` on a <td> drops the cell
   out of the table formatting context and the columns stop aligning — so the
   wrapping is done by the children instead. */
.tami__cell--actions {
	min-inline-size: 13rem;
}

.tami__cell--actions .tami__input {
	inline-size: 100%;
	margin-block-end: var(--tami-step-1, 0.375rem);
}

.tami__cell--actions .tami__button {
	margin-block-start: var(--tami-step-1, 0.375rem);
	margin-inline-end: var(--tami-step-1, 0.375rem);
}

/* Editor-authored tables and code blocks inside a story body. `display: block`
   on the table is what makes overflow-x possible at all — a table box ignores
   overflow — and browsers keep laying the rows out as a table inside it. */
.tami__prose table,
.tami__prose pre {
	display: block;
	max-inline-size: 100%;
	overflow-x: auto;
	-webkit-overflow-scrolling: touch;
}

/* -------------------------------------------------------------------------
 * 1. MODULE TOKENS
 *
 * All new names. Read the §5 tokens, never write them.
 * ------------------------------------------------------------------------- */

.tami {
	/* Direction token for the two properties that have no logical form:
	   gradient angles. 90deg runs toward the inline-end in LTR; the :dir(rtl)
	   override below turns it around so accent segments stay at the reading
	   start of a rule in Farsi. */
	--tami-flow: 90deg;

	/* Decorative accent — the region's colour, straight, for rules and tints
	   where contrast rules do not apply. */
	--tami-accent-raw: var(--tami-color-accent, #7cbb42);

	/* Interactive accent ("ink") — the colour used for anything a user must be
	   able to READ or SEE: links, buttons, focus rings. The raw brand green is
	   2.3:1 on white, so it can never be used for text or for a focus
	   indicator. --tami-color-accent-strong is the server-computed
	   darkening of whatever accent is in effect, and it is now emitted on
	   every render (region page or not), so it is the value that normally
	   wins here. The @supports derivation further down and the hand-checked
	   #4e7d24 below it remain as fallbacks for a page that somehow gets the
	   stylesheets without the computed block. */
	--tami-accent-ink: var(--tami-color-accent-strong, #4e7d24);

	/* Neutrals, aliased so the long var() chains below stay readable. */
	--tami-ink: var(--tami-color-heading, #1a1a1a);
	--tami-body-ink: var(--tami-color-text, #2b2b2b);
	--tami-muted-ink: var(--tami-color-text-muted, #5f6b6d);
	--tami-surface: var(--tami-color-surface, #ffffff);
	--tami-line: var(--tami-color-border, #e3e6e8);

	/* A barely-there tint used for alternating section surfaces. Kept as an
	   rgba wash rather than a solid so it works over any page background the
	   theme happens to have. */
	--tami-wash: rgba(16, 24, 32, 0.028);

	/* Elevation. Two soft layers rather than one hard one: a 1px contact
	   shadow that defines the edge, plus a wide ambient shadow that gives the
	   card its lift. The raised pair is deliberately *offset further* rather
	   than merely darker, which is what reads as "coming toward you". */
	--tami-elev-rest: 0 1px 2px rgba(16, 24, 32, 0.05), 0 6px 18px rgba(16, 24, 32, 0.07);
	--tami-elev-raise: 0 2px 4px rgba(16, 24, 32, 0.07), 0 18px 42px rgba(16, 24, 32, 0.14);

	/* Radii. A single family, scaled: cards are softer than controls. */
	--tami-radius-card: 14px;
	--tami-radius-control: 8px;
	--tami-radius-pill: 999px;

	/* Local micro-spacing. The macro rhythm (section / row / col / module)
	   comes from settings; these are the small in-component gaps that no
	   administrator should have to think about. */
	--tami-step-1: 0.375rem;
	--tami-step-2: 0.625rem;
	--tami-step-3: 1rem;
	--tami-step-4: 1.5rem;

	/* One easing curve everywhere, so unrelated components still feel like
	   one product. Slight overshoot-free ease-out. */
	--tami-ease: cubic-bezier(0.22, 0.7, 0.28, 1);
	--tami-dur: 220ms;

	/*
	 * RESPONSIVE SHELL TOKENS (§0, consumed in §2).
	 *
	 * These two are the ONLY place the phone→tablet container switch is
	 * expressed. The container, the hero inner and the section divider rule
	 * all read them, so those three can never disagree about where the gutter
	 * is — which is exactly what went wrong when each carried its own
	 * `max-width: 860px` copy of the same idea. One media query in §2 flips
	 * both, and the whole shell follows.
	 */
	--tami-gutter: clamp(1rem, 5vw, 1.75rem);
	--tami-shell-width: 100%;

	/*
	 * iOS text inflation. Safari on iPhone silently enlarges the text of any
	 * block it decides is "too narrow" when the device rotates to landscape,
	 * which breaks a carefully set type scale and, worse, changes it only on
	 * rotation so it looks like a rendering glitch. 100% means "use the size
	 * I asked for". It does NOT disable pinch zoom — that would be an
	 * accessibility failure (WCAG 1.4.4); it only stops the automatic
	 * inflation.
	 */
	-webkit-text-size-adjust: 100%;
	text-size-adjust: 100%;

	/*
	 * Android Chrome paints an opaque grey rectangle over any tapped link.
	 * On a card whose whole surface is the target that flashes the entire
	 * card grey. Replaced with a faint tint of our own; the real press
	 * feedback is the :active state in §21, so touch users still get an
	 * immediate answer to their tap.
	 */
	-webkit-tap-highlight-color: rgba(16, 24, 32, 0.12);

	/* Root box: honour the administrator's page padding/margin controls. */
	background-color: var(--tami-color-bg, transparent);
	font-weight: var(--tami-weight-body, 400);
	letter-spacing: var(--tami-letter-spacing, normal);
	margin-block: var(--tami-margin-block-start, 0) var(--tami-margin-block-end, 0);
	padding-block: var(--tami-pad-block-start, 0) var(--tami-pad-block-end, 0);
	padding-inline: var(--tami-pad-inline, 0);
	word-spacing: var(--tami-word-spacing, normal);
}

/* Mirror the gradient flow for right-to-left locales (fa_IR). */
.tami:dir(rtl) {
	--tami-flow: 270deg;
}

/*
 * Region-aware interactive colour.
 *
 * color-mix lets a region's accent tint its links and buttons while still
 * clearing AA: mixing 62% of the accent into a near-black green drags any
 * hue the client picks down into readable territory. Wrapped in @supports so
 * browsers without color-mix simply keep the hand-checked #4e7d24 above —
 * a slightly less colourful page, never an unreadable one.
 */
@supports (color: color-mix(in srgb, #000 50%, #fff)) {
	.tami {
		--tami-accent-ink: var(--tami-color-accent-strong, color-mix(in srgb, var(--tami-color-accent, #7cbb42) 62%, #0d1f08));
	}
}

/* -------------------------------------------------------------------------
 * 2. CONTAINER
 *
 * CONTRACTS-V2 §8.3: width 80%, max-width 1600px, centred.
 *
 * Percentage gutters are right on wide screens and wrong on phones — 10% of
 * 360px is 36px of dead space on each side of an already cramped column. So
 * the phone gets a real, clamped inline padding and the full width, and the
 * administrator's proportional container takes over from tablet portrait up.
 * Same visual gutter language at both ends, no cramping in the middle.
 *
 * Written mobile-first through the two shell tokens declared in §1, so the
 * hero (§4) and the section dividers (§6) switch on the SAME query as the
 * container and cannot drift apart.
 * ------------------------------------------------------------------------- */

.tami__container {
	inline-size: var(--tami-shell-width, 100%);
	margin-inline: auto;
	max-inline-size: var(--tami-page-max, 1600px);
	padding-inline: var(--tami-gutter, clamp(1rem, 5vw, 1.75rem));
}

/*
 * APPLE SAFE AREAS.
 *
 * An iPhone in landscape puts the notch/Dynamic Island inside the layout
 * viewport, and the home indicator along the bottom. env() reports how much to
 * keep clear. The inset is physical by nature — the notch does not move when
 * the locale is Farsi — so the SAME max() is applied to both inline sides,
 * which keeps the rule direction-neutral and RTL-safe.
 *
 * Two reasons this is a separate @supports block rather than being folded into
 * the token above. First, a browser with no env() support would treat the
 * whole custom-property value as invalid at computed-value time, and every
 * property reading it would fall back to its INITIAL value — the gutter would
 * not degrade, it would disappear. Second, it documents itself: the base token
 * is the design, this is the device accommodation.
 *
 * NOTE: env() resolves to 0 unless the theme's viewport meta tag carries
 * `viewport-fit=cover`. See INTEGRATION NEEDS.
 */
@supports (padding: max(0px, env(safe-area-inset-left, 0px))) {
	.tami {
		--tami-gutter: max(
			clamp(1rem, 5vw, 1.75rem),
			env(safe-area-inset-left, 0px),
			env(safe-area-inset-right, 0px)
		);
	}
}

/*
 * lg (768px) — tablet portrait and up.
 *
 * THE one query that switches the whole shell from "phone gutters" to the
 * administrator's proportional container. 768px is chosen because it is the
 * portrait width of every iPad: at that size 10% side margins read as design,
 * whereas at 400px they read as waste.
 */
@media (min-width: 48rem) {
	.tami {
		--tami-gutter: 0px;
		--tami-shell-width: var(--tami-page-width, 80%);
	}
}

/* A container nested inside another must not gutter twice. */
.tami__container .tami__container {
	inline-size: 100%;
	max-inline-size: none;
	padding-inline: 0;
}

/* -------------------------------------------------------------------------
 * 3. TYPOGRAPHY
 *
 * Sizes come from settings as px integers; the fallbacks are fluid clamps so
 * an unconfigured install still scales smoothly between phone and desktop
 * instead of snapping at each breakpoint (§0 rule 3).
 *
 * Every clamp below is built the same way: clamp(MIN, PREFERRED, MAX) where
 * PREFERRED is `Xrem + Yvw`. The rem part is what a user's own font-size
 * setting scales, the vw part is what the viewport scales — a pure-vw
 * preferred value would ignore the browser zoom setting entirely, which fails
 * WCAG 1.4.4. MIN is the small-phone size and MAX the ultra-wide ceiling, so
 * the type has stopped growing well before 4K.
 * ------------------------------------------------------------------------- */

/*
 * 3.1 THE MOBILE BODY-COPY FLOOR — 16px, non-negotiable.
 *
 * Below 16px, iOS Safari zooms the whole viewport the moment a form field
 * takes focus, and it does not zoom back out: the visitor is left on a page
 * that scrolls sideways, which is the exact failure §0 rule 2 exists to
 * prevent. 16px is also simply the smallest size long-form copy is
 * comfortable at on a phone held at arm's length.
 *
 * max() rather than an override, so the administrator's body_size setting is
 * always honoured UPWARD and only ever corrected downward, on small screens
 * alone; from tablet portrait up the setting is used exactly as entered.
 */
.tami {
	font-size: max(1rem, var(--tami-size-body, 1rem));
}

@media (min-width: 48rem) {
	.tami {
		font-size: var(--tami-size-body, 1rem);
	}
}

.tami__hero-title,
.tami__page-title,
.tami__section-title,
.tami__card-title,
.tami__leader-name {
	color: var(--tami-ink);
	font-family: var(--tami-font-heading, inherit);
	font-weight: var(--tami-weight-heading, 700);
	/* Headings set tighter than body copy; large type needs less leading. */
	line-height: 1.18;
	/* A 30-character ministry name in a 288px column has to be allowed to
	   break, or it decides the width of the whole page. */
	overflow-wrap: break-word;
	/* Avoids a one-word last line on a two-line title. Progressive; ignored
	   where unsupported. */
	text-wrap: balance;
}

/*
 * THE HERO-LESS PAGE TITLE.
 *
 * The plugin's heroed pages put their <h1> on the hero scrim
 * (.tami__hero-title). The submission form and the login prompt have no
 * hero, but the theme's own title is suppressed on them all the same (§17), so
 * they render this instead — otherwise those pages have no visible heading at
 * all, which is a navigation failure long before it is a design one.
 *
 * It reads the SAME --tami-size-h1 the hero does, so an administrator who
 * sets a heading size sets it once. The clamp is more restrained than the
 * hero's because this title sits on the page background at the top of a long
 * form rather than on a full-bleed band: at the hero's 3.5rem ceiling it
 * shouted over the first field.
 *
 * Colour comes from --tami-ink (the heading token, #1a1a1a by default,
 * 16:1 on white) — NOT from the accent. A page title is text to be read.
 */
.tami__page-title {
	font-size: var(--tami-size-h1, clamp(1.75rem, 1.4rem + 1.6vw, 2.5rem));
	letter-spacing: -0.015em;
	margin-block: 0 var(--tami-space-row, 2rem);
	/* A long page title should still break to a comfortable measure rather
	   than run the full width of a 1600px shell. */
	max-inline-size: 24ch;
}

/*
 * Justified body copy — CONTRACTS-V2 §8.6.
 *
 * Justification only works when the renderer is allowed to hyphenate; without
 * it, a narrow measure opens "rivers" of white space down the column. So:
 * hyphens:auto to let the engine break words, overflow-wrap:break-word so a
 * long URL cannot punch out of the column, and a ~72ch measure because
 * justified text degrades fastest at long line lengths.
 *
 * On a phone the column is simply too narrow for justification to ever look
 * right — at 288px a justified line holds perhaps five words and the spacing
 * between them goes visibly elastic — so the phone default is ragged-end
 * (text-align: start, logical, therefore ragged-left in Farsi) and
 * justification is switched ON at md (640px), the first width at which the
 * measure can carry it. That is the same decision the old
 * `max-width: 40rem` override made, restated mobile-first.
 */
.tami__prose {
	color: var(--tami-body-ink);
	/* The §3.1 floor, restated here because prose may set its own size from
	   the body_size token and must not fall under 16px on a phone either. */
	font-size: max(1rem, var(--tami-size-body, 1.0625rem));
	hyphens: auto;
	line-height: var(--tami-line-height, 1.75);
	/* Measure, not width: 72ch is the readability ceiling and it is what keeps
	   an ultra-wide screen from producing 200-character lines (§22). */
	max-inline-size: 72ch;
	overflow-wrap: break-word;
	text-align: start;
}

/* md (640px) — the measure is now wide enough to justify. */
@media (min-width: 40rem) {
	.tami__prose {
		text-align: justify;
	}
}

/* lg (768px) — past the phone, the administrator's size is used verbatim. */
@media (min-width: 48rem) {
	.tami__prose {
		font-size: var(--tami-size-body, 1.0625rem);
	}
}

.tami__prose > * + * {
	margin-block-start: var(--tami-space-module, 1rem);
}

/* Headings inside prose are never justified — a two-word heading stretched
   across 72ch is the classic justification failure. That is enforced by the
   `.tami h2, .tami h3, .tami h4` rule in §27.2, which outranks this
   selector; restating it here won nothing and would have hidden the fact that
   §27.2 is where heading alignment is actually decided. */
.tami__prose h2,
.tami__prose h3,
.tami__prose h4 {
	color: var(--tami-ink);
	font-family: var(--tami-font-heading, inherit);
	margin-block-start: var(--tami-space-row, 2rem);
	text-wrap: balance;
}

/* Links inside a block of text carry an underline at rest: colour alone would
   fail WCAG 1.4.1 (use of colour). */
.tami__prose a {
	color: var(--tami-accent-ink);
	text-decoration: underline;
	text-decoration-thickness: from-font;
	text-underline-offset: 0.16em;
}

.tami__prose a:hover {
	text-decoration-thickness: 2px;
}

.tami__prose blockquote {
	border-inline-start: 3px solid var(--tami-accent-raw);
	color: var(--tami-ink);
	font-size: 1.0625em;
	font-style: italic;
	margin-inline: 0;
	padding-inline-start: var(--tami-step-4);
	/* A pull quote is display type, not a block of copy — never justify.
	   LOAD-BEARING, unlike the two alignment restatements removed above it:
	   §27.2 justifies `.tami__prose`, a blockquote inherits that, and no
	   other rule names blockquote. Delete this and pull quotes justify. */
	text-align: start;
}

.tami__prose img {
	block-size: auto;
	border-radius: var(--tami-radius-control);
	max-inline-size: 100%;
}

/* -------------------------------------------------------------------------
 * 4. HERO
 *
 * CONTRACTS-V2 §8.2: every plugin page gets a hero, with breadcrumbs pinned
 * at the TOP of it.
 *
 * Design notes:
 *  - The hero is the only full-bleed element in the system. Everything else
 *    lives inside the container, so the hero edge-to-edge photograph is what
 *    gives each region page its identity.
 *  - The scrim is a separate ::before layer rather than an extra
 *    background-image layer. That way it works whether Agent E sets the photo
 *    via the --tami-hero-image custom property or as an inline
 *    background-image on the element (inline styles would otherwise blow away
 *    a multi-layer background shorthand and take the scrim with them).
 *  - The base colour underneath is a deep near-black green. With no image at
 *    all the hero is still a designed object — a dark field with a soft accent
 *    wash — and the light text on it still clears AA. NEVER trust the
 *    photograph to be dark.
 * ------------------------------------------------------------------------- */

.tami__hero {
	background-color: #101815;
	background-image: var(--tami-hero-image, none);
	background-position: 50% 50%;
	background-repeat: no-repeat;
	background-size: cover;
	color: #ffffff;
	isolation: isolate;
	margin-block-end: var(--tami-space-section, 4rem);
	overflow: hidden;
	position: relative;
}

/*
 * The scrim.
 *
 * Two stacked gradients: a vertical one that is heaviest at the top (where
 * the breadcrumbs sit) and at the bottom (where the title sits), plus a flat
 * floor of rgba(9,14,11,0.55) so that even the brightest possible photograph
 * cannot drop white text below AA. Measured worst case: white on the lightest
 * point of the scrim over pure white imagery ≈ 5.4:1.
 */
.tami__hero::before {
	background-image:
		linear-gradient(180deg, rgba(9, 14, 11, 0.78) 0%, rgba(9, 14, 11, 0.34) 42%, rgba(9, 14, 11, 0.82) 100%),
		linear-gradient(0deg, rgba(9, 14, 11, 0.55), rgba(9, 14, 11, 0.55));
	content: "";
	inset: 0;
	position: absolute;
	z-index: -1;
}

/*
 * A single hairline of the region accent along the bottom edge, so the hero
 * hands off to the page with a deliberate line rather than just stopping.
 */
.tami__hero::after {
	background: var(--tami-accent-raw);
	block-size: 3px;
	content: "";
	inset-block-end: 0;
	inset-inline: 0;
	position: absolute;
}

/* Legacy modifier from the previous markup generation — the base rule above
   already handles the image, so this only needs to exist so the class is not
   dead. */
.tami__hero--has-image {
	background-image: var(--tami-hero-image, none);
}

/*
 * ON "FULL BLEED".
 *
 * The hero fills the entire inline size of the plugin root, edge to edge, with
 * the container gutters living on .tami__hero-inner instead. When Agent E's
 * shortcode output sits in a Divi fullwidth section (or any theme row without
 * a max width) that IS a viewport-edge hero, which is the intended placement.
 *
 * The classic `margin-inline: calc(50% - 50vw)` trick was tried here and
 * deliberately removed. It widens the element to exactly 100vw, and 100vw
 * includes the scrollbar, so on desktop it overhangs the visible area by
 * ~15px and produces a horizontal scrollbar on every plugin page. The usual
 * cure is clipping on an ancestor that spans the viewport — but this plugin
 * never owns the page shell, and clipping on .tami itself would simply
 * clip the bleed back off again. So the bleed is a placement decision, not a
 * CSS one. See INTEGRATION NEEDS.
 */

.tami__hero-inner {
	display: flex;
	flex-direction: column;
	/* Shell tokens (§1/§2): full width with a gutter on phones, the
	   administrator's proportional container from tablet portrait up. The
	   element also carries .tami__container, so these repeat that rule on
	   purpose — a theme override of hero.php that drops the container class
	   must not lose its gutters. */
	inline-size: var(--tami-shell-width, 100%);
	margin-inline: auto;
	max-inline-size: var(--tami-page-max, 1600px);
	/*
	 * THE iOS 100vh PROBLEM.
	 *
	 * On mobile Safari `vh` is resolved against the LARGE viewport — the one
	 * you get with the address bar collapsed — so a 100vh box is taller than
	 * the screen for as long as the bar is visible, and the page starts life
	 * scrolled. `svh` is the SMALL viewport height: the worst case, with every
	 * piece of browser chrome on screen. For a MINIMUM height that is the
	 * right unit, because it guarantees the hero fits whatever the bar is
	 * doing, and it does not resize mid-scroll the way dvh does (a hero that
	 * grows and shrinks as you scroll is far worse than one that is 60px
	 * shorter than it could have been).
	 *
	 * The vh line is the fallback and MUST stay first: browsers that do not
	 * know svh drop the second declaration and keep it.
	 */
	min-block-size: clamp(15rem, 32vh, 26rem);
	min-block-size: clamp(15rem, 32svh, 26rem);
	/*
	 * Generous vertical rhythm, driven by the section-spacing control, with
	 * two ceilings: an absolute one (5rem) so a very large section_spacing
	 * cannot produce a hero taller than the screen, and a proportional one
	 * (9svh) so the padding shrinks on a short viewport. On a 1080px desktop
	 * 9svh is 97px and the 4rem setting wins — nothing changes. On a 568px
	 * iPhone SE it is 51px, which gives ~26px of the next section back.
	 *
	 * The svh pair is progressive: the vh line before it is the fallback.
	 */
	padding-block: min(var(--tami-space-section, 4rem), 9vh, 5rem) min(var(--tami-space-section, 4rem), 10vh, 5.5rem);
	padding-block: min(var(--tami-space-section, 4rem), 9svh, 5rem) min(var(--tami-space-section, 4rem), 10svh, 5.5rem);
	padding-inline: var(--tami-gutter, clamp(1rem, 5vw, 1.75rem));
	position: relative;
}

/*
 * wide (1600px) — a hero that is 1600px across and 420px tall reads as a
 * letterbox strip rather than a stage. Past the point where the container
 * stops growing, the hero gains height instead so its proportions hold.
 */
@media (min-width: 100rem) {
	.tami__hero-inner {
		min-block-size: clamp(20rem, 34vh, 30rem);
		min-block-size: clamp(20rem, 34svh, 30rem);
	}
}

/* Breadcrumbs sit at the top of the hero; the title block is pushed to the
   bottom so tall heroes keep the H1 optically anchored. */
.tami__hero-title {
	color: #ffffff;
	font-size: var(--tami-size-h1, clamp(2rem, 1.35rem + 2.9vw, 3.5rem));
	letter-spacing: -0.015em;
	margin-block: auto 0;
	max-inline-size: 20ch;
	padding-block-start: var(--tami-space-row, 2rem);
}

.tami__hero-desc {
	color: rgba(255, 255, 255, 0.92);
	font-size: clamp(1.0625rem, 1rem + 0.3vw, 1.25rem);
	line-height: 1.55;
	margin-block: var(--tami-space-module, 1rem) 0;
	max-inline-size: 62ch;
}

.tami__hero-blurb {
	color: rgba(255, 255, 255, 0.86);
	margin-block: var(--tami-space-module, 1rem) 0;
	max-inline-size: 62ch;
}

.tami__hero-blurb > *:first-child {
	margin-block-start: 0;
}

.tami__hero-blurb > *:last-child {
	margin-block-end: 0;
}

.tami__hero-cta {
	align-items: center;
	background: var(--tami-accent-raw);
	border: 1px solid transparent;
	border-radius: var(--tami-radius-pill);
	/* Near-black on the bright accent: 8:1+, and it survives any accent a
	   region picks far better than white would. */
	color: #10240a;
	display: inline-flex;
	font-weight: 700;
	justify-content: center;
	letter-spacing: 0.01em;
	margin-block-start: var(--tami-space-row, 2rem);
	/* WCAG 2.5.5 comfortable target. */
	min-block-size: 44px;
	padding-block: 0.7em;
	padding-inline: 1.6em;
	text-decoration: none;
	transition: transform var(--tami-dur) var(--tami-ease), box-shadow var(--tami-dur) var(--tami-ease);
}

/* align-self keeps the CTA hugging its own text width inside the hero's flex
   column instead of stretching to the full hero width. */
.tami__hero-inner > .tami__hero-cta {
	align-self: flex-start;
}

/*
 * THE PILL-INSIDE-A-PILL.
 *
 * The rules above assume .tami__hero-cta IS the link. templates/hero.php
 * renders it as a <p> WRAPPING an <a class="tami__button">, so both boxes
 * paint a pill: an accent capsule with a second accent capsule inside it,
 * carrying two sets of padding. On a 320px phone that costs about 110px of
 * hero height and pushes the button's own label into two lines — which is
 * what made it visible.
 *
 * :has() lets this be fixed without touching either template or breaking the
 * other reading: when the element CONTAINS a button it steps back and becomes
 * a plain positioning wrapper; when it IS the button (any markup that puts
 * the class straight on an <a>) nothing matches and the rules above stand.
 * Browsers without :has() simply keep the current double pill.
 */
.tami__hero-cta:has(.tami__button) {
	background: none;
	border: 0;
	border-radius: 0;
	box-shadow: none;
	min-block-size: 0;
	padding-block: 0;
	padding-inline: 0;
}

/* The wrapper must not answer to the pointer either — the button inside it
   already does, and two lifts on one control read as a rendering fault. */
.tami__hero-cta:has(.tami__button):hover,
.tami__hero-cta:has(.tami__button):focus-visible {
	box-shadow: none;
	transform: none;
}

.tami__hero-cta:hover,
.tami__hero-cta:focus-visible {
	box-shadow: 0 10px 26px rgba(0, 0, 0, 0.35);
	color: #10240a;
	transform: translateY(-2px);
}

/* -------------------------------------------------------------------------
 * 5. BREADCRUMBS (top of hero)
 * ------------------------------------------------------------------------- */

.tami__breadcrumbs {
	color: rgba(255, 255, 255, 0.78);
	display: flex;
	flex-wrap: wrap;
	font-size: 0.875rem;
	gap: 0.15rem var(--tami-step-2);
	letter-spacing: 0.02em;
	line-height: 1.4;
}

.tami__breadcrumb-item {
	align-items: center;
	color: rgba(255, 255, 255, 0.82);
	display: inline-flex;
	/* Comfortable pointer target without inflating the visual line height. */
	min-block-size: 28px;
	padding-block: 0.2em;
	text-decoration: none;
	transition: color var(--tami-dur) var(--tami-ease);
}

.tami__breadcrumb-item:hover,
.tami__breadcrumb-item:focus-visible {
	color: #ffffff;
	text-decoration: underline;
	text-underline-offset: 0.2em;
}

.tami__breadcrumb-sep {
	color: rgba(255, 255, 255, 0.45);
	/* Purely decorative; Agent E marks it aria-hidden. */
	user-select: none;
}

.tami__breadcrumb-current {
	align-items: center;
	color: #ffffff;
	display: inline-flex;
	font-weight: 600;
	min-block-size: 28px;
	padding-block: 0.2em;
}

/* -------------------------------------------------------------------------
 * 6. SECTIONS
 *
 * CONTRACTS-V2 §8.4 — the explicit client ask: sections must read as separate
 * things. Three devices, used together and deliberately quiet:
 *
 *   a) Rhythm. Every section is separated by --tami-space-section, which
 *      is roughly double the internal row spacing. Whitespace does most of
 *      the work; that is what makes it feel editorial rather than boxed-in.
 *   b) A hairline rule with an accent segment at its reading start
 *      (.tami__section--divider). The rule is drawn as a block-level
 *      ::before sized to the container, so it lines up exactly with the
 *      content instead of running edge-to-edge.
 *   c) An alternating surface wash on every second divided section, so long
 *      pages have a visible beat without any section shouting.
 * ------------------------------------------------------------------------- */

.tami__section {
	margin-block-start: var(--tami-space-section, 4rem);
	position: relative;
}

.tami__section:first-child {
	margin-block-start: 0;
}

/*
 * The separator. One gradient does both jobs: an accent segment for the first
 * 4.5rem, then the hairline for the rest. --tami-flow reverses the run in
 * RTL so the accent stays at the reading start.
 */
.tami__section--divider::before {
	background-image: linear-gradient(
		var(--tami-flow),
		var(--tami-accent-raw) 0,
		var(--tami-accent-raw) 4.5rem,
		var(--tami-line) 4.5rem,
		var(--tami-line) 100%
	);
	block-size: 2px;
	content: "";
	display: block;
	/* Tracks the shell exactly at every size: on a phone that is the full
	   width minus both gutters, from tablet portrait up it is the
	   administrator's page width. One expression, no breakpoint of its own —
	   this used to be a second `max-width: 860px` copy of §2 that could fall
	   out of step with it. */
	inline-size: calc(var(--tami-shell-width, 100%) - 2 * var(--tami-gutter, 0px));
	margin-block-end: var(--tami-space-section, 4rem);
	margin-inline: auto;
	max-inline-size: var(--tami-page-max, 1600px);
}

/*
 * Alternating surface tint. Applied to every second divided section so the
 * page reads as bands. The tint sits behind the divider rule, hence the
 * padding-block that lets the wash breathe around its content.
 */
.tami__section--divider:nth-of-type(even) {
	background-color: var(--tami-wash);
	padding-block-end: var(--tami-space-section, 4rem);
}

.tami__section-head {
	align-items: flex-end;
	display: flex;
	flex-wrap: wrap;
	gap: var(--tami-step-3) var(--tami-space-col, 1.5rem);
	justify-content: space-between;
	margin-block-end: var(--tami-space-row, 2rem);
}

.tami__section-title {
	font-size: var(--tami-size-h2, clamp(1.5rem, 1.25rem + 1.1vw, 2.125rem));
	letter-spacing: -0.01em;
	margin-block: 0;
	/* Anchor for the accent underline. */
	padding-block-end: 0.42em;
	position: relative;
}

/*
 * Consistent section-head accent underline. A short accent bar at rest that
 * extends to the full width of the title on hover/focus. Animated with
 * transform only, so it can never nudge the layout.
 */
.tami__section-title::after {
	background: var(--tami-accent-raw);
	block-size: 3px;
	border-radius: 2px;
	content: "";
	inline-size: 3rem;
	inset-block-end: 0;
	inset-inline-start: 0;
	position: absolute;
	transform-origin: 0 50%;
	transition: transform var(--tami-dur) var(--tami-ease);
}

/* transform-origin has no logical form — flip the growth anchor for RTL. */
.tami:dir(rtl) .tami__section-title::after {
	transform-origin: 100% 50%;
}

/* Grows from 3rem toward the title's own width. scaleX on a fixed-width bar
   is cheap and, unlike animating inline-size, never triggers layout. */
.tami__section-head:hover .tami__section-title::after,
.tami__section-head:focus-within .tami__section-title::after,
.tami__section-title:hover::after {
	transform: scaleX(2.4);
}

.tami__section-title a {
	color: inherit;
	text-decoration: none;
	transition: color var(--tami-dur) var(--tami-ease);
}

.tami__section-title a:hover,
.tami__section-title a:focus-visible {
	color: var(--tami-accent-ink);
}

.tami__section-actions {
	align-items: center;
	display: flex;
	flex-wrap: wrap;
	gap: var(--tami-step-2);
	/* Sits on the same optical baseline as the section title. */
	padding-block-end: 0.42em;
}

/* -------------------------------------------------------------------------
 * 7. GRIDS
 *
 * Read upward: 1 column on a phone, 2 from md (640px), 3 from xl (1024px).
 *
 * WHY HARD BREAKPOINTS HERE AND auto-fit ELSEWHERE.
 * The generic .tami__grid uses auto-fit/minmax (in the base sheet) because
 * it holds an unknown number of unknown things and "as many as fit" is the
 * honest answer. .tami__grid--3 cannot: CONTRACTS-V2 §8.9/§8.10 specify a
 * 3×3 block of nine, and auto-fit would happily render four across on a wide
 * screen and leave an orphan row of one. So the column COUNT is pinned and
 * only the step points are responsive.
 *
 * The two steps are content decisions, not device names: 640px is where two
 * 16:10 cards are each still wide enough for their photograph and a
 * three-line excerpt to read, and 1024px is where three are. They land on md
 * and xl of the §0 scale, which is why those tiers exist.
 * ------------------------------------------------------------------------- */

.tami__grid {
	display: grid;
	gap: var(--tami-space-row, 2rem) var(--tami-space-col, 1.5rem);
	list-style: none;
	margin-block: 0;
	padding-inline-start: 0;
}

.tami__grid > * {
	/* Grid items must be able to shrink below their content's intrinsic width
	   or a long unbroken word blows the column out. */
	margin-block: 0;
	min-inline-size: 0;
}

.tami__grid--3 {
	/* minmax(0, 1fr) rather than 1fr even at one column: the 1fr minimum is
	   auto, i.e. the content's intrinsic width, and one long word in one card
	   would otherwise widen the track and with it the page. */
	grid-template-columns: minmax(0, 1fr);
}

/* md (640px) — two across. */
@media (min-width: 40rem) {
	.tami__grid--3 {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

/* xl (1024px) — the contracted three across. */
@media (min-width: 64rem) {
	.tami__grid--3 {
		grid-template-columns: repeat(3, minmax(0, 1fr));
	}
}

/* -------------------------------------------------------------------------
 * 8. CARDS
 *
 * The "hero card": image-forward, elevated, with a fixed media aspect ratio so
 * a grid of mixed-crop photographs still lines up on a strict baseline.
 *
 * The whole card is the hover surface — hovering anywhere lifts the card,
 * zooms the photograph a touch, and draws the title underline. :focus-within
 * mirrors every one of those states so keyboard users get the same feedback.
 * ------------------------------------------------------------------------- */

.tami__card {
	background: var(--tami-surface);
	block-size: 100%;
	border: 1px solid var(--tami-line);
	border-radius: var(--tami-radius-card);
	box-shadow: var(--tami-elev-rest);
	display: flex;
	flex-direction: column;
	overflow: hidden;
	padding: 0;
	position: relative;
	transition:
		transform var(--tami-dur) var(--tami-ease),
		box-shadow var(--tami-dur) var(--tami-ease),
		border-color var(--tami-dur) var(--tami-ease);
}

.tami__card:hover,
.tami__card:focus-within {
	border-color: var(--tami-accent-raw);
	box-shadow: var(--tami-elev-raise);
	transform: translateY(-4px);
}

/* Media box — a fixed 16:10 window. object-fit does the cropping so no image
   is ever letterboxed or squashed. */
.tami__card-media {
	aspect-ratio: 16 / 10;
	background: var(--tami-line);
	display: block;
	line-height: 0;
	overflow: hidden;
	position: relative;
}

.tami__card-media img {
	block-size: 100%;
	display: block;
	inline-size: 100%;
	object-fit: cover;
	object-position: 50% 50%;
	transition: transform 420ms var(--tami-ease);
}

.tami__card:hover .tami__card-media img,
.tami__card:focus-within .tami__card-media img {
	transform: scale(1.045);
}

/* A soft floor on the photograph so a white-topped image never runs into the
   card body with no separation. */
.tami__card-media::after {
	background-image: linear-gradient(180deg, rgba(16, 24, 32, 0) 62%, rgba(16, 24, 32, 0.16) 100%);
	content: "";
	inset: 0;
	pointer-events: none;
	position: absolute;
}

.tami__card-body {
	display: flex;
	flex: 1 1 auto;
	flex-direction: column;
	gap: var(--tami-step-2);
	padding: var(--tami-space-col, 1.5rem);
}

.tami__card-title {
	/* Fluid fallback: 17px on a small phone up to 20px on a large desktop. If
	   the administrator has set h3_size that value wins outright — a chosen
	   number is a chosen number, and clamping it would look like a bug. */
	font-size: var(--tami-size-h3, clamp(1.0625rem, 1rem + 0.35vw, 1.25rem));
	line-height: 1.3;
	margin-block: 0;
}

.tami__card-title a {
	color: inherit;
	position: relative;
	text-decoration: none;
	transition: color var(--tami-dur) var(--tami-ease);
}

/*
 * Animated title underline. transform: scaleX only — animating a border or a
 * width would reflow the card on every hover.
 */
.tami__card-title a::after {
	background: currentColor;
	block-size: 2px;
	content: "";
	inset-block-end: -0.14em;
	inset-inline: 0;
	position: absolute;
	transform: scaleX(0);
	transform-origin: 0 50%;
	transition: transform var(--tami-dur) var(--tami-ease);
}

.tami:dir(rtl) .tami__card-title a::after {
	transform-origin: 100% 50%;
}

.tami__card:hover .tami__card-title a,
.tami__card:focus-within .tami__card-title a {
	color: var(--tami-accent-ink);
}

.tami__card:hover .tami__card-title a::after,
.tami__card:focus-within .tami__card-title a::after,
.tami__card-title a:hover::after {
	transform: scaleX(1);
}

/*
 * Meta line. Small caps-ish label styling with a middot between items, drawn
 * as a ::before on siblings so the markup does not need separator elements.
 */
.tami__card-meta {
	color: var(--tami-muted-ink);
	display: flex;
	flex-wrap: wrap;
	/* 13px on a phone, 12px from tablet portrait. Uppercase tracked-out type
	   at 12px is legible on a desktop monitor at 60cm and marginal on a phone
	   held at arm's length, so the small screen gets the larger size — the
	   opposite of the usual reflex, and the correct way round. */
	font-size: 0.8125rem;
	gap: 0.35em;
	letter-spacing: 0.06em;
	line-height: 1.4;
	margin-block: 0;
	text-transform: uppercase;
}

@media (min-width: 48rem) {
	.tami__card-meta {
		font-size: 0.75rem;
	}
}

.tami__card-meta > * + *::before {
	color: var(--tami-line);
	content: "·";
	margin-inline-end: 0.35em;
}

.tami__card-meta a {
	color: inherit;
	text-decoration: none;
}

.tami__card-meta a:hover {
	color: var(--tami-accent-ink);
	text-decoration: underline;
}

.tami__card-excerpt {
	color: var(--tami-body-ink);
	/* Three lines keeps every card in a row the same height regardless of how
	   long the editor's excerpt is. */
	-webkit-box-orient: vertical;
	display: -webkit-box;
	/* 16px on a phone, where the card is the full width of the screen and its
	   excerpt IS the body copy of the page; 15px from tablet portrait, where
	   the card is one of two or three columns and wants to sit back. */
	font-size: 1rem;
	-webkit-line-clamp: 3;
	line-clamp: 3;
	line-height: 1.6;
	margin-block: 0;
	overflow: hidden;
}

@media (min-width: 48rem) {
	.tami__card-excerpt {
		font-size: 0.9375rem;
	}
}

.tami__card-cta {
	align-items: center;
	color: var(--tami-accent-ink);
	display: inline-flex;
	font-size: 0.875rem;
	font-weight: 700;
	gap: 0.4em;
	letter-spacing: 0.02em;
	/* Pushed to the bottom of the card so CTAs align across a row even when
	   titles wrap to different heights. */
	margin-block: auto 0;
	min-block-size: 44px;
	padding-block-start: var(--tami-step-2);
	text-decoration: none;
}

.tami__card-cta:hover,
.tami__card-cta:focus-visible {
	text-decoration: underline;
	text-underline-offset: 0.2em;
}

/* The arrow slides toward the reading end on hover. margin-inline-start is
   logical, so it moves the correct way in Farsi. */
.tami__card-cta .tami__icon--directional {
	display: inline-block;
	transition: transform var(--tami-dur) var(--tami-ease);
}

.tami__card:hover .tami__card-cta .tami__icon--directional {
	transform: translateX(0.2em);
}

.tami:dir(rtl) .tami__card:hover .tami__card-cta .tami__icon--directional {
	transform: translateX(-0.2em);
}

/* -------------------------------------------------------------------------
 * 9. STAT CARDS ("At a Glance")
 *
 * CONTRACTS-V2 §8.8 — these are <a> elements, and the whole point of this
 * round is that they stop looking like dead numbers. Everything here is about
 * signalling "this is a link": pointer cursor, a lift on hover, an accent
 * rule that fills in, and a genuinely visible focus ring.
 * ------------------------------------------------------------------------- */

.tami__stat-card {
	align-items: center;
	background: var(--tami-surface);
	border: 1px solid var(--tami-line);
	border-radius: var(--tami-radius-card);
	box-shadow: var(--tami-elev-rest);
	color: inherit;
	cursor: pointer;
	display: flex;
	flex-direction: column;
	gap: 0.25rem;
	justify-content: center;
	/*
	 * Comfortably past the 44px minimum target in both axes, but sized for the
	 * two-column phone grid first. Measured on a 320px iPhone SE the cell is
	 * 111px wide, and "Contributors" — the longest label, and a single
	 * unbreakable word — needs 98px at this size. Hence the smallest inline
	 * padding step here: 6px a side leaves 99px and the label fits without
	 * being clipped by the overflow rule below. Both paddings step back up as
	 * soon as there is room (§20.1 sets the column counts).
	 */
	min-block-size: 7rem;
	overflow: hidden;
	padding-block: var(--tami-step-3);
	padding-inline: var(--tami-step-1);
	position: relative;
	text-align: center;
	text-decoration: none;
	transition:
		transform var(--tami-dur) var(--tami-ease),
		box-shadow var(--tami-dur) var(--tami-ease),
		border-color var(--tami-dur) var(--tami-ease);
}

/* sm (480px) — a large phone has room for the full inline padding again. */
@media (min-width: 30rem) {
	.tami__stat-card {
		padding-inline: var(--tami-step-3);
	}
}

/* md (640px) — three columns from here (§20.1), so the cell can take its
   full desktop proportions. */
@media (min-width: 40rem) {
	.tami__stat-card {
		min-block-size: 132px;
		padding-block: var(--tami-space-col, 1.5rem);
	}
}

/* Accent rule along the bottom edge: a short stub at rest that fills the full
   card width on hover — the affordance that says "clickable" without a
   button. */
.tami__stat-card::after {
	background: var(--tami-accent-raw);
	block-size: 4px;
	content: "";
	inset-block-end: 0;
	inset-inline: 0;
	position: absolute;
	transform: scaleX(0.22);
	transform-origin: 0 50%;
	transition: transform var(--tami-dur) var(--tami-ease);
}

.tami:dir(rtl) .tami__stat-card::after {
	transform-origin: 100% 50%;
}

.tami__stat-card:hover,
.tami__stat-card:focus-visible {
	border-color: var(--tami-accent-raw);
	box-shadow: var(--tami-elev-raise);
	color: inherit;
	transform: translateY(-4px);
}

.tami__stat-card:hover::after,
.tami__stat-card:focus-visible::after {
	transform: scaleX(1);
}

.tami__stat-card:focus-visible {
	outline: 3px solid var(--tami-accent-ink);
	outline-offset: 3px;
}

.tami__stat-num {
	color: var(--tami-ink);
	display: block;
	font-family: var(--tami-font-heading, inherit);
	/* 32px in a 143px phone cell, 52px on a desktop. The floor is what stops a
	   four-digit count wrapping inside the two-column phone grid. */
	font-size: clamp(2rem, 1.6rem + 1.9vw, 3.25rem);
	font-variant-numeric: tabular-nums;
	font-weight: 800;
	letter-spacing: -0.03em;
	line-height: 1;
	/* Same clipping guard as the label: a locale-formatted seven-figure count
	   is wider than a 111px phone cell, and wrapping at its group separator
	   beats having the last digits cut off. */
	max-inline-size: 100%;
}

.tami__stat-card:hover .tami__stat-num {
	color: var(--tami-accent-ink);
}

.tami__stat-label {
	color: var(--tami-muted-ink);
	display: block;
	font-size: 0.75rem;
	font-weight: 600;
	/* "CONTRIBUTORS" is the longest label. At 0.1em tracking it needs ~100px,
	   which is more than a 320px phone leaves inside a two-column cell, so the
	   tracking opens up only once the grid does. */
	letter-spacing: 0.04em;
	line-height: 1.3;
	/*
	 * The cell is a centred flex column, so this span is sized by its
	 * content — and a single unbreakable word is allowed to be wider than the
	 * box that holds it, at which point the cell's `overflow: hidden` silently
	 * cuts the end off. Capping the span at the cell's own width forces the
	 * inherited overflow-wrap to do its job and WRAP instead of clip. It is
	 * the difference between "Contributor" and "Contributors" in five of the
	 * six locales, where the translated label is longer than the English.
	 */
	max-inline-size: 100%;
	text-transform: uppercase;
}

@media (min-width: 30rem) {
	.tami__stat-label {
		letter-spacing: 0.1em;
	}
}

/* -------------------------------------------------------------------------
 * 10. PAGINATION AND "VIEW ALL"
 *
 * Every control is at least 44×44 (WCAG 2.5.5). The current page is marked by
 * fill AND weight AND aria-current in the markup — never by colour alone.
 * ------------------------------------------------------------------------- */

.tami__pagination {
	align-items: center;
	display: flex;
	flex-wrap: wrap;
	gap: var(--tami-step-2);
	justify-content: center;
	margin-block-start: var(--tami-space-row, 2rem);
}

.tami__page-link,
.tami__page-current {
	align-items: center;
	border: 1px solid var(--tami-line);
	border-radius: var(--tami-radius-control);
	display: inline-flex;
	font-size: 0.9375rem;
	font-variant-numeric: tabular-nums;
	font-weight: 600;
	justify-content: center;
	line-height: 1;
	min-block-size: 44px;
	min-inline-size: 44px;
	padding-inline: 0.85em;
	text-decoration: none;
}

.tami__page-link {
	background: var(--tami-surface);
	color: var(--tami-accent-ink);
	transition:
		background-color var(--tami-dur) var(--tami-ease),
		border-color var(--tami-dur) var(--tami-ease),
		color var(--tami-dur) var(--tami-ease);
}

.tami__page-link:hover,
.tami__page-link:focus-visible {
	background: var(--tami-wash);
	border-color: var(--tami-accent-raw);
	color: var(--tami-accent-ink);
}

/* Current page: filled, heavier, and not a link. Three independent signals. */
.tami__page-current {
	background: var(--tami-accent-ink);
	border-color: var(--tami-accent-ink);
	color: #ffffff;
	font-weight: 800;
}

.tami__view-all {
	align-items: center;
	border: 1px solid var(--tami-line);
	border-radius: var(--tami-radius-pill);
	color: var(--tami-accent-ink);
	display: inline-flex;
	font-size: 0.875rem;
	font-weight: 700;
	gap: 0.45em;
	justify-content: center;
	letter-spacing: 0.03em;
	min-block-size: 44px;
	padding-inline: 1.35em;
	text-decoration: none;
	text-transform: uppercase;
	transition:
		background-color var(--tami-dur) var(--tami-ease),
		border-color var(--tami-dur) var(--tami-ease),
		transform var(--tami-dur) var(--tami-ease);
}

.tami__view-all:hover,
.tami__view-all:focus-visible {
	background: var(--tami-wash);
	border-color: var(--tami-accent-raw);
	color: var(--tami-accent-ink);
	transform: translateY(-1px);
}

.tami__view-all .tami__icon--directional {
	transition: transform var(--tami-dur) var(--tami-ease);
}

.tami__view-all:hover .tami__icon--directional {
	transform: translateX(0.2em);
}

.tami:dir(rtl) .tami__view-all:hover .tami__icon--directional {
	transform: translateX(-0.2em);
}

/* -------------------------------------------------------------------------
 * 11. LEADERSHIP BLOCK
 *
 * Portrait grid. Circular crops with a hairline ring; a photograph is optional,
 * so the placeholder (initials on an accent tint) is designed rather than an
 * empty hole.
 * ------------------------------------------------------------------------- */

.tami__leadership {
	display: grid;
	gap: var(--tami-space-row, 2rem) var(--tami-space-col, 1.5rem);
	grid-template-columns: repeat(auto-fit, minmax(min(100%, 168px), 1fr));
	list-style: none;
	margin-block: 0;
	padding-inline-start: 0;
}

.tami__leader {
	display: flex;
	flex-direction: column;
	gap: var(--tami-step-1);
	margin-block: 0;
	min-inline-size: 0;
	text-align: center;
}

.tami__leader-photo {
	align-items: center;
	aspect-ratio: 1 / 1;
	/* The tint doubles as the placeholder background when no <img> is present. */
	background: color-mix(in srgb, var(--tami-accent-raw) 18%, #ffffff);
	block-size: auto;
	border-radius: 50%;
	box-shadow: 0 0 0 1px var(--tami-line), var(--tami-elev-rest);
	color: var(--tami-accent-ink);
	display: flex;
	font-family: var(--tami-font-heading, inherit);
	font-size: 1.5rem;
	font-weight: 700;
	inline-size: min(100%, 144px);
	justify-content: center;
	margin-block-end: var(--tami-step-2);
	margin-inline: auto;
	object-fit: cover;
	object-position: 50% 20%;
	overflow: hidden;
	transition: box-shadow var(--tami-dur) var(--tami-ease), transform var(--tami-dur) var(--tami-ease);
}

/* color-mix fallback: a flat neutral tint is fine, it is decorative. */
@supports not (color: color-mix(in srgb, #000 50%, #fff)) {
	.tami__leader-photo {
		background: #eef3e8;
	}
}

.tami__leader:hover .tami__leader-photo {
	box-shadow: 0 0 0 2px var(--tami-accent-raw), var(--tami-elev-raise);
	transform: translateY(-3px);
}

.tami__leader-name {
	color: var(--tami-ink);
	font-size: 1rem;
	line-height: 1.3;
	margin-block: 0;
	overflow-wrap: break-word;
}

.tami__leader-role {
	color: var(--tami-muted-ink);
	font-size: 0.75rem;
	letter-spacing: 0.07em;
	line-height: 1.4;
	margin-block: 0;
	text-transform: uppercase;
}

/* -------------------------------------------------------------------------
 * 12. EMPTY STATE
 *
 * An empty region should still look intentional. Dashed hairline, centred,
 * with room for an optional CTA.
 * ------------------------------------------------------------------------- */

.tami__empty {
	background: var(--tami-surface);
	border: 1px dashed var(--tami-line);
	border-radius: var(--tami-radius-card);
	color: var(--tami-muted-ink);
	display: grid;
	gap: var(--tami-step-2);
	justify-items: center;
	padding-block: clamp(2.5rem, 6vw, 4rem);
	padding-inline: var(--tami-step-4);
	text-align: center;
}

.tami__empty > * {
	margin-block: 0;
	max-inline-size: 46ch;
}

/* -------------------------------------------------------------------------
 * 13. SIDEBAR LAYOUT VARIANTS
 *
 * _tami_sidebar defaults to `none`, and CONTRACTS-V2 §8.7 says the layout
 * renders full width unless a post opts in. §6 names the root modifiers but
 * not the child elements, so the two-column rules below are written against
 * a __layout / __main / __aside triplet and are inert if that markup is not
 * present. Flagged under INTEGRATION NEEDS.
 * ------------------------------------------------------------------------- */

.tami--sidebar-none .tami__layout {
	display: block;
}

.tami__layout {
	display: grid;
	gap: var(--tami-space-row, 2rem) var(--tami-space-col, 1.5rem);
	grid-template-columns: minmax(0, 1fr);
}

.tami__layout > * {
	min-inline-size: 0;
}

/*
 * xl (1024px) — the first width where a 320px aside can sit beside a column
 * of body copy and leave that column a readable measure. Below it the aside
 * stacks under the main content, in document order, which is why the markup
 * puts it after: a sidebar that reads before the article on a phone is a
 * content bug, not a layout one.
 */
@media (min-width: 64rem) {
	/* order is a logical concept in grid: 1 is first in the reading direction,
	   so this mirrors correctly in Farsi with no extra rules. */
	.tami--sidebar-left .tami__layout,
	.tami--sidebar-right .tami__layout {
		grid-template-columns: minmax(0, 1fr) minmax(0, 320px);
	}

	.tami--sidebar-left .tami__layout {
		grid-template-columns: minmax(0, 320px) minmax(0, 1fr);
	}

	.tami--sidebar-left .tami__aside {
		order: -1;
	}
}

/* -------------------------------------------------------------------------
 * 14. SHARED CONTROLS AND LEGACY MARKUP
 *
 * The classes below are still emitted by templates written in the previous
 * round (submission form, contributor dashboard, filters, the earlier card
 * and single layouts). They are kept and re-skinned to the new system so
 * nothing regresses while markup migrates to the §6 contract.
 * ------------------------------------------------------------------------- */

/*
 * Buttons use the accent EXACTLY as chosen, not a darkened derivative.
 *
 * Previously the fill was --tami-accent-ink, an auto-darkened variant
 * generated so that white label text would pass AA. The side effect was that
 * an admin who picked light green (#7cbb42) saw a dark green button sitting
 * next to light green accents elsewhere — two colours from one setting, which
 * reads as a bug because it is one.
 *
 * The fix keeps both promises: paint the button in the admin's actual colour
 * and pick the LABEL colour to suit it. StyleInheritance computes
 * --tami-color-accent-contrast (dark ink on light accents, white on dark
 * ones) and emits it on `.tami` for every render, region or not, so
 * contrast is AA everywhere without overriding the choice.
 *
 * The var() fallback below is #1a1a1a, NOT white: a fallback is only reached
 * when nothing has set the token, and in that case the fill is the
 * stylesheet's own default #7cbb42 — a light green, on which white is 2.3:1
 * and near-black is 7.5:1. A fallback has to be measured against the fill its
 * own sheet would paint, not against a dark accent somebody might pick.
 */
.tami__button {
	align-items: center;
	background: var(--tami-color-accent, var(--tami-accent-raw, var(--tami-accent-ink)));
	border: 1px solid transparent;
	border-radius: var(--tami-radius-pill);
	color: var(--tami-color-accent-contrast, #1a1a1a);
	cursor: pointer;
	display: inline-flex;
	font-family: inherit;
	font-size: 0.9375rem;
	font-weight: 700;
	justify-content: center;
	line-height: 1.2;
	min-block-size: 44px;
	padding-block: 0.65em;
	padding-inline: 1.5em;
	text-decoration: none;
	transition: transform var(--tami-dur) var(--tami-ease), box-shadow var(--tami-dur) var(--tami-ease), filter var(--tami-dur) var(--tami-ease);
}

.tami__button:hover,
.tami__button:focus-visible {
	box-shadow: var(--tami-elev-rest);
	/* Keep the label colour the accent was matched against — only deepen the
	   fill slightly, so hover never flips the pairing back out of contrast. */
	color: var(--tami-color-accent-contrast, #1a1a1a);
	filter: brightness(0.94);
	text-decoration: none;
	transform: translateY(-1px);
}

.tami__button--secondary {
	background: transparent;
	border-color: var(--tami-line);
	color: var(--tami-accent-ink);
}

.tami__button--secondary:hover,
.tami__button--secondary:focus-visible {
	background: var(--tami-wash);
	border-color: var(--tami-accent-raw);
	color: var(--tami-accent-ink);
	filter: none;
}

.tami__section-more,
.tami__story-read,
.tami__ministry-link,
.tami__single-back,
.tami__filters-reset {
	color: var(--tami-accent-ink);
	font-weight: 700;
	text-decoration: none;
}

.tami__section-more:hover,
.tami__story-read:hover,
.tami__ministry-link:hover,
.tami__single-back:hover,
.tami__filters-reset:hover {
	text-decoration: underline;
	text-underline-offset: 0.2em;
}

/* Breathing room between a link's label and its directional glyph. */
.tami__section-more .tami__icon--directional,
.tami__story-read .tami__icon--directional,
.tami__ministry-link .tami__icon--directional,
.tami__card-cta .tami__icon--directional,
.tami__view-all .tami__icon--directional {
	display: inline-block;
	margin-inline-start: 0.35em;
}

.tami__single-back .tami__icon--directional {
	display: inline-block;
	margin-inline-end: 0.35em;
	margin-inline-start: 0;
}

/* --- legacy hero sidebar / featured list ------------------------------- */

.tami__hero-layout {
	display: grid;
	gap: var(--tami-space-row, 2rem);
	grid-template-columns: minmax(0, 1fr);
}

/* xl (1024px) — same reasoning as §13: the featured rail only earns its
   place beside the hero copy once both can be read at once. */
@media (min-width: 64rem) {
	.tami__hero-layout {
		align-items: start;
		grid-template-columns: minmax(0, 1fr) minmax(0, 340px);
	}
}

.tami__hero-description {
	color: rgba(255, 255, 255, 0.92);
	font-size: 1.125rem;
	margin-block: var(--tami-step-3) 0;
	max-inline-size: 62ch;
}

.tami__featured {
	background: rgba(255, 255, 255, 0.08);
	border: 1px solid rgba(255, 255, 255, 0.22);
	border-radius: var(--tami-radius-card);
	padding: var(--tami-step-3);
}

.tami__featured-heading {
	border-block-end: 2px solid var(--tami-accent-raw);
	color: #ffffff;
	font-family: var(--tami-font-heading, inherit);
	font-size: 0.8125rem;
	letter-spacing: 0.1em;
	margin-block: 0 var(--tami-step-2);
	padding-block-end: var(--tami-step-1);
	text-transform: uppercase;
}

.tami__featured-list {
	display: grid;
	gap: var(--tami-step-1);
	list-style: none;
	margin-block: 0;
	padding-inline-start: 0;
}

.tami__featured-item {
	margin-block: 0;
}

.tami__featured-link {
	align-items: center;
	border-radius: var(--tami-radius-control);
	color: inherit;
	display: flex;
	gap: var(--tami-step-2);
	min-block-size: 44px;
	padding: var(--tami-step-1);
	text-decoration: none;
	transition: background-color var(--tami-dur) var(--tami-ease);
}

.tami__featured-link:hover,
.tami__featured-link:focus-visible {
	background: rgba(255, 255, 255, 0.14);
}

.tami__featured-thumb {
	block-size: 64px;
	border-radius: var(--tami-radius-control);
	flex: 0 0 auto;
	inline-size: 64px;
	object-fit: cover;
}

.tami__featured-thumb--empty {
	background: rgba(255, 255, 255, 0.2);
	display: inline-block;
}

.tami__featured-text {
	display: block;
	min-inline-size: 0;
}

.tami__featured-title {
	color: #ffffff;
	display: block;
	font-weight: 600;
	line-height: 1.35;
}

.tami__featured-date {
	color: rgba(255, 255, 255, 0.72);
	display: block;
	font-size: 0.8125rem;
	margin-block-start: 0.15em;
}

/* --- legacy dashboard cards (superseded by .tami__stat-card) --------- */

.tami__dashboard {
	margin-block-start: var(--tami-space-section, 4rem);
}

.tami__dashboard-heading,
.tami__gallery-heading,
.tami__documents-heading,
.tami__contact-heading,
.tami__section-heading {
	color: var(--tami-ink);
	font-family: var(--tami-font-heading, inherit);
	font-size: var(--tami-size-h3, 1.375rem);
	font-weight: var(--tami-weight-heading, 700);
	margin-block: 0 var(--tami-space-row, 2rem);
}

.tami__dashboard-list {
	display: grid;
	gap: var(--tami-space-col, 1.5rem);
	grid-template-columns: repeat(auto-fit, minmax(min(100%, 200px), 1fr));
	list-style: none;
	margin-block: 0;
	padding-inline-start: 0;
}

.tami__dashboard-card {
	background: var(--tami-surface);
	border: 1px solid var(--tami-line);
	border-radius: var(--tami-radius-card);
	box-shadow: var(--tami-elev-rest);
	display: grid;
	gap: 0.25rem;
	justify-items: center;
	margin-block: 0;
	min-block-size: 120px;
	padding-block: var(--tami-space-col, 1.5rem);
	padding-inline: var(--tami-step-3);
	text-align: center;
	transition: box-shadow var(--tami-dur) var(--tami-ease), transform var(--tami-dur) var(--tami-ease);
}

.tami__dashboard-card:hover {
	box-shadow: var(--tami-elev-raise);
	transform: translateY(-3px);
}

.tami__dashboard-icon,
.tami__empty-icon {
	color: var(--tami-accent-ink);
	display: inline-flex;
}

.tami__dashboard-number {
	color: var(--tami-ink);
	font-family: var(--tami-font-heading, inherit);
	font-size: 2.25rem;
	font-variant-numeric: tabular-nums;
	font-weight: 800;
	letter-spacing: -0.03em;
	line-height: 1;
}

.tami__dashboard-label {
	color: var(--tami-muted-ink);
	font-size: 0.75rem;
	font-weight: 600;
	letter-spacing: 0.1em;
	text-transform: uppercase;
}

/* --- legacy filters ----------------------------------------------------- */

.tami__filters {
	margin-block-end: var(--tami-space-row, 2rem);
}

.tami__filters-fieldset {
	align-items: end;
	border: 1px solid var(--tami-line);
	border-radius: var(--tami-radius-card);
	display: flex;
	flex-wrap: wrap;
	gap: var(--tami-step-3);
	margin-inline: 0;
	padding-block: var(--tami-step-3);
	padding-inline: var(--tami-step-3);
}

.tami__filters-field {
	display: grid;
	/* Grows to share the row on a laptop, wraps to its own full-width row on a
	   phone. The `min(100%, …)` basis is what makes the second half true: a
	   flat 12rem basis on a 288px column would refuse to shrink and push the
	   fieldset — and with it the page — past the viewport. */
	flex: 1 1 min(100%, 12rem);
	gap: 0.3rem;
	min-inline-size: 0;
}

.tami__filters-label {
	color: var(--tami-muted-ink);
	font-size: 0.75rem;
	font-weight: 600;
	letter-spacing: 0.07em;
	text-transform: uppercase;
}

/*
 * FORM CONTROLS — the 16px rule, and why it is not negotiable.
 *
 * If a focused field's computed font-size is below 16px, iOS Safari zooms the
 * viewport in to meet it. It never zooms back out. The visitor is left on a
 * page that is wider than the screen, scrolled sideways, with the rest of the
 * form off to one side — the single most reported "the site is broken on my
 * iPhone" complaint there is, and it is caused by one declaration.
 *
 * So: 1rem everywhere by default, and the denser 15px control only where the
 * viewport is at least tablet-portrait wide AND the pointer is fine — i.e. a
 * mouse or trackpad, which never triggers focus zoom. Gating on the pointer
 * rather than on width alone is the §0 rule 4 principle: an iPad Pro in
 * landscape is 1366px wide and is still a touch device.
 */
.tami__filters-select,
.tami__select,
.tami__input,
.tami__textarea {
	background: var(--tami-surface);
	border: 1px solid var(--tami-line);
	border-radius: var(--tami-radius-control);
	color: var(--tami-body-ink);
	font-family: inherit;
	font-size: 1rem;
	max-inline-size: 100%;
	min-block-size: 44px;
	min-inline-size: 0;
	padding-block: 0.5em;
	padding-inline: 0.7em;
}

/*
 * The 15px desktop densification that used to live here is GONE, deliberately.
 *
 * It never applied to three of its four selectors. The Divi-beating pass later
 * in this file declares `.tami .tami__input` (specificity 0,2,0) with
 * `font-size: max(1rem, 16px)`, which outranks a bare `.tami__input` (0,1,0)
 * AND comes later in the sheet. Only `.tami__filters-select` — absent from
 * that block — actually densified, so a filter dropdown rendered at 15px beside
 * a 16px text input in the same row.
 *
 * Raising this rule's specificity to match would have "fixed" it by shrinking
 * three controls that have been 16px since launch. Making the fourth match the
 * other three is the smaller, safer change: it removes the mismatch, and it
 * keeps every control on the iOS 16px focus-zoom floor rather than relying on
 * `pointer: fine` to be right about whether a device can zoom.
 */

.tami__textarea {
	min-block-size: 8rem;
}

/* --- legacy story / ministry cards ------------------------------------- */

.tami__stories-grid,
.tami__ministries-grid,
.tami__gallery-list {
	display: grid;
	gap: var(--tami-space-row, 2rem) var(--tami-space-col, 1.5rem);
	grid-template-columns: minmax(0, 1fr);
	list-style: none;
	margin-block: 0;
	padding-inline-start: 0;
}

/* md (640px) / xl (1024px) — the legacy grids step on exactly the same two
   points as .tami__grid--3 (§7), so a page that mixes old and new markup
   still reflows as one thing rather than at four different widths. */
@media (min-width: 40rem) {
	.tami__stories-grid,
	.tami__ministries-grid,
	.tami__gallery-list {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

@media (min-width: 64rem) {
	.tami__stories-grid,
	.tami__ministries-grid {
		grid-template-columns: repeat(3, minmax(0, 1fr));
	}
}

.tami__stories-item,
.tami__ministries-item,
.tami__gallery-item {
	display: grid;
	margin-block: 0;
	min-inline-size: 0;
}

.tami__story-card,
.tami__ministry-card {
	background: var(--tami-surface);
	block-size: 100%;
	border: 1px solid var(--tami-line);
	border-radius: var(--tami-radius-card);
	box-shadow: var(--tami-elev-rest);
	display: flex;
	flex-direction: column;
	overflow: hidden;
	transition: transform var(--tami-dur) var(--tami-ease), box-shadow var(--tami-dur) var(--tami-ease), border-color var(--tami-dur) var(--tami-ease);
}

.tami__ministry-card {
	gap: 0.75rem;
	padding: var(--tami-space-col, 1.5rem);
}

.tami__story-card:hover,
.tami__story-card:focus-within,
.tami__ministry-card:hover,
.tami__ministry-card:focus-within {
	border-color: var(--tami-accent-raw);
	box-shadow: var(--tami-elev-raise);
	transform: translateY(-4px);
}

.tami__story-media {
	display: block;
	line-height: 0;
	overflow: hidden;
}

.tami__story-thumb {
	aspect-ratio: 16 / 10;
	block-size: auto;
	inline-size: 100%;
	max-inline-size: 100%;
	object-fit: cover;
	transition: transform 420ms var(--tami-ease);
}

.tami__story-card:hover .tami__story-thumb {
	transform: scale(1.045);
}

.tami__story-body {
	display: flex;
	flex: 1 1 auto;
	flex-direction: column;
	gap: var(--tami-step-2);
	padding: var(--tami-space-col, 1.5rem);
}

.tami__story-title,
.tami__ministry-name {
	color: var(--tami-ink);
	font-family: var(--tami-font-heading, inherit);
	font-size: var(--tami-size-h3, 1.1875rem);
	font-weight: var(--tami-weight-heading, 700);
	line-height: 1.3;
	margin-block: 0;
}

.tami__story-title a,
.tami__ministry-name a {
	color: inherit;
	text-decoration: none;
	transition: color var(--tami-dur) var(--tami-ease);
}

.tami__story-card:hover .tami__story-title a,
.tami__ministry-card:hover .tami__ministry-name a,
.tami__story-title a:hover,
.tami__ministry-name a:hover {
	color: var(--tami-accent-ink);
	text-decoration: underline;
	text-underline-offset: 0.16em;
}

.tami__story-meta,
.tami__story-date,
.tami__ministry-country,
.tami__ministry-count {
	color: var(--tami-muted-ink);
	font-size: 0.8125rem;
	margin-block: 0;
}

.tami__story-excerpt,
.tami__ministry-excerpt {
	color: var(--tami-body-ink);
	font-size: 0.9375rem;
	line-height: 1.6;
	margin-block: 0;
}

.tami__story-foot,
.tami__ministry-foot {
	align-items: center;
	display: flex;
	flex-wrap: wrap;
	gap: var(--tami-step-2);
	justify-content: space-between;
	margin-block: auto 0;
	padding-block-start: var(--tami-step-2);
}

.tami__ministry-foot {
	border-block-start: 1px solid var(--tami-line);
	padding-block-start: 0.75rem;
}

.tami__ministry-head {
	align-items: center;
	display: flex;
	gap: var(--tami-step-2);
}

.tami__ministry-logo {
	block-size: 56px;
	border-radius: 50%;
	box-shadow: 0 0 0 1px var(--tami-line);
	flex: 0 0 auto;
	inline-size: 56px;
	object-fit: cover;
}

.tami__ministry-logo--empty {
	align-items: center;
	background: var(--tami-accent-raw);
	color: #10240a;
	display: inline-flex;
	font-size: 1.375rem;
	font-weight: 800;
	justify-content: center;
}

/* --- legacy single layouts --------------------------------------------- */

.tami__single-header {
	background: var(--tami-surface);
	border: 1px solid var(--tami-line);
	border-inline-start: 4px solid var(--tami-accent-raw);
	border-radius: var(--tami-radius-card);
	margin-block-end: var(--tami-space-row, 2rem);
	padding-block: var(--tami-step-3);
	padding-inline: var(--tami-step-4);
}

.tami__single-meta {
	display: flex;
	flex-wrap: wrap;
	gap: var(--tami-step-3) var(--tami-space-row, 2rem);
	list-style: none;
	margin-block: 0;
	padding-inline-start: 0;
}

.tami__single-meta-item {
	display: grid;
	gap: 0.1rem;
	margin-block: 0;
}

.tami__single-meta-label,
.tami__contact-label {
	color: var(--tami-muted-ink);
	font-size: 0.6875rem;
	font-weight: 700;
	letter-spacing: 0.09em;
	text-transform: uppercase;
}

.tami__single-meta-value {
	color: var(--tami-ink);
	font-weight: 600;
}

.tami__single-meta-value a,
.tami__contact-value a {
	color: var(--tami-accent-ink);
	text-decoration: none;
}

.tami__single-meta-value a:hover,
.tami__contact-value a:hover {
	text-decoration: underline;
	text-underline-offset: 0.2em;
}

.tami__single-content {
	max-inline-size: 72ch;
}

.tami__single-footer {
	border-block-start: 1px solid var(--tami-line);
	margin-block-start: var(--tami-space-section, 4rem);
	padding-block-start: var(--tami-step-3);
}

.tami__gallery {
	margin-block-start: var(--tami-space-section, 4rem);
}

/*
 * Documents, beneath "Photos & Video".
 *
 * Same section rhythm as the gallery above it, so the two read as siblings
 * rather than one crowding the other.
 *
 * `list-style: none` is load-bearing, not tidiness: these <li>s each hold a
 * BUTTON, and a browser's default marker put a bullet directly to the left
 * of it, which reads as a list of links rather than a row of download
 * actions. The gallery list opts out for the same reason a few rules up;
 * this list simply never did.
 */
.tami__documents {
	margin-block-start: var(--tami-space-section, 4rem);
}

/*
 * SPECIFICITY IS THE POINT HERE, not decoration.
 *
 * A bare `.tami__documents-list` (0,1,0) loses to the theme: Divi ships
 * `#left-area ul, .entry-content ul, .et-l--body ul { list-style: disc }`
 * at (0,1,1), in an inline stylesheet that also comes later in the document.
 * So the list kept its bullets AND a 16px marker indent from Divi's padding,
 * which is exactly the dot beside the download button that this was supposed
 * to remove.
 *
 * Scoping each selector under `.tami` lifts it to (0,2,0), which beats that
 * without resorting to !important. `list-style` is set on the ITEM as well as
 * the list because the theme targets `ul` and `li` separately, and inheriting
 * from a list that has been overridden inherits the override.
 */
/*
 * AN ID SELECTOR IS THE ONE THING CLASSES CANNOT OUTWEIGH.
 *
 * Divi ships, in an inline stylesheet:
 *
 *   #left-area ul, .entry-content ul, .et-l--body ul { padding: 0 0 23px 1em; list-style: disc }
 *
 * `#left-area ul` is (1,0,1) and our lists sit inside #left-area, so no
 * amount of class nesting on our side wins -- our own `padding-inline-start:
 * 0` was being discarded, leaving both lists indented 1em from their own
 * headings and carrying 23px of padding underneath. That 1em is the gap the
 * bullet used to sit in, so it read as leftover marker space even after the
 * marker was gone.
 *
 * !important is the correct tool here rather than a lazy one: the alternative
 * is hardcoding #left-area into this stylesheet, which would bind the plugin
 * to one theme's DOM. Scoped to two of our own classes and three properties,
 * so it cannot leak into anything else.
 */
/*
 * The native media player. Replaces core's wp_video_shortcode markup, which
 * could never work here -- see RegionPage::player_html() on why a URL with no
 * file extension defeats it. Sized like the gallery images beside it so a
 * video and a photo in the same grid do not fight over the row height.
 */
.tami .tami__player {
	block-size: auto;
	border-radius: var(--tami-radius-card);
	display: block;
	inline-size: 100%;
	max-inline-size: 100%;
}

.tami .tami__player--audio {
	block-size: 54px;
}

.tami .tami__player-fallback {
	font-size: 0.875em;
	margin: 0.5em 0 0;
}

.tami .tami__gallery-list,
.tami .tami__documents-list {
	list-style: none !important;
	padding-inline-start: 0 !important;
	padding-block-end: 0 !important;
}

.tami .tami__documents-list {

	display: flex;
	flex-wrap: wrap;
	gap: var(--tami-space-col, 1.5rem);
	list-style: none;
	margin-block: 0;
	padding-inline-start: 0;
}

.tami .tami__documents-item {
	list-style: none;
	margin: 0;
	padding-inline-start: 0;
}

/*
 * Belt and braces for engines that still lay out a marker box after
 * list-style-type: none. Safe where ::marker is unsupported: the rule is
 * simply dropped.
 */
.tami .tami__documents-item::marker {
	content: "";
}

/* The button owns its own spacing; the parts inside it sit on one line. */
.tami .tami__doc-link {
	align-items: baseline;
	display: inline-flex;
	flex-wrap: wrap;
	gap: 0.5em;
	text-align: start;
}

.tami .tami__doc-meta {
	font-size: 0.875em;
	opacity: 0.75;
}

.tami__gallery-item img,
.tami__gallery-item video {
	block-size: auto;
	border-radius: var(--tami-radius-card);
	inline-size: 100%;
	max-inline-size: 100%;
}

.tami__contact {
	background: var(--tami-surface);
	border: 1px solid var(--tami-line);
	border-radius: var(--tami-radius-card);
	box-shadow: var(--tami-elev-rest);
	margin-block-start: var(--tami-space-section, 4rem);
	padding: var(--tami-step-4);
}

.tami__contact-list {
	display: grid;
	gap: var(--tami-step-2);
	list-style: none;
	margin-block: 0;
	padding-inline-start: 0;
}

.tami__contact-item {
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem;
	margin-block: 0;
}

.tami__contact-label {
	flex: 0 0 auto;
	min-inline-size: 5.5rem;
}

.tami__contact-value {
	min-inline-size: 0;
	overflow-wrap: anywhere;
}

/* --- legacy pagination list -------------------------------------------- */

.tami__pagination-list {
	display: flex;
	flex-wrap: wrap;
	gap: var(--tami-step-2);
	justify-content: center;
	list-style: none;
	margin-block: 0;
	padding-inline-start: 0;
}

.tami__pagination-item {
	margin-block: 0;
}

.tami__pagination-link {
	align-items: center;
	border: 1px solid var(--tami-line);
	border-radius: var(--tami-radius-control);
	color: var(--tami-accent-ink);
	display: inline-flex;
	font-variant-numeric: tabular-nums;
	font-weight: 600;
	justify-content: center;
	min-block-size: 44px;
	min-inline-size: 44px;
	padding-inline: 0.85em;
	text-decoration: none;
	transition: background-color var(--tami-dur) var(--tami-ease), border-color var(--tami-dur) var(--tami-ease);
}

.tami__pagination-link:hover,
.tami__pagination-link:focus-visible {
	background: var(--tami-wash);
	border-color: var(--tami-accent-raw);
}

.tami__pagination-link--current {
	background: var(--tami-accent-ink);
	border-color: var(--tami-accent-ink);
	color: #ffffff;
	font-weight: 800;
}

.tami__pagination-gap {
	align-items: center;
	color: var(--tami-muted-ink);
	display: inline-flex;
	min-block-size: 44px;
	padding-inline: 0.3em;
}

/* --- legacy empty state ------------------------------------------------- */

.tami__empty-state {
	background: var(--tami-surface);
	border: 1px dashed var(--tami-line);
	border-radius: var(--tami-radius-card);
	display: grid;
	gap: 0.4rem;
	justify-items: center;
	padding-block: clamp(2.5rem, 6vw, 4rem);
	padding-inline: var(--tami-step-4);
	text-align: center;
}

.tami__empty-title {
	color: var(--tami-ink);
	font-family: var(--tami-font-heading, inherit);
	font-size: 1.25rem;
	margin-block: 0;
}

.tami__empty-message {
	color: var(--tami-muted-ink);
	margin-block: 0;
	max-inline-size: 46ch;
}

.tami__empty-actions {
	margin-block: var(--tami-step-3) 0;
}

/* -------------------------------------------------------------------------
 * 15. FOCUS VISIBILITY
 *
 * WCAG 2.1 SC 1.4.11 wants a focus indicator at 3:1 against its surroundings.
 * The base sheet's ring uses the raw accent, which is only ~2:1 on white, so
 * it is upgraded here to the darkened ink colour and thickened to 3px.
 * ------------------------------------------------------------------------- */

.tami a:focus-visible,
.tami button:focus-visible,
.tami input:focus-visible,
.tami select:focus-visible,
.tami textarea:focus-visible,
.tami [tabindex]:focus-visible {
	outline: 3px solid var(--tami-accent-ink);
	outline-offset: 3px;
}

/*
 * On the hero the ring sits on a dark photographic scrim, where the ink green
 * drops to roughly 1.4:1 and effectively vanishes. White is ~12:1 there.
 * These selectors carry the same specificity as the block above and come
 * later in the source, so they win inside the hero and nowhere else.
 */
.tami__hero a:focus-visible,
.tami__hero button:focus-visible,
.tami__hero input:focus-visible,
.tami__hero select:focus-visible,
.tami__hero [tabindex]:focus-visible {
	outline: 3px solid #ffffff;
	outline-offset: 3px;
}

/* -------------------------------------------------------------------------
 * 16. REDUCED MOTION
 *
 * The base sheet already collapses transition durations. This goes further and
 * removes the movement itself: no lift, no image zoom, no sliding arrows. The
 * underline states stay — they are meaning, not decoration — they simply
 * appear instantly.
 * ------------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
	.tami__card:hover,
	.tami__card:focus-within,
	.tami__stat-card:hover,
	.tami__stat-card:focus-visible,
	.tami__story-card:hover,
	.tami__story-card:focus-within,
	.tami__ministry-card:hover,
	.tami__ministry-card:focus-within,
	.tami__dashboard-card:hover,
	.tami__button:hover,
	.tami__button:focus-visible,
	.tami__hero-cta:hover,
	.tami__hero-cta:focus-visible,
	.tami__view-all:hover,
	.tami__view-all:focus-visible,
	.tami__leader:hover .tami__leader-photo {
		transform: none;
	}

	.tami__card:hover .tami__card-media img,
	.tami__card:focus-within .tami__card-media img,
	.tami__story-card:hover .tami__story-thumb,
	.tami__card:hover .tami__card-cta .tami__icon--directional,
	.tami__view-all:hover .tami__icon--directional {
		transform: none;
	}

	/* The accent bars still change state, they just do not travel. */
	.tami__section-head:hover .tami__section-title::after,
	.tami__section-title:hover::after {
		transform: scaleX(1.6);
	}
}

/* =========================================================================
 * 17. THEME TITLE SUPPRESSION — THE ONE SANCTIONED OUT-OF-SCOPE RULE
 * =========================================================================
 *
 * READ THIS BEFORE TOUCHING THE BLOCK BELOW.
 *
 * WHY IT EXISTS
 * Plugin pages render their own <h1> inside the hero (.tami__hero-title),
 * because the hero — breadcrumbs, region title, blurb, CTA — is the page's
 * identity and it must sit at the very top of the content. The host theme
 * (Divi, plus its Theme Builder header layout) ALSO prints the WordPress page
 * title immediately above the content area. Left alone, every region, ministry
 * and story page shows the title twice: once in the theme's small grey type
 * and again, correctly, in the hero. There is no theme setting that removes it
 * per page, and CONTRACTS.md forbids us from taking over the page template, so
 * the only remaining lever is CSS.
 *
 * WHY IT IS SAFE
 * CONTRACTS-V2 §8.1 sanctions exactly this one exception. Agent E adds the
 * body class `tami-page` (via the body_class filter) ONLY on pages this
 * plugin owns, so every selector below is gated on our own pages. Off those
 * pages not one declaration applies.
 *
 * WHY EACH SELECTOR IS SHAPED THE WAY IT IS
 * Every selector targets an h1 specifically, or a direct child of a known
 * theme title wrapper. That matters: a Divi Blog module dropped onto one of
 * our pages renders its post titles as h2.entry-title, and a looser selector
 * would blank them out. Our own markup never carries .entry-title/.page-title
 * and never sits inside .entry-header/.et_pb_title_container, so this cannot
 * reach into .tami.
 *
 * !important is required because Divi's own stylesheet sets display on these
 * elements from a higher-specificity, later-loading rule
 * (#main-content .container .et_pb_title_container h1 and friends).
 *
 * RULES FOR FUTURE EDITS
 *  - NEVER widen this beyond `body.tami-page`.
 *  - NEVER drop the h1 / direct-child qualifiers.
 *  - NEVER add a rule here for anything other than suppressing a duplicated
 *    page title or a duplicated featured image (the block just below). Any
 *    other cross-scope styling is a contract violation.
 * ========================================================================= */

body.tami-page h1.entry-title,
body.tami-page h1.page-title,
body.tami-page .entry-header > h1,
body.tami-page .page-header > h1,
body.tami-page .et_post_meta_wrapper > h1,
body.tami-page .et_pb_title_container > h1,
body.tami-page .et_pb_title_container > .entry-title {
	/* countering Divi's #main-content .et_pb_title_container h1 */
	display: none !important;
}

/*
 * The same duplication, for the FEATURED IMAGE.
 *
 * Divi's single.php prints the post thumbnail inside .et_post_meta_wrapper,
 * directly under the title it prints there, whenever "Show featured image
 * on single posts" is on — which is the theme default. Our ministry and
 * story singles now show that very image whole, in the hero's banner
 * (§30.1), so the theme's copy sat immediately above ours and every single
 * opened with the photograph twice. While the hero used the image as a
 * darkened cover background the two read as different things; as a banner
 * they are visibly the same file, one above the other.
 *
 * Same gate, same shape, same reasons as the title rule: our own body class
 * only, a direct child of the one theme wrapper that prints it, and nothing
 * that could reach an image inside .tami or a Blog module's thumbnails
 * (those render inside .et_pb_post .entry-featured-image-url, not as a
 * direct child of .et_post_meta_wrapper).
 */
body.tami-page .et_post_meta_wrapper > img {
	/* countering Divi's single.php featured-image print */
	display: none !important;
}

/* =========================================================================
 * 20. CLIENT REVISIONS (v0.3.1)
 *
 * Changes requested after reviewing v0.3.0 on the live local site. Kept in one
 * clearly-labelled block so the reasoning survives, rather than being smeared
 * back through the sections above.
 * ========================================================================= */

/* -------------------------------------------------------------------------
 * 20.1  "At a Glance" as a GRID, not boxes.
 *
 * The stat cards were individually boxed — surface fill, border, shadow, and
 * a lift on hover — which made the section read as six separate objects. The
 * client asked for a grid. So: one shared surface, hairline dividers between
 * cells, no per-card box. The cells are still <a> elements and still have to
 * announce themselves as clickable, so the affordance moves from "card lifts"
 * to "cell tints and its number takes the accent".
 * ------------------------------------------------------------------------- */

.tami__stat-grid {
	background: var(--tami-surface);
	border: 1px solid var(--tami-line);
	border-radius: 10px;
	box-shadow: var(--tami-elev-rest);
	/*
	 * 2 → 3 → 6. Six cells, and the count only ever divides six evenly, so
	 * there is never a short final row.
	 *
	 * NEVER ONE. A single column of six 132px cells is 800px of scrolling for
	 * six numbers — the "At a Glance" section would stop being a glance. Two
	 * columns hold at 320px because §9 sizes the cell for exactly that case.
	 *
	 * Hard counts rather than auto-fit: auto-fit with a 9rem minimum resolves
	 * to four or five columns through the middle of the range, which leaves an
	 * orphan row of one or two and breaks the block into an obviously
	 * accidental shape.
	 */
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	/* The 1px gap lets the grid's own background show through as dividers,
	   which is why the cells below paint their own background. */
	gap: 1px;
	overflow: hidden;
}

/* md (640px) — three across, two rows. */
@media (min-width: 40rem) {
	.tami__stat-grid {
		grid-template-columns: repeat(3, minmax(0, 1fr));
	}
}

/*
 * xxl (1280px) — all six in one row.
 *
 * Not at xl (1024px). Measured on the live Divi build — where the plugin sits
 * inside the theme's own container, so the shell is narrower than the
 * viewport — six cells at 1024px are about 117px each, which leaves 85px of
 * content and clips nothing only because §9's label cap wraps it. At 1280px
 * they are ~134px, which holds "CONTRIBUTORS" (98px) on one line with room
 * for the longer translations of the other five labels.
 */
@media (min-width: 80rem) {
	.tami__stat-grid {
		grid-template-columns: repeat(6, minmax(0, 1fr));
	}
}

.tami__stat-grid .tami__stat-card {
	background: var(--tami-surface);
	border: 0;
	border-radius: 0;
	box-shadow: none;
	/* Paints the 1px grid gap, forming the divider lines. */
	outline: 1px solid var(--tami-line);
	outline-offset: 0;
	transform: none;
}

.tami__stat-grid .tami__stat-card::after {
	/* The bottom accent stub belonged to the boxed treatment. */
	content: none;
}

.tami__stat-grid .tami__stat-card:hover,
.tami__stat-grid .tami__stat-card:focus-visible {
	background: var(--tami-wash);
	box-shadow: none;
	/* No lift: a cell that rises out of a grid tears the divider lines. */
	transform: none;
}

/* Focus must still be unmistakable even though the lift is gone. */
.tami__stat-grid .tami__stat-card:focus-visible {
	outline: 3px solid var(--tami-accent-ink);
	outline-offset: -3px;
}

/* -------------------------------------------------------------------------
 * 20.2  Image treatment: 10px radius + shadow on every plugin image.
 *
 * Applied to the images themselves rather than their wrappers, so the corners
 * are actually rounded on the pixels. Logos and leader portraits keep their
 * own shapes (a circular portrait must not become a rounded square), so they
 * are excluded and handled just below.
 * ------------------------------------------------------------------------- */

.tami img:not(.tami__logo-image):not(.tami__leader-image),
.tami__card-media img,
.tami__card-image,
.tami__single img,
.tami__prose img {
	border-radius: 10px;
	box-shadow: var(--tami-elev-rest);
}

/* The card's media box clips the image, so IT carries the radius too —
   otherwise the clip squares off the corners the image just rounded. */
.tami__card-media {
	border-radius: 10px;
	overflow: hidden;
}

/* The ministry logo is a square brand mark: same radius and shadow, but it
   must not inherit any card cropping. */
.tami__logo-image {
	border-radius: 10px;
	box-shadow: var(--tami-elev-rest);
}

/* -------------------------------------------------------------------------
 * 20.3  Breadcrumb colours are admin-controllable.
 *
 * Falls back to the previous inherited values when the settings are blank, so
 * an untouched site looks exactly as before.
 * ------------------------------------------------------------------------- */

.tami__breadcrumbs a,
.tami__breadcrumb-item a {
	color: var(--tami-color-breadcrumb, currentColor);
}

.tami__breadcrumb-current,
.tami__breadcrumbs [aria-current="page"] {
	color: var(--tami-color-breadcrumb-current, var(--tami-color-breadcrumb, currentColor));
}

.tami__breadcrumb-sep {
	color: var(--tami-color-breadcrumb, currentColor);
	opacity: 0.6;
}

/* -------------------------------------------------------------------------
 * 20.4  Suppress the THEME's sidebar on plugin views.
 *
 * Second sanctioned out-of-scope rule, and the same reasoning as the title
 * suppression above: the sidebar is printed by Divi, not by us, so no rule
 * inside .tami can reach it. A ministry set to "no sidebar" was still
 * getting Divi's, because a CPT single inherits the theme's default layout.
 *
 * RegionPage already swaps the body classes so Divi lays the content out full
 * width; this removes the element itself. Both are scoped to
 * body.tami-page and must never be widened.
 * ------------------------------------------------------------------------- */

body.tami-page #sidebar,
body.tami-page #main-content .container:not(.et_pb_row)::after {
	display: none !important; /* countering Divi's own #sidebar layout */
}

body.tami-page #left-area {
	float: none !important; /* countering Divi's sidebar float */
	inline-size: 100% !important;
	padding-inline-end: 0 !important;
	width: 100% !important;
}

/* =========================================================================
 * 21. DEVICE CLASS — TOUCH, POINTER AND VIEWPORT SHAPE
 * =========================================================================
 *
 * Everything above this line answers to WIDTH. Nothing below it does.
 *
 * These are the queries that make the difference between a layout that merely
 * fits a phone and a page that behaves like an app on one: a target big
 * enough for a thumb, a hover state that does not stick after a tap, a hero
 * that does not swallow a landscape screen, and text that clears the notch.
 * They are deliberately last so they win over the component rules they
 * correct, and they are keyed on capability rather than size because a 1366px
 * iPad Pro and a 1280px touchscreen laptop are both touch devices.
 * ========================================================================= */

/* -------------------------------------------------------------------------
 * 21.1  Tap delay and press feedback — every pointer, no query needed.
 * ------------------------------------------------------------------------- */

/*
 * `manipulation` tells the browser this element will never be double-tapped
 * to zoom, so it can dispatch the click immediately instead of waiting ~300ms
 * to find out. Panning and pinch-zoom are untouched — `touch-action: none`
 * would break both and is an accessibility failure.
 */
.tami a,
.tami button,
.tami summary,
.tami [role="button"] {
	touch-action: manipulation;
}

/* -------------------------------------------------------------------------
 * 21.2  Coarse pointers — 44×44 CSS px minimum (WCAG 2.5.5).
 *
 * A fingertip contact patch is about 9mm, roughly 44px at typical phone
 * densities. Applied only where the pointer is coarse: forcing 44px rows on a
 * mouse-driven page would just make the design loose for no benefit.
 *
 * Inline links inside a sentence — .tami__prose a, .tami__card-meta a —
 * are deliberately NOT inflated. WCAG exempts targets whose size is
 * constrained by the line height of the text they sit in, and stretching them
 * would tear the paragraph apart to no one's advantage.
 * ------------------------------------------------------------------------- */

@media (pointer: coarse) {
	.tami__breadcrumb-item,
	.tami__breadcrumb-current {
		min-block-size: 44px;
	}

	/* These are stand-alone actions rendered as bare links, so they have no
	   box of their own to grow: inline-flex gives them one. */
	.tami__section-more,
	.tami__story-read,
	.tami__ministry-link,
	.tami__single-back,
	.tami__filters-reset {
		align-items: center;
		display: inline-flex;
		min-block-size: 44px;
	}

	/* Separation is the other half of WCAG 2.5.8: adjacent targets need space
	   between them, or the right one is a coin toss. */
	.tami__pagination,
	.tami__pagination-list,
	.tami__section-actions,
	.tami__cell--actions {
		gap: var(--tami-step-3);
	}

	.tami__featured-link {
		padding-block: var(--tami-step-2);
	}
}

/* -------------------------------------------------------------------------
 * 21.3  Touch — hover is not a state here.
 *
 * Mobile Safari and Android Chrome apply :hover to the last element tapped
 * and hold it there until something else is tapped. Every hover-only
 * affordance in this sheet therefore "sticks": a card stays lifted, a
 * photograph stays zoomed, an arrow stays slid over. Worse, the lift fires
 * DURING the tap, so the thing under the finger moves.
 *
 * So on hover-less pointers every hover transform is neutralised, and the
 * press feedback is moved to :active, which on touch is exactly as long as
 * the finger is down. :focus-within and :focus-visible are untouched — a
 * Bluetooth keyboard on an iPad still needs them.
 * ------------------------------------------------------------------------- */

@media (hover: none) {
	.tami__card:hover,
	.tami__story-card:hover,
	.tami__ministry-card:hover,
	.tami__dashboard-card:hover,
	.tami__stat-card:hover,
	.tami__button:hover,
	.tami__hero-cta:hover,
	.tami__view-all:hover {
		box-shadow: var(--tami-elev-rest);
		filter: none;
		transform: none;
	}

	.tami__card:hover .tami__card-media img,
	.tami__card:focus-within .tami__card-media img,
	.tami__story-card:hover .tami__story-thumb,
	.tami__card:hover .tami__card-cta .tami__icon--directional,
	.tami__view-all:hover .tami__icon--directional,
	.tami__leader:hover .tami__leader-photo {
		transform: none;
	}

	/* Back to the resting 3rem bar rather than the 2.4× hover extension. */
	.tami__section-head:hover .tami__section-title::after,
	.tami__section-title:hover::after {
		transform: scaleX(1);
	}

	/* Press feedback: instant, unambiguous, and gone the moment the finger
	   lifts. This is what replaces the tap-highlight rectangle suppressed at
	   the root in §1. */
	.tami__card:active,
	.tami__story-card:active,
	.tami__ministry-card:active,
	.tami__stat-card:active,
	.tami__featured-link:active {
		background-color: var(--tami-wash);
	}

	.tami__button:active,
	.tami__hero-cta:active,
	.tami__view-all:active,
	.tami__page-link:active,
	.tami__pagination-link:active {
		filter: brightness(0.92);
	}
}

/* -------------------------------------------------------------------------
 * 21.4  Short landscape — the phone turned sideways.
 *
 * A phone in landscape is roughly 375–430px TALL. The hero's 15rem floor is
 * 240px of that, plus the theme header above it: turn the device and the
 * visitor sees a photograph and nothing else, with no signal that there is a
 * page underneath.
 *
 * This is a viewport SHAPE, not a step on the width scale — a 900×400 window
 * on a laptop has the same problem — so it is the one place in this file that
 * uses a max-* query, and it is keyed on height and orientation rather than
 * width. 30rem (480px) is the tallest landscape phone plus a margin.
 * ------------------------------------------------------------------------- */

@media (orientation: landscape) and (max-height: 30rem) {
	.tami__hero-inner {
		/* Drop the floor entirely: the hero becomes exactly as tall as
		   breadcrumbs + title + description need, which is around 180px. */
		min-block-size: 0;
		padding-block: clamp(0.75rem, 7vh, 2.25rem);
		padding-block: clamp(0.75rem, 7svh, 2.25rem);
	}

	.tami__hero-title {
		font-size: clamp(1.5rem, 1rem + 2.4vw, 2.375rem);
		padding-block-start: var(--tami-step-3);
	}

	.tami__hero-desc,
	.tami__hero-description {
		font-size: 1rem;
		line-height: 1.45;
	}

	.tami__hero-cta,
	.tami__hero-blurb {
		margin-block-start: var(--tami-step-3);
	}

	/* The section gap after the hero is tuned for a tall screen; on a short
	   one it is another screenful of nothing. */
	.tami__hero {
		margin-block-end: var(--tami-space-row, 2rem);
	}
}

/* -------------------------------------------------------------------------
 * 21.5  Apple safe areas in landscape — clearing the notch.
 *
 * In landscape the notch / Dynamic Island sits inside the layout viewport on
 * one inline side and the home indicator along the bottom. §2 covers the
 * phone-width case through --tami-gutter; this covers the case that query
 * cannot reach, namely a landscape phone or tablet wide enough (≥768px) to be
 * using the proportional container, where a page_width_pct of 100 would put
 * the first characters of every line under the cutout.
 *
 * The same max() is applied to both inline sides on purpose: the inset is
 * physical, the layout is logical, and taking the larger of the two keeps the
 * rule identical in Farsi. On any device without insets every env() resolves
 * to 0 and this changes nothing at all; where env() is not supported the
 * declaration is simply invalid and the §2 padding stands.
 * ------------------------------------------------------------------------- */

@media (orientation: landscape) {
	.tami__container,
	.tami__hero-inner {
		padding-inline: max(
			var(--tami-gutter, 0px),
			env(safe-area-inset-left, 0px),
			env(safe-area-inset-right, 0px)
		);
	}

	/* The home indicator overlaps the last ~34px of the page in landscape. */
	.tami {
		padding-block-end: max(
			var(--tami-pad-block-end, 0px),
			env(safe-area-inset-bottom, 0px)
		);
	}
}

/* =========================================================================
 * 22. ULTRA-WIDE — 1920px and beyond
 * =========================================================================
 *
 * The default page_max_width of 1600px is the primary defence here, and the
 * 72ch measure on .tami__prose (§3) is what actually stops long lines: a
 * 1536px column of 11pt text would run to about 190 characters, roughly
 * two and a half times the readable maximum.
 *
 * What the max-width cannot fix is the CARD. Three tracks across a 2000px
 * container are 650px each, which turns a thumbnail into a poster and a
 * three-line excerpt into a lonely strip. So past 1920px the tracks stop
 * growing and the surplus becomes margin. The column COUNT is unchanged —
 * CONTRACTS-V2 §8.9/§8.10 specify a 3×3 block and a fourth column would break
 * it — the tracks simply stop expanding and centre themselves.
 * ========================================================================= */

@media (min-width: 120rem) {
	.tami__grid--3,
	.tami__stories-grid,
	.tami__ministries-grid {
		/* justify-content centres the TRACKS, and it is direction-aware, so
		   the leftover space splits evenly in Farsi too. */
		grid-template-columns: repeat(3, minmax(0, 30rem));
		justify-content: center;
	}

	/* Hero copy is display type; it has to stop somewhere short of the
	   container or the eye cannot find the start of the next line. */
	.tami__hero-desc,
	.tami__hero-blurb,
	.tami__hero-description {
		max-inline-size: 56ch;
	}
}

/* =========================================================================
 * 23. PREFERS-CONTRAST
 * =========================================================================
 *
 * Requested by users with low vision, and by anyone reading a laptop screen
 * in direct sun — which, for a plugin whose contributors are in the field, is
 * not the edge case it sounds like.
 *
 * Only OUR tokens are rewritten (§1 names). The administrator's §5 colour
 * settings are never touched: this raises the contrast of the FURNITURE —
 * hairlines, muted labels, shadows — around whatever palette they chose.
 * ========================================================================= */

@media (prefers-contrast: more) {
	.tami {
		/* A hairline at #e3e6e8 is 1.2:1 on white and effectively invisible. */
		--tami-line: #6b7280;
		/* Muted text stops being muted: the hierarchy is carried by size and
		   weight, which survive, rather than by contrast, which does not. */
		--tami-muted-ink: var(--tami-color-text, #2b2b2b);
		--tami-wash: rgba(16, 24, 32, 0.08);
		/* Soft ambient shadows read as nothing at high contrast; a hard ring
		   does the same job of separating a card from the page. */
		--tami-elev-rest: 0 0 0 1px rgba(16, 24, 32, 0.35);
		--tami-elev-raise: 0 0 0 2px rgba(16, 24, 32, 0.55);
	}

	.tami__card,
	.tami__story-card,
	.tami__ministry-card,
	.tami__dashboard-card,
	.tami__stat-grid,
	.tami__empty,
	.tami__empty-state,
	.tami__contact,
	.tami__single-header {
		border-width: 2px;
	}

	.tami a:focus-visible,
	.tami button:focus-visible,
	.tami input:focus-visible,
	.tami select:focus-visible,
	.tami textarea:focus-visible,
	.tami [tabindex]:focus-visible {
		outline-width: 4px;
	}

	/* Flatten the hero scrim to its darkest stop so white text over a bright
	   photograph keeps a single predictable ratio rather than a gradient of
	   them. */
	.tami__hero::before {
		background-image: linear-gradient(0deg, rgba(9, 14, 11, 0.86), rgba(9, 14, 11, 0.86));
	}

	/* Card titles stop relying on hover to reveal that they are links. */
	.tami__card-title a::after {
		transform: scaleX(1);
	}
}

/* =========================================================================
 * 24. PRINT
 * =========================================================================
 *
 * Stories get printed. Field staff print them to carry into places with no
 * connectivity, and supporters print them to pass around. So the printed page
 * is a real output, not an afterthought: black on white, no furniture, no
 * dead controls, and every link's destination spelled out because paper
 * cannot be clicked.
 *
 * SCOPE NOTE. Every selector here stays inside .tami. The theme's header,
 * navigation and footer are Divi's markup and this plugin is not permitted to
 * reach outside its own scope for anything except the two sanctioned
 * suppressions in §17 and §20.4 — so hiding theme chrome on print is a job
 * for the theme's own print stylesheet. See INTEGRATION NEEDS.
 * ========================================================================= */

@media print {
	.tami {
		background: none;
		color: #000000;
		/* Points, not pixels: the printer's unit is physical. */
		font-size: 11pt;
		line-height: 1.5;
	}

	/* Navigation, pagination and calls to action are all instructions to do
	   something the paper cannot do. */
	.tami__breadcrumbs,
	.tami__hero-cta,
	.tami__pagination,
	.tami__pagination-list,
	.tami__view-all,
	.tami__filters,
	.tami__section--dashboard,
	.tami__stat-grid,
	.tami__section-actions,
	.tami__empty-actions,
	.tami__story-actions,
	.tami__actions,
	.tami__single-back,
	.tami__section-title::after,
	.tami__hero::before,
	.tami__hero::after,
	.tami__card-media::after {
		display: none;
	}

	/* The hero becomes a title block. Its photograph is a background image and
	   most browsers will not print it anyway; forcing it would only produce a
	   grey rectangle over which the white text would vanish. */
	.tami__hero {
		background: none;
		box-shadow: none;
		color: #000000;
		margin-block-end: 1.5rem;
		overflow: visible;
	}

	.tami__hero-inner {
		min-block-size: 0;
		padding-block: 0;
		padding-inline: 0;
	}

	.tami__hero-title,
	.tami__hero-desc,
	.tami__hero-description,
	.tami__hero-blurb,
	.tami__prose,
	.tami__card-title,
	.tami__section-title {
		color: #000000;
	}

	.tami__container {
		inline-size: 100%;
		max-inline-size: none;
		padding-inline: 0;
	}

	/* Paper has its own measure — the page width. A ch cap on top of it would
	   waste a third of every sheet. */
	.tami__prose,
	.tami__single-content {
		max-inline-size: none;
		orphans: 3;
		widows: 3;
	}

	/*
	 * Spell out link destinations. Fragment and javascript links are skipped:
	 * "(#main)" printed after a word is noise, not information.
	 */
	.tami__prose a,
	.tami__single-meta-value a,
	.tami__contact-value a {
		color: #000000;
		text-decoration: underline;
	}

	.tami__prose a::after,
	.tami__contact-value a::after {
		content: " (" attr(href) ")";
		font-size: 0.85em;
		overflow-wrap: anywhere;
	}

	.tami__prose a[href^="#"]::after,
	.tami__prose a[href^="javascript:"]::after {
		content: "";
	}

	/* Nothing may be split across a sheet boundary. break-inside is the
	   current property; page-break-inside is its predecessor and is still what
	   several print engines actually implement. */
	.tami__card,
	.tami__story-card,
	.tami__ministry-card,
	.tami__leader,
	.tami__single-header,
	.tami__contact,
	.tami__table tr {
		page-break-inside: avoid;
		break-inside: avoid;
	}

	.tami__card,
	.tami__story-card,
	.tami__ministry-card,
	.tami__single-header,
	.tami__contact,
	.tami__stat-card {
		border: 1px solid #999999;
		box-shadow: none;
	}

	/* Countering §20.2, which is more specific and would otherwise keep the
	   drop shadow — a shadow prints as a smear of grey toner. */
	.tami img:not(.tami__logo-image):not(.tami__leader-image),
	.tami__card-media img,
	.tami__card-image,
	.tami__logo-image,
	.tami__prose img {
		box-shadow: none;
	}

	/* Two across on A4: three tracks of cards come out too small to read. */
	.tami__grid--3,
	.tami__stories-grid,
	.tami__ministries-grid {
		grid-template-columns: repeat(2, minmax(0, 1fr));
		justify-content: start;
	}

	/* The table no longer needs to scroll — the sheet is as wide as it is. */
	.tami__table-wrap {
		overflow-x: visible;
	}

	.tami__table {
		min-inline-size: 0;
	}

	/* Section rhythm tuned for a screen wastes paper. */
	.tami__section {
		margin-block-start: 1.5rem;
	}

	.tami__section--divider::before {
		margin-block-end: 1rem;
	}
}

/* =========================================================================
 * 25. TAP-TARGET: make the whole card clickable
 *
 * Measured on a 390x844 iPhone: the card TITLE link was a 179x24 hit area —
 * well under the 44px minimum, and a fiddly target on a phone. The card
 * already contains a second link (the "View Profile" CTA) pointing at the
 * SAME url, so stretching the title over the card costs nothing functionally
 * and turns the entire card into one generous target — which is also what
 * people instinctively tap on a card.
 *
 * The ::after overlay sits above the card's own background but below the CTA
 * text, so the CTA still reads as an affordance. Both links share a
 * destination, so whichever one receives the tap does the same thing.
 * ========================================================================= */

.tami__card {
	/* Already relative in §8; restated so this block is self-contained if the
	   card styles are ever refactored. */
	position: relative;
}

.tami__card-title > a::after {
	content: "";
	inset: 0;
	position: absolute;
	/* Above the card surface, below nothing else that needs pointer events. */
	z-index: 1;
}

/* The visible CTA keeps its hover/focus styling and stays keyboard-reachable;
   it simply is not the thing being tapped on touch. */
.tami__card-cta {
	position: relative;
	z-index: 2;
}

/* -------------------------------------------------------------------------
 * 25.1  Breadcrumb links on touch
 *
 * Inline text links inside a breadcrumb trail are explicitly exempt from the
 * WCAG 2.2 minimum target size (2.5.8, "inline" exception), so this is not a
 * conformance fix — measured on a 390px viewport the "Africa" crumb was a
 * ~20px-tall target, which is simply awkward with a thumb.
 *
 * Vertical padding only, applied under a coarse pointer: it grows the hit
 * area without changing the trail's typography or wrapping on desktop.
 * ------------------------------------------------------------------------- */

@media (pointer: coarse) {
	.tami__breadcrumbs a,
	.tami__breadcrumb-item a {
		display: inline-block;
		/* ~44px total with the line-height, without altering the visual rhythm. */
		padding-block: 0.6rem;
	}

	.tami__breadcrumbs {
		/* Reclaim the space the padding adds so the hero does not grow. */
		margin-block-end: -0.6rem;
	}
}

/* =========================================================================
 * 26. THE SUBMISSION FORM
 *
 * This section exists because the form had almost no styling at all: of its
 * 35 classes only .tami__input and .tami__actions carried any rules, so
 * the most important page a contributor ever sees fell back to raw browser and
 * theme defaults while every other plugin surface used the design system.
 *
 * Everything below is built from the SAME tokens as the cards, hero and
 * sections above — surface, line, ink, accent, radius, elevation, the spacing
 * scale — so the form now reads as part of the plugin rather than a stray
 * WordPress form that wandered in.
 *
 * Priorities, in order: legible at 320px; obvious what is required; the media
 * area feels like somewhere you drop files rather than a disabled panel; and
 * every control keeps a visible focus state.
 * ========================================================================= */

/* ---- shell -------------------------------------------------------------- */

.tami .tami__form {
	display: flex;
	flex-direction: column;
	gap: var(--tami-space-row, 2rem);
	/* Forms are read in a single column: a comfortable measure beats filling
	   a 1600px shell with 1600px-wide text fields. */
	max-inline-size: 56rem;
}

/* ---- fieldsets read as cards -------------------------------------------- */

.tami .tami__fieldset {
	background: var(--tami-surface);
	border: 1px solid var(--tami-line);
	border-radius: 10px;
	box-shadow: var(--tami-elev-rest);
	/*
	 * NOT display:flex.
	 *
	 * A <legend> is not a normal child: browsers lay it out on the
	 * fieldset's top border, and making the fieldset a flex container makes
	 * that behaviour worse, not better — the heading rendered above the card
	 * with the border re-joining beneath it, so every section title looked
	 * detached from the panel it names. flow-root keeps a plain block
	 * formatting context (which the legend understands) and child margins
	 * supply the rhythm flex-gap would have.
	 */
	display: flow-root;
	/* Browsers disagree on default fieldset margin AND padding — reset both. */
	margin: 0;
	padding-block: var(--tami-step-3, 1.5rem);
	padding-inline: var(--tami-step-3, 1.5rem);
}

.tami .tami__legend {
	/*
	 * display:block is what actually pulls the legend INSIDE the card.
	 * A <legend> is laid out on the fieldset's top border by default, so
	 * with float:none alone the heading floated above the card and the
	 * border re-joined beneath it — the title looked detached from the
	 * panel it names.
	 */
	display: block;
	color: var(--tami-ink);
	font-family: var(--tami-font-heading, inherit);
	font-size: clamp(1.05rem, 0.98rem + 0.35vw, 1.25rem);
	font-weight: 700;
	/*
	 * FLOATING is what finally moves the legend off the border.
	 *
	 * display:block alone is not enough — browsers keep rendering a <legend>
	 * in the fieldset's border box, which left the heading sitting on the
	 * card edge with the border passing through it. Floating takes it out of
	 * that special layout and into normal flow; inline-size:100% keeps it on
	 * its own line, and the fieldset's flow-root contains the float.
	 */
	float: inline-start;
	inline-size: 100%;
	line-height: 1.3;
	/* Enough air that the heading reads as a section title, not a label. */
	margin-block-end: var(--tami-step-2, 1rem);
	padding-inline: 0;
}

/* Same accent rule the section headings use, so the two feel related. */
.tami .tami__legend::after {
	background: var(--tami-accent-raw);
	block-size: 3px;
	border-radius: 3px;
	content: "";
	display: block;
	inline-size: 2.5rem;
	margin-block-start: 0.5rem;
}

.tami .tami__fieldset--consent {
	background: var(--tami-wash);
}

/* ---- fields -------------------------------------------------------------- */

.tami .tami__field {
	display: flex;
	flex-direction: column;
	gap: 0.4rem;
}

.tami .tami__label {
	color: var(--tami-ink);
	font-size: 0.95rem;
	font-weight: 600;
	line-height: 1.4;
}

.tami .tami__required {
	color: var(--tami-accent-ink);
	font-weight: 700;
	/* The asterisk carries the meaning on its own — never colour alone. */
	margin-inline-start: 0.15em;
}

.tami .tami__hint {
	color: var(--tami-muted-ink);
	font-size: 0.875rem;
	line-height: 1.5;
	margin: 0;
}

/* ---- controls ------------------------------------------------------------ */

.tami .tami__input,
.tami .tami__select,
.tami .tami__textarea,
.tami .tami__filters-select {
	background: var(--tami-surface);
	border: 1px solid var(--tami-line);
	border-radius: var(--tami-radius-control, 8px);
	color: var(--tami-ink);
	font-family: inherit;
	/* 16px floor: anything smaller makes iOS Safari zoom in on focus. */
	font-size: max(1rem, 16px);
	inline-size: 100%;
	line-height: 1.5;
	min-block-size: 44px;
	padding-block: 0.6rem;
	padding-inline: 0.85rem;
	transition:
		border-color var(--tami-dur) var(--tami-ease),
		box-shadow var(--tami-dur) var(--tami-ease);
}

.tami .tami__textarea {
	min-block-size: 10rem;
	resize: vertical;
}

.tami .tami__input:hover,
.tami .tami__select:hover,
.tami .tami__textarea:hover {
	border-color: var(--tami-accent-raw);
}

.tami .tami__input:focus-visible,
.tami .tami__select:focus-visible,
.tami .tami__textarea:focus-visible {
	border-color: var(--tami-accent-ink);
	/* A ring rather than an outline, so focusing never nudges the layout. */
	box-shadow: 0 0 0 3px color-mix(in srgb, var(--tami-accent-raw) 28%, transparent);
	outline: none;
}

.tami .tami__input:disabled,
.tami .tami__select:disabled,
.tami .tami__textarea:disabled {
	background: var(--tami-wash);
	color: var(--tami-muted-ink);
	cursor: not-allowed;
}

/* Room for the native select arrow without hiding the control's affordance. */
.tami .tami__select {
	padding-inline-end: 2.25rem;
}

/* ---- checkbox and radio rows --------------------------------------------- */

.tami .tami__field--checkbox {
	align-items: flex-start;
	flex-direction: row;
	gap: 0.65rem;
}

.tami .tami__checkbox,
.tami .tami__radio {
	accent-color: var(--tami-accent-raw);
	/* A 20px box inside a tall row: the LABEL is the target, not the box. */
	block-size: 1.25rem;
	flex: 0 0 auto;
	inline-size: 1.25rem;
	margin-block-start: 0.15rem;
}

.tami .tami__label--inline {
	cursor: pointer;
	font-weight: 400;
	/* Generous leading gives the label a comfortable tap area by itself. */
	line-height: 1.6;
}

/* ---- file input ---------------------------------------------------------- */

.tami .tami__file {
	background: var(--tami-wash);
	border: 2px dashed var(--tami-line);
	border-radius: 10px;
	color: var(--tami-ink);
	cursor: pointer;
	display: block;
	font-family: inherit;
	font-size: max(0.95rem, 16px);
	inline-size: 100%;
	padding-block: var(--tami-step-3, 1.5rem);
	padding-inline: var(--tami-step-2, 1rem);
	transition:
		background var(--tami-dur) var(--tami-ease),
		border-color var(--tami-dur) var(--tami-ease);
}

.tami .tami__file:hover,
.tami .tami__file:focus-within {
	background: var(--tami-surface);
	border-color: var(--tami-accent-raw);
}

.tami .tami__file::file-selector-button {
	background: var(--tami-color-accent, var(--tami-accent-raw));
	border: 0;
	border-radius: var(--tami-radius-pill, 999px);
	color: var(--tami-color-accent-contrast, #1a1a1a);
	cursor: pointer;
	font-family: inherit;
	font-size: 0.9375rem;
	font-weight: 700;
	margin-inline-end: 0.85rem;
	min-block-size: 44px;
	padding-block: 0.55em;
	padding-inline: 1.25em;
	transition: filter var(--tami-dur) var(--tami-ease);
}

.tami .tami__file::file-selector-button:hover {
	filter: brightness(0.94);
}

/* ---- upload list --------------------------------------------------------- */

.tami .tami__upload-list {
	display: flex;
	flex-direction: column;
	gap: 0.75rem;
	list-style: none;
	margin: 0;
	padding: 0;
}

.tami .tami__upload-item {
	background: var(--tami-surface);
	border: 1px solid var(--tami-line);
	border-radius: 10px;
	display: flex;
	flex-direction: column;
	gap: 0.5rem;
	padding: 0.85rem;
}

.tami .tami__upload-name {
	font-weight: 600;
	/* A long filename must wrap, not push the card sideways. */
	overflow-wrap: anywhere;
}

.tami .tami__upload-state {
	color: var(--tami-muted-ink);
	font-size: 0.875rem;
}

/* Status is always carried by the text as well as the colour. */
.tami .tami__upload-item--done {
	border-inline-start: 4px solid var(--tami-accent-raw);
}

.tami .tami__upload-item--failed {
	border-inline-start: 4px solid #b32d2e;
}

.tami .tami__upload-item--failed .tami__upload-state {
	color: #b32d2e;
}

.tami .tami__upload-progress {
	background: var(--tami-wash);
	block-size: 6px;
	border: 0;
	border-radius: 999px;
	inline-size: 100%;
	overflow: hidden;
}

.tami .tami__upload-progress::-webkit-progress-bar {
	background: var(--tami-wash);
}

.tami .tami__upload-progress::-webkit-progress-value {
	background: var(--tami-accent-raw);
}

.tami .tami__upload-progress::-moz-progress-bar {
	background: var(--tami-accent-raw);
}

/* The per-file alt / cover / caption controls sit quietly under their file. */
.tami .tami__upload-alt,
.tami .tami__upload-captions {
	display: flex;
	flex-direction: column;
	font-size: 0.9rem;
	gap: 0.3rem;
}

.tami .tami__upload-cover {
	align-items: center;
	display: flex;
	font-size: 0.9rem;
	gap: 0.5rem;
}

/* ---- status and notices --------------------------------------------------- */

.tami .tami__status {
	color: var(--tami-muted-ink);
	font-size: 0.9rem;
	margin: 0;
	/* Reserve the line so announcing a status never shifts the layout. */
	min-block-size: 1.4em;
}

.tami .tami__status--error {
	color: #b32d2e;
	font-weight: 600;
}

.tami .tami__autosave {
	color: var(--tami-muted-ink);
	font-size: 0.85rem;
}

.tami .tami__notice {
	background: var(--tami-wash);
	border-inline-start: 4px solid var(--tami-accent-raw);
	border-radius: 10px;
	margin: 0;
	padding-block: 0.85rem;
	padding-inline: 1rem;
}

.tami .tami__notice--recovery {
	border-inline-start-color: #b26200;
}

/* ---- actions -------------------------------------------------------------- */

.tami .tami__actions {
	align-items: center;
	display: flex;
	flex-wrap: wrap;
	gap: 0.75rem;
}

/* On a phone the buttons stack and go full width — a half-width primary
   action at 320px is a needlessly small target. */
@media (max-width: 29.999rem) {
	.tami__actions .tami__button {
		inline-size: 100%;
	}
}

/* ---- roomier once there is space ------------------------------------------ */

@media (min-width: 48rem) {
	.tami .tami__fieldset {
		padding-block: var(--tami-step-4, 2rem);
		padding-inline: var(--tami-step-4, 2rem);
	}
}

/* Rhythm inside a flow-root fieldset: child margins replace the flex gap the
   legend quirk forced us to give up (see .tami__fieldset above). */
.tami .tami__fieldset > * + * {
	margin-block-start: var(--tami-space-module, 1rem);
}

/* The legend is the one child that must NOT inherit that top margin — it is
   the first thing in the card. */
.tami .tami__fieldset > .tami__legend {
	margin-block-start: 0;
}

/* The floated legend must not have siblings flowing beside it: without a
   clear, the first field wrapped into the narrow strip left of the float and
   collapsed to one character per line. */
.tami .tami__fieldset > * {
	clear: both;
}

/* -------------------------------------------------------------------------
 * 27. CLIENT REVISIONS — 2026-09-01
 *
 * Flags, taglines, justified body copy, page padding, and the rebuilt
 * ministry profile. Everything here is scoped under .tami and written in
 * logical properties, so Farsi gets the mirrored layout for free.
 *
 * Where a rule has to beat Divi it carries TWO class selectors
 * (.tami .tami__x = 0,2,0) rather than one, because Divi's element
 * selectors like `.entry-content ul` land at 0,1,1 and would otherwise win.
 * ------------------------------------------------------------------------- */

/* -------------------------------------------------------------------------
 * 27.1  Page padding — 30px from the site header, 50px before the footer.
 *
 * On the OUTER wrapper, not on each section: a plugin page is a stack of
 * sections with their own rhythm, and padding each one would compound.
 * ------------------------------------------------------------------------- */

.tami {
	padding-block-end: 50px;
	padding-block-start: 30px;
}

/* A shortcode dropped mid-page is not a page. It sits inside the editor's own
   flow, which already has spacing above and below it, so it keeps the module
   rhythm instead of the page rhythm. */
.tami.tami--inline {
	padding-block: 0;
}

/* -------------------------------------------------------------------------
 * 27.2  Justified body copy.
 *
 * The client asked for justify on text, body text and excerpts — and ONLY
 * those. Headings, buttons, labels, meta lines and table cells stay
 * start-aligned: justifying a three-word heading tears it into a line of
 * islands.
 *
 * hyphens: auto is not optional here. Justify without hyphenation in a 300px
 * card column opens rivers of white space; with it, the same column reads
 * normally. The lang attribute WordPress prints on <html> drives the
 * dictionary, so this works in every locale the site ships.
 * ------------------------------------------------------------------------- */

.tami .tami__prose,
.tami .tami__prose p,
.tami .tami__prose li,
.tami .tami__card-excerpt,
.tami .tami__hero-blurb,
.tami .tami__hero-blurb p,
.tami .tami__story-body,
.tami .tami__story-body p,
.tami .tami__address-body,
.tami .tami__excerpt {
	hyphens: auto;
	text-align: justify;
	-webkit-hyphens: auto;
}

/* The final line of a justified block is start-aligned by spec, but Divi sets
   text-align-last on some containers; restate it so a one-line excerpt is not
   stretched edge to edge. */
.tami .tami__prose p,
.tami .tami__card-excerpt,
.tami .tami__hero-blurb p,
.tami .tami__story-body p {
	text-align-last: start;
}

/*
 * Never justify a heading, a control, or a data cell — see the note above.
 *
 * KEEP THE `text-align: start` HERE. It looks like it duplicates the root
 * rule in tami.css and it does not: the root rule stops the theme's
 * `text-align: left` from being INHERITED into our subtree, and these
 * elements do not merely inherit. A bare `th`/`td` is targeted by the theme
 * directly (measured: `left` without this rule, in Farsi too), an h2 inside a
 * justified block inherits `justify` from that block rather than from
 * `.tami`, and `.tami__button` centres itself. Each is a declared value
 * the root rule cannot reach past.
 */
.tami h1,
.tami h2,
.tami h3,
.tami h4,
.tami .tami__card-title,
.tami .tami__card-meta,
.tami .tami__section-title,
.tami .tami__button,
.tami .tami__label,
.tami th,
.tami td {
	text-align: start;
	text-align-last: auto;
	hyphens: manual;
	-webkit-hyphens: manual;
}

/* -------------------------------------------------------------------------
 * 27.3  Flags.
 *
 * Two shapes. The IMAGE flag is a real <img> and keeps its aspect ratio —
 * object-fit: contain, never cover, because a cropped flag is a different
 * flag. The CHIP is the fallback for a country whose flag image has not been
 * set: two letters in a bordered pill, which reads as "a flag belongs here"
 * rather than as a broken image.
 *
 * Both are aria-hidden at the markup level. The place name is always printed
 * beside them, so a screen reader must not hear the country twice.
 * ------------------------------------------------------------------------- */

.tami .tami-flag {
	block-size: 0.85em;
	border-radius: 2px;
	box-shadow: 0 0 0 1px rgb(0 0 0 / 12%);
	display: inline-block;
	flex: none;
	inline-size: auto;
	margin-inline-end: 0.45em;
	object-fit: contain;
	vertical-align: -0.08em;
}

/* The chip carries text, so it sizes from its content rather than from a
   fixed box. Tabular-ish letterforms keep KE and MW the same width. */
.tami .tami-flag--chip {
	background: var(--tami-wash, rgb(0 0 0 / 4%));
	block-size: auto;
	border: 1px solid var(--tami-line, rgb(0 0 0 / 12%));
	border-radius: 3px;
	box-shadow: none;
	color: var(--tami-muted-ink, #55606a);
	font-size: 0.68em;
	font-weight: 700;
	letter-spacing: 0.06em;
	line-height: 1.5;
	padding-inline: 0.34em;
	text-transform: uppercase;
	vertical-align: 0.06em;
}

/*
 * A place name and its flag are one unit, and the flag must never be left
 * stranded at the end of a line with the name it belongs to on the next.
 *
 * Suppressing that break is harder than it looks, because the break in
 * question is the one a browser opens AFTER an atomic inline — the <img> —
 * and nothing at the character level closes it. Measured in Chrome 148 at a
 * 262px column (the 375px phone), heading `Stories from <flag>Saint Helena,
 * Ascension and Tristan da Cunha`: the flag ended line one at x=249 in a
 * column running to x=319 and the name started on line two. The WORD JOINER
 * (U+2060) that Flags::label_html() emits between the two did NOT prevent
 * it, and neither did NBSP or ZWNBSP in its place — isolated in a bare div,
 * U+2060 after an <img> orphaned at exactly the same widths as no separator
 * at all. `white-space: nowrap` on the IMG, which this rule used to carry,
 * was inert for a second reason on top of that: white-space governs an
 * element's OWN text content and an <img> has none.
 *
 * `white-space: nowrap` on this span does suppress the break, and is the
 * wrong trade: at that same 262px column the label measured 540px wide and
 * shoved 329px of heading out of its column.
 *
 * inline-block is what actually works. The flag then opens the label's own
 * first line, so there is no preceding content it can be stranded after, and
 * the name still wraps freely inside the box — 43 characters of Saint Helena
 * take three lines in that column exactly as before, with no overflow.
 *
 * The cost, stated honestly: a label too wide for the space left on the
 * current line now moves down whole rather than starting mid-line, so
 * `Cities in <flag>Democratic Republic of the Congo` is one line taller
 * between roughly 300px and 480px of column. A heading that deterministically
 * breaks after its lead-in still reads as a heading; a detached flag reads as
 * a bug. (A `white-space: nowrap` wrapper around the flag and the first word
 * of the name would cost no line at all, but that is markup, not CSS —
 * Flags::label_html().)
 *
 * white-space is pinned to normal so a theme setting nowrap further up cannot
 * stop the name wrapping inside the box.
 */
.tami .tami-place {
	display: inline-block;
	white-space: normal;
}

/* -------------------------------------------------------------------------
 * 27.4  The flag hero.
 *
 * The background copy of the flag is blurred and dimmed into a colour wash;
 * this crisp copy sits above it at a readable size with the whole flag
 * visible. Scaling the blurred layer past the edges hides the soft border
 * that `filter: blur()` leaves at the box boundary.
 * ------------------------------------------------------------------------- */

/*
 * DO NOT redefine .tami__hero::before here.
 *
 * That is the scrim — two stacked gradients over a flat rgba(9,14,11,0.55)
 * floor, sized so white text clears AA against the brightest possible image
 * (measured worst case ≈ 5.4:1). An earlier version of this section overrode
 * it with a blurred copy of the flag at 0.32 opacity, which threw the contrast
 * guarantee away: the hero rendered as a bright green-and-white field with
 * white text over the white half, and the crisp flag disappeared into its own
 * blurred backdrop because the two were the same image.
 *
 * The flag rides the element's own background-image, exactly as a photograph
 * does, and the untouched scrim darkens it into an abstract colour field. That
 * is the whole trick: a flag is fine as hero ART as long as something
 * guarantees the text on top of it.
 */
.tami .tami__hero--flag {
	background-position: center;
	background-size: cover;
	overflow: hidden;
	position: relative;
}

.tami .tami__hero-flag {
	margin-block: 0 var(--tami-step-2, 1rem);
	margin-inline: 0;
	max-inline-size: 240px;
}

/*
 * A white mount around the crisp flag, not just a shadow.
 *
 * The backdrop behind it is the same flag, so a shadow alone does not separate
 * them — a green flag on its own green wash simply vanishes at the edges. The
 * mount is what makes the flag read as a discrete object, and it is how flags
 * are shown on paper anyway.
 */
.tami .tami__hero-flag img {
	background: #fff;
	block-size: auto;
	border-radius: 10px;
	box-shadow:
		0 1px 2px rgb(9 14 11 / 28%),
		0 10px 30px rgb(9 14 11 / 38%);
	display: block;
	inline-size: 100%;
	object-fit: contain;
	padding: 6px;
}

@media (min-width: 48rem) {
	.tami .tami__hero-flag {
		max-inline-size: 300px;
	}
}

/* -------------------------------------------------------------------------
 * 27.5  Headline block — the H1, an optional mark beside it, the tagline.
 * ------------------------------------------------------------------------- */

.tami .tami__hero-headline {
	align-items: center;
	display: flex;
	flex-wrap: wrap;
	gap: var(--tami-step-2, 1rem);
}

.tami .tami__hero-headline-text {
	flex: 1 1 16rem;
	min-inline-size: 0;
}

/* The ministry mark: a fixed, square, contained block so logos of wildly
   different aspect ratios all occupy the same slot beside the name. */
.tami .tami__hero-badge {
	align-items: center;
	background: var(--tami-color-surface, #fff);
	block-size: 84px;
	border-radius: 10px;
	box-shadow:
		0 1px 2px rgb(16 24 32 / 10%),
		0 6px 18px rgb(16 24 32 / 14%);
	display: flex;
	flex: none;
	inline-size: 84px;
	justify-content: center;
	overflow: hidden;
	padding: 8px;
}

.tami .tami__hero-badge img {
	block-size: 100%;
	border-radius: 0;
	box-shadow: none;
	inline-size: 100%;
	object-fit: contain;
}

@media (min-width: 48rem) {
	.tami .tami__hero-badge {
		block-size: 104px;
		inline-size: 104px;
	}
}

/* -------------------------------------------------------------------------
 * 27.6  Taglines.
 *
 * Not justified: a tagline is one line of display copy, and justifying a
 * single line does nothing but risk stretching it. Nothing justifies a
 * tagline, so that needs no declaration — it needed one only while the
 * theme's `text-align: left` was still leaking in, which is now stopped at
 * `.tami` in the base sheet. Both taglines inherit `start` from there.
 * ------------------------------------------------------------------------- */

.tami .tami__tagline {
	color: var(--tami-muted-ink, #55606a);
	font-size: 1.02rem;
	font-style: italic;
	line-height: 1.5;
	margin-block: 0.35rem 0;
}

.tami .tami__hero-tagline {
	color: inherit;
	opacity: 0.86;
}

.tami .tami-card__tagline {
	color: var(--tami-muted-ink, #55606a);
	font-size: 0.9rem;
	font-style: italic;
	line-height: 1.45;
	margin-block: 0.15rem 0.35rem;
}

/* -------------------------------------------------------------------------
 * 27.7  No bullets on card grids.
 *
 * The grid <ul> already sets list-style: none, but a marker can arrive three
 * other ways: an inherited list-style-type on the <li>, a theme's ::before
 * bullet, or ::marker. All three are closed here, with two class selectors so
 * a theme rule at 0,1,1 cannot reopen them.
 * ------------------------------------------------------------------------- */

.tami .tami__grid,
.tami .tami__grid-item,
.tami .tami__leadership {
	list-style: none;
}

.tami .tami__grid-item::marker {
	content: "";
}

.tami .tami__grid-item::before {
	content: none;
}

/* -------------------------------------------------------------------------
 * 27.8  Ministry cards — photograph on top, mark beside the name.
 * ------------------------------------------------------------------------- */

.tami .tami__card--ministry .tami__card-logo {
	background: var(--tami-color-surface, #fff);
	block-size: 56px;
	border: 1px solid var(--tami-line, rgb(0 0 0 / 10%));
	border-radius: 10px;
	box-shadow: 0 1px 3px rgb(16 24 32 / 12%);
	flex: none;
	inline-size: 56px;
	object-fit: contain;
	padding: 5px;
}

/* The empty-logo placeholder is the ministry's initial, centred in the same
   box so a card without a mark keeps the grid's alignment. */
.tami .tami__card--ministry .tami__card-logo--empty {
	align-items: center;
	color: var(--tami-muted-ink, #55606a);
	display: flex;
	font-size: 1.5rem;
	font-weight: 700;
	justify-content: center;
	line-height: 1;
	padding: 0;
}

.tami .tami__card--ministry .tami__card-head {
	align-items: center;
	display: flex;
	gap: 0.75rem;
}

.tami .tami__card--ministry .tami__card-id {
	min-inline-size: 0;
}

/* A 150-word description needs room to breathe and a ceiling, or one verbose
   ministry stretches its whole row. The clamp keeps every card in a row the
   same height while still showing far more than the old 55-word excerpt. */
.tami .tami__card--ministry .tami__card-excerpt {
	-webkit-box-orient: vertical;
	display: -webkit-box;
	-webkit-line-clamp: 9;
	line-clamp: 9;
	overflow: hidden;
}

/* -------------------------------------------------------------------------
 * 27.9  Ministry profile — the facts row: one row, two columns.
 * ------------------------------------------------------------------------- */

.tami .tami-ministry__facts {
	align-items: start;
	background: var(--tami-color-surface, #fff);
	border: 1px solid var(--tami-line, rgb(0 0 0 / 10%));
	border-radius: 10px;
	box-shadow: 0 1px 3px rgb(16 24 32 / 8%);
	display: grid;
	gap: var(--tami-space-col, 1.5rem);
	grid-template-columns: minmax(0, 1fr);
	margin-block-end: var(--tami-space-module, 1.5rem);
	padding: clamp(1rem, 3vw, 1.75rem);
}

@media (min-width: 48rem) {
	.tami .tami-ministry__facts {
		grid-template-columns: minmax(0, 200px) minmax(0, 1fr);
	}
}

.tami .tami-ministry__facts-logo {
	align-items: center;
	display: flex;
	justify-content: center;
}

.tami .tami-ministry__facts-logo img {
	block-size: auto;
	inline-size: 100%;
	max-inline-size: 180px;
	object-fit: contain;
}

.tami .tami-ministry__facts-meta {
	display: grid;
	gap: 0.9rem;
	list-style: none;
	margin-block: 0;
	padding-inline-start: 0;
}

.tami .tami-ministry__facts-meta .tami__single-meta-item {
	border-block-end: 1px solid var(--tami-line, rgb(0 0 0 / 8%));
	display: grid;
	gap: 0.15rem;
	padding-block-end: 0.9rem;
}

.tami .tami-ministry__facts-meta .tami__single-meta-item:last-child {
	border-block-end: 0;
	padding-block-end: 0;
}

.tami .tami-ministry__facts-meta .tami__single-meta-label {
	color: var(--tami-muted-ink, #55606a);
	font-size: 0.72rem;
	font-weight: 700;
	letter-spacing: 0.08em;
	text-transform: uppercase;
}

.tami .tami-ministry__facts-meta .tami__single-meta-value {
	font-size: 1.02rem;
}

/* -------------------------------------------------------------------------
 * 27.10  About + address, as one padded module.
 * ------------------------------------------------------------------------- */

.tami .tami-ministry__about {
	background: var(--tami-color-surface, #fff);
	border: 1px solid var(--tami-line, rgb(0 0 0 / 10%));
	border-radius: 10px;
	box-shadow: 0 1px 3px rgb(16 24 32 / 8%);
	margin-block-end: var(--tami-space-module, 1.5rem);
	padding: clamp(1.15rem, 3.5vw, 2rem);
}

.tami .tami-ministry__about > * + * {
	border-block-start: 1px solid var(--tami-line, rgb(0 0 0 / 8%));
	margin-block-start: clamp(1.15rem, 3vw, 1.75rem);
	padding-block-start: clamp(1.15rem, 3vw, 1.75rem);
}

.tami .tami-ministry__about .tami__section-title {
	margin-block-start: 0;
}

.tami .tami__address-body {
	font-style: normal;
	line-height: 1.7;
}

/* -------------------------------------------------------------------------
 * 27.11  Contact list — the client asked for air between the rows.
 * ------------------------------------------------------------------------- */

.tami .tami__contact-list {
	display: grid;
	gap: 1rem;
	list-style: none;
	margin-block: 0;
	padding-inline-start: 0;
}

.tami .tami__contact-item {
	align-items: baseline;
	display: flex;
	flex-wrap: wrap;
	gap: 0.35rem 0.85rem;
	padding-block: 0.35rem;
}

.tami .tami__contact-item + .tami__contact-item {
	border-block-start: 1px solid var(--tami-line, rgb(0 0 0 / 8%));
	padding-block-start: 1rem;
}

.tami .tami__contact-label {
	color: var(--tami-muted-ink, #55606a);
	flex: none;
	font-size: 0.72rem;
	font-weight: 700;
	letter-spacing: 0.08em;
	min-inline-size: 6.5rem;
	text-transform: uppercase;
}

.tami .tami__contact-value {
	min-inline-size: 0;
	overflow-wrap: anywhere;
}

/* -------------------------------------------------------------------------
 * 27.12  Leadership — a 3-column grid of raised cards.
 *
 * Three across on desktop, so six people read as the 2 x 3 the client asked
 * for; two on a tablet, one on a phone. The lift is a two-layer shadow — a
 * tight contact shadow plus a wide soft one — which is what reads as depth.
 * A single big blur reads as fog.
 * ------------------------------------------------------------------------- */

.tami .tami-leaders {
	display: grid;
	gap: var(--tami-space-row, 1.75rem) var(--tami-space-col, 1.5rem);
	grid-template-columns: minmax(0, 1fr);
	list-style: none;
	margin-block: 0;
	padding-inline-start: 0;
}

@media (min-width: 36rem) {
	.tami .tami-leaders {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

@media (min-width: 62rem) {
	.tami .tami-leaders {
		grid-template-columns: repeat(3, minmax(0, 1fr));
	}
}

.tami .tami-leader {
	align-items: center;
	background: var(--tami-color-surface, #fff);
	border: 1px solid var(--tami-line, rgb(0 0 0 / 8%));
	border-radius: 10px;
	box-shadow:
		0 1px 2px rgb(16 24 32 / 10%),
		0 10px 24px -6px rgb(16 24 32 / 18%);
	display: flex;
	flex-direction: column;
	gap: 0.5rem;
	padding: clamp(1.1rem, 3vw, 1.6rem);
	text-align: center;
	transition:
		box-shadow var(--tami-dur, 180ms) var(--tami-ease, ease),
		transform var(--tami-dur, 180ms) var(--tami-ease, ease);
}

@media (hover: hover) and (pointer: fine) {
	.tami .tami-leader:hover,
	.tami .tami-leader:focus-within {
		box-shadow:
			0 2px 4px rgb(16 24 32 / 12%),
			0 18px 36px -8px rgb(16 24 32 / 24%);
		transform: translateY(-3px);
	}
}

@media (prefers-reduced-motion: reduce) {
	.tami .tami-leader {
		transition: none;
	}

	.tami .tami-leader:hover,
	.tami .tami-leader:focus-within {
		transform: none;
	}
}

.tami .tami-leader__photo {
	block-size: 128px;
	border-radius: 50%;
	display: block;
	flex: none;
	inline-size: 128px;
	overflow: hidden;
}

.tami .tami-leader__photo img {
	block-size: 100%;
	border-radius: 50%;
	box-shadow: none;
	inline-size: 100%;
	object-fit: cover;
}

/* No photo: a neutral disc, not an empty gap, so the grid keeps its rhythm. */
.tami .tami-leader__photo--empty,
.tami .tami__leader-photo--empty {
	background: var(--tami-wash, rgb(0 0 0 / 5%));
	border: 1px dashed var(--tami-line, rgb(0 0 0 / 14%));
}

.tami .tami-leader__name {
	color: var(--tami-color-heading, inherit);
	font-size: 1.08rem;
	font-weight: 700;
	line-height: 1.3;
}

.tami .tami-leader__role {
	color: var(--tami-muted-ink, #55606a);
	font-size: 0.78rem;
	font-weight: 600;
	letter-spacing: 0.07em;
	text-transform: uppercase;
}

/* -------------------------------------------------------------------------
 * 27.13  Call and email, under the role.
 *
 * Real links with visible labels, not bare icons: an unlabelled icon is a
 * guess for a sighted user and a 44px minimum for a thumb. Both are met here.
 * ------------------------------------------------------------------------- */

.tami .tami-leader__actions {
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem;
	justify-content: center;
	margin-block-start: 0.35rem;
}

.tami .tami-leader__action {
	align-items: center;
	background: var(--tami-wash, rgb(0 0 0 / 4%));
	border: 1px solid var(--tami-line, rgb(0 0 0 / 12%));
	border-radius: var(--tami-radius-pill, 999px);
	color: var(--tami-body-ink, inherit);
	display: inline-flex;
	font-size: 0.82rem;
	font-weight: 600;
	gap: 0.4rem;
	line-height: 1;
	min-block-size: 44px;
	padding-inline: 0.9rem;
	text-decoration: none;
	transition:
		background-color var(--tami-dur, 180ms) var(--tami-ease, ease),
		border-color var(--tami-dur, 180ms) var(--tami-ease, ease),
		color var(--tami-dur, 180ms) var(--tami-ease, ease);
}

.tami .tami-leader__action:hover,
.tami .tami-leader__action:focus-visible {
	background: var(--tami-color-accent, #7cbb42);
	border-color: var(--tami-color-accent, #7cbb42);
	color: var(--tami-color-accent-contrast, #1a1a1a);
}

.tami .tami-leader__icon {
	block-size: 18px;
	border-radius: 0;
	box-shadow: none;
	flex: none;
	inline-size: 18px;
}

@media (prefers-reduced-motion: reduce) {
	.tami .tami-leader__action {
		transition: none;
	}
}

/* -------------------------------------------------------------------------
 * 27.14  Flags in the pager.
 *
 * A pager link is a small square; a flag in front of a page number would
 * overflow it. Only the LABELLED pager links (a country name in a "browse by
 * country" pager) get one, and it is scaled down to match the smaller type.
 * ------------------------------------------------------------------------- */

.tami .tami__pagination .tami-flag {
	block-size: 0.75em;
	margin-inline-end: 0.35em;
}

/* -------------------------------------------------------------------------
 * 27.15  Print — flags and shadows cost ink and give nothing back.
 * ------------------------------------------------------------------------- */

@media print {
	.tami .tami__hero--flag::before,
	.tami .tami-leader__actions {
		display: none;
	}

	.tami .tami-leader,
	.tami .tami-ministry__facts,
	.tami .tami-ministry__about {
		box-shadow: none;
	}

	.tami {
		padding-block: 0;
	}
}

/* -------------------------------------------------------------------------
 * 28. THE RICH TEXT EDITOR — "Tell Us What Happened"
 *
 * A hand-built contenteditable surface with a toolbar above it. No bundle,
 * no TinyMCE: Divi loads its own copy of TinyMCE and the two fight.
 *
 * Progressive enhancement is the whole design. The server renders the editor
 * with [hidden] and the textarea visible; the script swaps them. So a visitor
 * with no JavaScript gets the plain textarea they always had, and one with
 * JavaScript gets the toolbar.
 * ------------------------------------------------------------------------- */

/* -------------------------------------------------------------------------
 * 28.1  [hidden] must actually hide.
 *
 * This is load-bearing, not defensive. The UA rule for [hidden] is
 * `display: none`, at specificity (0,0,0) — ANY display we set on these
 * classes silently overrides it, and the no-JS visitor gets a dead editor
 * stacked on top of their working textarea. So the hidden state is restated
 * at (0,3,0), above both the two-class rules below and anything Divi has.
 * ------------------------------------------------------------------------- */

.tami .tami__editor[hidden],
.tami .tami__textarea[hidden],
.tami .tami__editor-surface[hidden] {
	display: none !important;
}

/* -------------------------------------------------------------------------
 * 28.2  The editor shell.
 * ------------------------------------------------------------------------- */

.tami .tami__editor {
	background: var(--tami-color-surface, #fff);
	border: 1px solid var(--tami-line, rgb(0 0 0 / 18%));
	border-radius: var(--tami-radius-control, 10px);
	display: flex;
	flex-direction: column;
	overflow: hidden;
	transition: border-color var(--tami-dur, 180ms) var(--tami-ease, ease);
}

/* The focus ring belongs to the whole control, not to the inner div: to the
   person typing, the editor IS one field.

   Drawn in accent-ink, like every other focus ring in this sheet (§21, the
   filter controls, the card links). The raw accent was wrong here for the
   reason it is wrong anywhere a user has to SEE something: the default
   #7cbb42 is 2.3:1 against the white editor and the white page, and WCAG
   1.4.11 asks a focus indicator for 3:1. Ink is the same hue at 5:1. The
   translucent halo stays keyed to the raw accent — it is decoration layered
   under the border, and the border is the indicator. */
.tami .tami__editor:focus-within {
	border-color: var(--tami-accent-ink);
	box-shadow: 0 0 0 3px rgb(from var(--tami-accent-raw, #7cbb42) r g b / 22%);
}

/* rgb(from …) is recent. Browsers without it get a plain neutral ring rather
   than no ring at all — this is the fallback, overridden above where relative
   colour is supported. */
@supports not (color: rgb(from white r g b / 50%)) {
	.tami .tami__editor:focus-within {
		box-shadow: 0 0 0 3px rgb(16 24 32 / 14%);
	}
}

/* -------------------------------------------------------------------------
 * 28.3  The toolbar.
 * ------------------------------------------------------------------------- */

.tami .tami__editor-bar {
	align-items: center;
	background: var(--tami-wash, rgb(0 0 0 / 3%));
	border-block-end: 1px solid var(--tami-line, rgb(0 0 0 / 12%));
	display: flex;
	flex-wrap: wrap;
	gap: 2px;
	padding: 6px;
}

.tami .tami__editor-btn {
	align-items: center;
	background: transparent;
	border: 1px solid transparent;
	border-radius: 6px;
	color: var(--tami-body-ink, inherit);
	cursor: pointer;
	display: inline-flex;
	font-family: var(--tami-font-heading, inherit);
	font-size: 0.95rem;
	font-weight: 600;
	justify-content: center;
	line-height: 1;
	/* 36px, not the 44px tap minimum: nine of those would wrap to three rows
	   on a phone and push the writing surface off-screen. The toolbar is an
	   optional convenience over a fully usable textarea, and §21.2 raises
	   these to 44px on coarse pointers where it matters. */
	min-block-size: 36px;
	min-inline-size: 36px;
	padding-inline: 0.4rem;
	transition:
		background-color var(--tami-dur, 180ms) var(--tami-ease, ease),
		border-color var(--tami-dur, 180ms) var(--tami-ease, ease);
}

@media (hover: hover) and (pointer: fine) {
	.tami .tami__editor-btn:hover {
		background: var(--tami-color-surface, #fff);
		border-color: var(--tami-line, rgb(0 0 0 / 16%));
	}
}

/* Ink, not raw accent — same 1.4.11 reasoning as the editor shell above. The
   toolbar sits on --tami-wash, a near-white tint, so a light-green ring
   here was the least visible focus state on the page. */
.tami .tami__editor-btn:focus-visible {
	border-color: var(--tami-accent-ink);
	outline: 2px solid var(--tami-accent-ink);
	outline-offset: 1px;
}

/* aria-pressed is the state — style FROM it rather than from a parallel class,
   so the accessible state and the visible state can never disagree. */
.tami .tami__editor-btn[aria-pressed="true"] {
	background: var(--tami-color-accent, #7cbb42);
	border-color: var(--tami-color-accent, #7cbb42);
	color: var(--tami-color-accent-contrast, #1a1a1a);
}

/* Coarse pointers get the full 44px target (WCAG 2.5.5). */
@media (pointer: coarse) {
	.tami .tami__editor-btn {
		min-block-size: 44px;
		min-inline-size: 44px;
	}
}

@media (prefers-reduced-motion: reduce) {
	.tami .tami__editor,
	.tami .tami__editor-btn {
		transition: none;
	}
}

/* -------------------------------------------------------------------------
 * 28.4  The writing surface.
 *
 * Two class selectors so Divi's `textarea` / element rules cannot reach in,
 * and a min-height rather than rows: this is a div, not a textarea.
 * ------------------------------------------------------------------------- */

.tami .tami__editor-surface {
	background: var(--tami-color-surface, #fff);
	border: 0;
	color: var(--tami-body-ink, inherit);
	font-family: inherit;
	font-size: 1rem;
	hyphens: auto;
	line-height: 1.7;
	min-block-size: 14rem;
	overflow-wrap: break-word;
	padding: clamp(0.85rem, 2.5vw, 1.15rem);
	text-align: justify;
}

.tami .tami__editor-surface:focus,
.tami .tami__editor-surface:focus-visible {
	/* The ring is on the shell (28.2). A second one inside it reads as two
	   nested fields. */
	outline: none;
}

/* No placeholder rule here on purpose. A contenteditable has no `placeholder`
   attribute, so faking one needs the script to mark the empty state — and
   :empty alone will not do it, because a surface that has been typed in and
   cleared keeps a stray <br>. The script does not mark it, so a rule for it
   would be dead CSS describing a feature that does not exist. The bordered
   shell and the toolbar above it already read as a text field. */

/* Rhythm inside the surface. The author is writing prose, so it should look
   like the prose it will become. */
.tami .tami__editor-surface > * {
	margin-block: 0;
}

.tami .tami__editor-surface > * + * {
	margin-block-start: 0.85em;
}

/* hyphens, not alignment. The surface justifies its paragraphs (28.4 above)
   and a heading must not follow it, but §27.2 already start-aligns every h2/h3
   under `.tami` — a third copy of that answer here only made it harder to
   find the one that decides. Hyphenation is the part §27.2 cannot do from
   here, because the surface turns it on for the whole block. */
.tami .tami__editor-surface h2,
.tami .tami__editor-surface h3 {
	font-family: var(--tami-font-heading, inherit);
	font-weight: var(--tami-weight-heading, 700);
	hyphens: manual;
	line-height: 1.25;
}

.tami .tami__editor-surface h2 {
	font-size: 1.35rem;
}

.tami .tami__editor-surface h3 {
	font-size: 1.15rem;
}

.tami .tami__editor-surface ul,
.tami .tami__editor-surface ol {
	padding-inline-start: 1.5rem;
}

.tami .tami__editor-surface li {
	margin-block: 0.2em;
}

.tami .tami__editor-surface li + li {
	margin-block-start: 0.2em;
}

.tami .tami__editor-surface blockquote {
	border-inline-start: 3px solid var(--tami-color-accent, #7cbb42);
	color: var(--tami-muted-ink, #55606a);
	font-style: italic;
	margin-inline: 0;
	padding-inline-start: 1rem;
}

.tami .tami__editor-surface a {
	color: var(--tami-color-accent-strong, #4d7a26);
	text-decoration: underline;
}

/* -------------------------------------------------------------------------
 * 28.5  The cascading place selects.
 *
 * A select whose options have all been filtered out must not look like a
 * working control. The script disables it; this makes that visible.
 * ------------------------------------------------------------------------- */

.tami .tami__select:disabled {
	background: var(--tami-wash, rgb(0 0 0 / 4%));
	color: var(--tami-muted-ink, #55606a);
	cursor: not-allowed;
	opacity: 1;
}

/* -------------------------------------------------------------------------
 * 28.6  Print — a form is not a document.
 * ------------------------------------------------------------------------- */

@media print {
	.tami .tami__editor-bar {
		display: none;
	}

	.tami .tami__editor {
		border: 1px solid #999;
	}
}

/* =========================================================================
 * 29. THE THREE NARRATIVE STEPS — Struggle, Intervention, Transformation
 *
 * The client's editorial spine for "Share Your Story": pick a topic, then
 * answer three questions. Visually the job is to make three writing areas
 * read as ONE numbered sequence rather than as three unrelated fields that
 * happen to be stacked — otherwise a contributor treats step 2 as optional
 * and the story arrives with a middle missing.
 *
 * Every rule is scoped under .tami and uses logical properties, so the
 * numbered rail flips to the right-hand side in Farsi with no extra work.
 * ========================================================================= */

/* -------------------------------------------------------------------------
 * 29.1  Hiding must actually hide, and must not depend on us.
 *
 * The steps ship VISIBLE from the server and the script hides them until a
 * topic is chosen. That inversion is deliberate — a visitor with no
 * JavaScript must never meet a collapsed section nothing can open. The rule
 * below is the same load-bearing [hidden] restatement §28.1 needed: the UA's
 * `display: none` sits at (0,0,0), so the grid/flex we set on these classes
 * would silently beat it.
 * ------------------------------------------------------------------------- */

.tami .tami__steps[hidden],
.tami .tami__step[hidden] {
	display: none !important;
}

/* -------------------------------------------------------------------------
 * 29.2  The sequence.
 * ------------------------------------------------------------------------- */

.tami .tami__steps {
	display: flex;
	flex-direction: column;
	gap: var(--tami-step-3, 1.5rem);
}

.tami .tami__step {
	display: flex;
	flex-direction: column;
	gap: 0.5rem;
	/*
	 * The rail. A 3px accent line on the leading edge is what turns three
	 * boxes into one numbered run — the eye follows it down the page. It is
	 * decoration on top of the number and the "Step 1 — …" label, never the
	 * only thing carrying the sequence, so it costs nothing in high contrast
	 * or when a border is dropped.
	 */
	border-inline-start: 3px solid var(--tami-line, rgb(0 0 0 / 12%));
	padding-inline-start: var(--tami-step-3, 1.25rem);
	transition: border-color var(--tami-dur, 180ms) var(--tami-ease, ease);
}

/* The step being written in is the one lit up. focus-within covers the
   textarea, the editor surface AND the toolbar, which is the whole point. */
.tami .tami__step:focus-within {
	border-inline-start-color: var(--tami-color-accent, #7cbb42);
}

/* -------------------------------------------------------------------------
 * 29.3  The heading line: number badge + "Step 1 — The Struggle".
 * ------------------------------------------------------------------------- */

.tami .tami__step-head {
	align-items: center;
	display: flex;
	gap: 0.6rem;
	margin: 0;
}

.tami .tami__step-number {
	align-items: center;
	background: var(--tami-accent-raw, #7cbb42);
	border-radius: 50%;
	/* Not var(--tami-ink): this sits on the accent, and the accent is a
	   mid-tone green that mid-grey text does not clear 4.5:1 against. */
	color: #fff;
	display: inline-flex;
	flex: 0 0 auto;
	font-family: var(--tami-font-heading, inherit);
	font-size: 0.9rem;
	font-weight: 700;
	justify-content: center;
	line-height: 1;
	/* A circle, so both axes are fixed and a two-digit step would not stretch it
	   into an oval — block-size and inline-size, never width/height. */
	block-size: 1.75rem;
	inline-size: 1.75rem;
}

.tami .tami__step-title {
	font-family: var(--tami-font-heading, inherit);
	/* A shade larger than a field label: this is a section title inside the
	   fieldset, and the three of them are the structure of the page. */
	font-size: clamp(1rem, 0.95rem + 0.2vw, 1.1rem);
	font-weight: 700;
	line-height: 1.3;
	/* The label is a flex item here; let it wrap rather than squeeze the badge. */
	min-inline-size: 0;
}

/* -------------------------------------------------------------------------
 * 29.4  The prompt.
 *
 * The actual question the client wrote. It is the thing a contributor reads
 * before typing, so it gets more room than a hint usually does — but it stays
 * muted, because the answer is what matters on the screen.
 * ------------------------------------------------------------------------- */

.tami .tami__step-prompt {
	/* Prompts are read, not scanned: a comfortable measure stops the eye
	   losing its place on a wide screen. */
	max-inline-size: 46rem;
}

/* -------------------------------------------------------------------------
 * 29.5  The topic select that opens the steps.
 *
 * TWO class-level selectors, as every frontend control here needs, because
 * Divi styles bare `select` and a single class loses to it. Indentation
 * inside the options is done with no-break spaces in the markup — a browser
 * gives us no way to style option text, and padding on <option> is ignored
 * by every engine that matters.
 * ------------------------------------------------------------------------- */

.tami .tami__select[data-tami-topic] {
	font-variant-numeric: tabular-nums;
}

/* -------------------------------------------------------------------------
 * 29.6  Narrow screens.
 *
 * The rail costs horizontal room a phone does not have. Below 480px it thins
 * out and the indent goes, while the number badge — which is what actually
 * says "this is step 2 of 3" — stays exactly as it is.
 * ------------------------------------------------------------------------- */

@media (max-width: 480px) {
	.tami .tami__step {
		border-inline-start-width: 2px;
		padding-inline-start: 0.75rem;
	}
}

/* -------------------------------------------------------------------------
 * 29.7  High contrast and reduced motion.
 * ------------------------------------------------------------------------- */

@media (prefers-contrast: more) {
	.tami .tami__step {
		border-inline-start-color: currentcolor;
	}

	.tami .tami__step-number {
		outline: 1px solid currentcolor;
	}
}

@media (prefers-reduced-motion: reduce) {
	.tami .tami__step {
		transition: none;
	}
}

/* -------------------------------------------------------------------------
 * 29.8  Print.
 *
 * A printed form is a worksheet: the questions must survive, the rail need
 * not. Kept alongside §28.6 rather than merged into it, so the editor's print
 * rules and the steps' can change independently.
 * ------------------------------------------------------------------------- */

@media print {
	.tami .tami__step {
		border-inline-start: 1px solid #999;
	}

	.tami .tami__step-number {
		background: none;
		color: #000;
		outline: 1px solid #000;
	}
}

/* =========================================================================
 * 30. CLIENT REVISIONS — 2026-09-02
 *
 * Banner heroes on the ministry and story singles, full-width justified
 * hero copy, the About / Contact rhythm the client measured, contact rows
 * with icons, the image lightbox, the "thank you" modal after a submission,
 * and the submission-form heading gap.
 *
 * Everything lands in this one section so the diff reads as one change.
 * Where a rule has to beat something declared EARLIER in this file it says
 * so and by how much — the bracketed numbers are specificities — because
 * the alternative, editing the earlier rule in place, would smear this
 * revision back through eight sections and hide what changed.
 * ========================================================================= */

/* -------------------------------------------------------------------------
 * 30.1  Hero — "banner" mode (templates/hero.php, $image_mode = 'banner').
 *
 * Cover mode (§4) stretches the featured image behind the text and darkens
 * it with a scrim. That is right for a region's landscape photograph and
 * wrong for a ministry's featured image or a story's cover: those are
 * PICTURES — people, a building, a printed poster — and a crop through the
 * middle of a face with white type over it was the client's complaint.
 *
 * Banner mode shows the whole image, uncropped, above a light band that
 * carries the breadcrumbs, the title and the excerpt. The image is never
 * cut: it sits `object-fit: contain` inside a box that is the full hero
 * width and no taller than 80vh, and the box is painted with a blurred,
 * dimmed copy of the same image, so a portrait or a square logo is framed
 * by its own colours rather than by empty white either side.
 *
 * .tami__hero (§4) is (0,1,0) and sets the dark field, the white type
 * and the background image; every banner rule below carries `.tami` in
 * front of it, so (0,2,0) and up wins without touching §4. Region, country
 * and city heroes never carry the modifier and are untouched.
 * ------------------------------------------------------------------------- */

.tami .tami__hero--banner {
	/* The SHORTHAND, deliberately: it resets background-image as well. §4
	   and the --has-image rule both paint --tami-hero-image on the
	   section, and in banner mode the media box paints it instead. */
	background: var(--tami-color-surface, #fff);
	color: var(--tami-ink, #1a1a1a);
}

/* No scrim: there is no photograph behind the text to darken. The accent
   hairline (::after) stays — it is what hands the hero off to the page. */
.tami .tami__hero--banner::before {
	display: none;
}

/* A bannered hero with NO image is just the light band. A hairline along
   its top edge is what stops it reading as a page that has lost its hero.
   Inset shadow rather than a border so the box does not grow, and top-only
   is direction-neutral. */
.tami .tami__hero--banner:not(.tami__hero--has-image) {
	box-shadow: inset 0 1px 0 var(--tami-line, #e3e6e8);
}

/* The media box: full hero width, clips the oversized wash below. */
.tami .tami__hero-media {
	background: #101815;
	inline-size: 100%;
	overflow: hidden;
	position: relative;
}

/* The wash — the same image, blurred and dimmed. Oversized by 6% on every
   side so the soft edge blur() leaves at a box boundary is clipped away by
   the media box instead of showing as a pale frame. */
.tami .tami__hero-media::before {
	background-image: var(--tami-hero-image, none);
	background-position: 50% 50%;
	background-repeat: no-repeat;
	background-size: cover;
	content: "";
	filter: blur(28px) saturate(1.05);
	inset: -6%;
	opacity: 0.55;
	position: absolute;
}

/*
 * The picture itself. NEVER cropped and never wider than the hero: the box
 * is the full hero width, its height follows the image's own ratio up to
 * min(80vh, 900px), and past that ceiling `object-fit: contain` shrinks the
 * picture inside the box — so a very tall portrait sits centred on the wash
 * with the wash showing either side, and a panorama simply spans. The svh
 * line is the progressive twin of the vh one (§4 explains the iOS reason)
 * and MUST stay second.
 *
 * SPECIFICITY. §20.2 rounds and shadows every plugin image through
 * `.tami img:not(.tami__logo-image):not(.tami__leader-image)`,
 * which is (0,3,1). A banner image is edge to edge, so a radius would show
 * the wash through two rounded corners and a drop shadow would draw a grey
 * smear under it. Four classes — (0,4,0) — is the least that beats it.
 */
.tami .tami__hero--banner .tami__hero-media .tami__hero-image {
	block-size: auto;
	border-radius: 0;
	box-shadow: none;
	display: block;
	inline-size: 100%;
	margin-inline: auto;
	max-block-size: min(80vh, 900px);
	max-block-size: min(80svh, 900px);
	object-fit: contain;
	position: relative;
}

/*
 * The band. The tall cover-mode floor — §4's min-block-size, its 9svh
 * padding pair, the extra height §4's wide query adds past 1600px — exists
 * to give a photograph room; in banner mode the photograph has its own box,
 * so the band is exactly as tall as breadcrumbs + title + excerpt need.
 * (0,3,0) beats the (0,1,0) restatements of .tami__hero-inner in §4,
 * §21.4 and §24. No transition is involved anywhere in banner mode, so
 * prefers-reduced-motion has nothing to neutralise.
 */
.tami .tami__hero--banner .tami__hero-inner {
	min-block-size: 0;
	padding-block: clamp(1.25rem, 3vw, 2rem);
}

/* No photograph to anchor the title against, so the 2rem push-down §4
   gives the H1 is halved; the type takes the heading ink. */
.tami .tami__hero--banner .tami__hero-title {
	color: var(--tami-ink, #1a1a1a);
	padding-block-start: var(--tami-step-3, 1rem);
}

.tami .tami__hero--banner .tami__hero-desc,
.tami .tami__hero--banner .tami__hero-blurb {
	color: var(--tami-body-ink, #2b2b2b);
}

/* §27.6 inherits the tagline's colour from the hero and dims it with
   opacity; on a light band the muted ink at full opacity is the same idea
   at a readable 4.9:1 instead of a dimmed near-black. */
.tami .tami__hero--banner .tami__hero-tagline {
	color: var(--tami-muted-ink, #5f6b6d);
	opacity: 1;
}

/*
 * Breadcrumbs on the light band. §5 paints them in translucent white and
 * §20.3 lets an administrator recolour them; the administrator's setting is
 * kept as the FIRST fallback in every rule here, so a configured breadcrumb
 * colour still wins on a banner and only the white default is replaced.
 * §5's :hover on the item (0,2,0) painted the whole <li> white; on a banner
 * that state moves to the link, which is the thing actually hovered.
 */
.tami .tami__hero--banner .tami__breadcrumbs,
.tami .tami__hero--banner .tami__breadcrumb-item,
.tami .tami__hero--banner .tami__breadcrumb-sep,
.tami .tami__hero--banner .tami__breadcrumbs a {
	color: var(--tami-color-breadcrumb, var(--tami-muted-ink, #5f6b6d));
}

.tami .tami__hero--banner .tami__breadcrumb-current,
.tami .tami__hero--banner .tami__breadcrumbs a:hover,
.tami .tami__hero--banner .tami__breadcrumbs a:focus-visible {
	color: var(--tami-color-breadcrumb-current, var(--tami-color-breadcrumb, var(--tami-ink, #1a1a1a)));
}

/* §15 switches the hero's focus ring to WHITE for the dark scrim; on the
   light band white is invisible, so the ink ring comes back. (0,3,1)
   against §15's (0,2,1). */
.tami .tami__hero--banner a:focus-visible,
.tami .tami__hero--banner button:focus-visible,
.tami .tami__hero--banner [tabindex]:focus-visible {
	outline: 3px solid var(--tami-accent-ink);
	outline-offset: 3px;
}

@media print {
	/* The wash is a blurred smear of toner; the picture itself prints. */
	.tami .tami__hero-media::before {
		display: none;
	}

	.tami .tami__hero-media {
		background: none;
	}

	.tami .tami__hero--banner .tami__hero-inner {
		padding-block: 0;
	}
}

/* -------------------------------------------------------------------------
 * 30.2  Hero excerpt and blurb — full width, justified, on EVERY hero.
 *
 * The 62ch measure (§4) and the 56ch ultra-wide cap (§22) were right for a
 * one-line strapline and wrong for the paragraph the client actually writes
 * there: at 62ch the excerpt stopped two-thirds of the way across the band
 * and left the last third empty. It now spans the band, is justified with
 * hyphenation like the body copy (§27.2), and carries 10px of inline
 * padding so its edges sit just inside the band's.
 *
 * (0,2,0) against §4's and §22's (0,1,0). §27.2 already justifies the blurb
 * at this specificity; it is restated so this section is the one place the
 * hero copy's alignment is decided.
 * ------------------------------------------------------------------------- */

.tami .tami__hero-desc,
.tami .tami__hero-blurb {
	hyphens: auto;
	-webkit-hyphens: auto;
	max-inline-size: none;
	overflow-wrap: break-word;
	padding-inline: 10px;
	text-align: justify;
}

/* The last line of a justified block is start-aligned by spec; Divi sets
   text-align-last on some containers, so it is pinned here as §27.2 does
   for the body copy. */
.tami .tami__hero-desc,
.tami .tami__hero-blurb p {
	text-align-last: start;
}

/* In banner mode the headline (badge + H1 + tagline) and the breadcrumbs
   take the same 10px, so the logo's edge, the title's edge and the
   excerpt's edge line up down the band. */
.tami .tami__hero--banner .tami__hero-headline,
.tami .tami__hero--banner .tami__breadcrumbs {
	padding-inline: 10px;
}

/* -------------------------------------------------------------------------
 * 30.3  "About" and "Contact" — the 15px the client asked for.
 *
 * The ask is exact: 15px between the About heading and its description,
 * 15px between the Contact heading and its list. "Between" is measured from
 * the bottom edge of the heading's accent underline to the top edge of the
 * first line box — the two edges DevTools draws — not to the ink of the
 * first capital letter, which sits a further ~8px down at the default type
 * and moves with every font.
 *
 * Measured on the live ministry page at 1280px before this change: the
 * About heading's box bottom and the first <p>'s box top were the SAME
 * pixel (0px), because nothing set a margin on either; the Contact heading
 * was likewise flush with its list, whose first row then added 5.6px of
 * its own padding. Three things therefore make the gap, and all three are
 * pinned here:
 *
 *   1. the heading's underline padding (0.42em, §6) — restated, because a
 *      Divi phone rule outranks §6 and zeroes it (see just below);
 *   2. the heading's margin-block-end, which IS the 15px;
 *   3. nothing on the other side — the prose's first child and the first
 *      contact row give up their top margin and padding.
 * ------------------------------------------------------------------------- */

/*
 * FOUND WHILE MEASURING, and fixed for every section title, not only these
 * two. Divi's critical CSS carries `@media (max-width: 479px) { .et_pb_post
 * h2 { font-size: 16px; padding-bottom: 0 } }` at (0,1,1). Every plugin
 * page renders inside Divi's article.et_pb_post, so on a small phone that
 * rule beat §6's `.tami__section-title` (0,1,0) and every section title —
 * "Ministry Leadership", "Stories from this Ministry", the region page's
 * heads — dropped to body size with the accent underline sitting on the
 * letters. Measured at 375px: 16px / 0px before, 24.1px / 10.1px after. The
 * two declarations are §6's own, restated one class higher; the token and
 * the fluid clamp are untouched.
 */
.tami .tami__section-title {
	font-size: var(--tami-size-h2, clamp(1.5rem, 1.25rem + 1.1vw, 2.125rem));
	padding-block-end: 0.42em; /* countering Divi's `@media (max-width: 479px) .et_pb_post h2` */
}

.tami .tami__about .tami__section-title,
.tami .tami__contact .tami__section-title {
	margin-block-end: 15px;
	padding-block-end: 0.42em;
}

.tami .tami__about .tami__prose {
	margin-block-start: 0;
}

.tami .tami__about .tami__prose > :first-child {
	margin-block-start: 0;
	padding-block-start: 0;
}

.tami .tami__contact .tami__contact-list {
	margin-block-start: 0;
}

/* (0,4,0): §27.11 pads every row top and bottom at (0,2,0). */
.tami .tami__contact .tami__contact-item:first-child {
	padding-block-start: 0;
}

/*
 * "As per width of the section". The 72ch measure on .tami__prose (§3)
 * is a readability ceiling for a bare column; inside the About card and the
 * story article the container IS the measure the client set, and a
 * paragraph that stops at 72ch inside a wider card looks unfinished. The
 * cap is lifted on exactly those two, they justify with hyphenation, and
 * the same 10px inline padding as the hero copy keeps their edges just
 * inside their surface. The standfirst carries .tami__prose itself
 * (story-single.php) so the story rule reaches it; it is named as well in
 * case a theme override drops the shared class. (0,3,0) against §3's
 * (0,1,0) and §27.2's (0,2,0).
 */
.tami .tami__about .tami__prose,
.tami .tami__single--story .tami__prose,
.tami .tami__single--story .tami__standfirst {
	hyphens: auto;
	-webkit-hyphens: auto;
	max-inline-size: none;
	padding-inline: 10px;
	text-align: justify;
}

/* -------------------------------------------------------------------------
 * 30.4  Contact rows — icon, label, value.
 *
 * ministry-single.php now leads every row with a small inline SVG (a map
 * for the address, an envelope, a handset, a globe). Three grid columns: a
 * fixed 1.5rem icon slot, the label at its own width, the value taking the
 * rest. The children are placed by CLASS rather than by source order, so a
 * row without an icon — a theme override of the template that predates
 * them — still lands its label and value in the right columns and only
 * leaves the icon slot empty.
 *
 * Mobile first (§0): on a small phone the label and value stack in the
 * second column beside the icon, and from sm (30rem) the value moves out to
 * a third column. (0,3,0) against §27.11's (0,2,0).
 * ------------------------------------------------------------------------- */

.tami .tami__contact .tami__contact-item {
	align-items: start;
	column-gap: 0.65rem;
	display: grid;
	grid-template-columns: 1.5rem minmax(0, 1fr);
	row-gap: 0.15rem;
}

.tami .tami__contact .tami__contact-icon {
	align-items: center;
	block-size: 1.5rem;
	color: var(--tami-accent-ink);
	display: inline-flex;
	grid-column: 1;
	grid-row: 1;
	inline-size: 1.5rem;
	justify-content: center;
}

/* Sized here rather than trusting the width/height attributes alone, so a
   theme rule on `svg` cannot inflate it to the cell. */
.tami .tami__contact .tami__contact-icon svg {
	block-size: 20px;
	flex: none;
	inline-size: 20px;
}

.tami .tami__contact .tami__contact-label {
	grid-column: 2;
	/* The same line box as the icon, so the two centre on each other. */
	line-height: 1.5rem;
	min-inline-size: 5.5rem;
}

.tami .tami__contact .tami__contact-value {
	grid-column: 2;
	line-height: 1.5rem;
}

/* sm (480px) — the value earns its own column. */
@media (min-width: 30rem) {
	.tami .tami__contact .tami__contact-item {
		grid-template-columns: 1.5rem auto minmax(0, 1fr);
	}

	.tami .tami__contact .tami__contact-value {
		grid-column: 3;
	}
}

/* The postal address keeps its line breaks (nl2br) and reads as a block of
   text, not as the italic small print <address> is by UA default. */
.tami .tami__contact .tami__address-body {
	font-style: normal;
	line-height: 1.7;
	margin: 0;
}

/*
 * The Contact block is a surface card, as it was (§14). Now that it sits
 * directly under the facts row rather than at the foot of the profile, its
 * 4rem section gap becomes the module gap the About and facts cards keep
 * between themselves, and it takes their border, radius, shadow and
 * padding (§27.9, §27.10) so the three read as one family. (0,3,0) against
 * §14's (0,1,0).
 */
.tami .tami__single--ministry .tami__contact {
	border: 1px solid var(--tami-line, rgb(0 0 0 / 10%));
	border-radius: 10px;
	box-shadow: 0 1px 3px rgb(16 24 32 / 8%);
	margin-block: 0 var(--tami-space-module, 1.5rem);
	padding: clamp(1.15rem, 3.5vw, 2rem);
}

/* -------------------------------------------------------------------------
 * 30.5  The image lightbox (assets/js/tami.js, module `lightbox`).
 *
 * The trigger is an <a class="tami__lightbox-link" data-tami-lightbox>
 * wrapped around the ministry logo (hero badge and facts row) and every
 * leader photo. It must change NOTHING about the image it wraps. The badge
 * and the facts column size the <img> as their flex item, so there the
 * anchor becomes a block that fills the slot the image used to fill and
 * the image's own rules stand; the leader photo is a 128px circle that
 * clips its image (§27.12), so there the anchor fills the circle. Without
 * JavaScript the anchor is a plain link to the full-size file, which is a
 * perfectly good fallback.
 *
 * The overlay is appended to <body>, OUTSIDE the page's .tami root, and
 * therefore carries .tami itself so it inherits the tokens and the
 * direction firewall. That also means it inherits §27.1's page padding and
 * the §1 root box — hence every overlay rule is (0,2,0) or more and resets
 * them.
 * ------------------------------------------------------------------------- */

.tami .tami__lightbox-link {
	cursor: zoom-in;
	display: inline-block;
}

.tami .tami__lightbox-link img {
	display: block;
}

/* Hero badge (§27.5): fill the 84/104px slot, the img rule does the rest. */
.tami .tami__hero-badge .tami__lightbox-link {
	block-size: 100%;
	display: block;
	inline-size: 100%;
}

/* Facts row (§27.9): the same 180px cap the img carries, centred by the
   column's flex alignment exactly as the bare img was. */
.tami .tami-ministry__facts-logo .tami__lightbox-link {
	display: block;
	inline-size: 100%;
	max-inline-size: 180px;
}

/* Leader portrait (§27.12): the anchor IS the inside of the circle. */
.tami .tami__leader-photo .tami__lightbox-link {
	block-size: 100%;
	border-radius: 50%;
	display: block;
	inline-size: 100%;
	overflow: hidden;
}

/*
 * The portrait anchor's OWN focus ring can never be seen. §15 draws every
 * ring 3px outside the control's box, and this control's box is the whole
 * inside of a circle that clips (`overflow: hidden` on the span, §11 and
 * §27.12) — the ring lands entirely in the clipped region. Before C4 the
 * photo was not focusable, so nothing was lost; now it is a real link in
 * the tab order, and a link whose focus is invisible fails WCAG 2.4.7 on
 * every leader card. §27.12's :focus-within lift on the card is not a
 * substitute: it is gated on a fine pointer and reduced to a shadow under
 * prefers-reduced-motion.
 *
 * So the ring is drawn on the SPAN, which nothing clips (the card sets no
 * overflow), in the ink, weight and offset §15 gives every other control —
 * outline follows border-radius, so it is a circle around the circle.
 * :has(> …:focus-visible) keeps the browser's own heuristic: a ring after
 * Tab, none after a mouse click. (0,4,0), but nothing else sets outline on
 * the span. A browser without :has() takes the :focus-within rule instead,
 * which also rings on a mouse click; that ring is under the viewer the
 * click opens, a small price for the ring never being absent.
 */
.tami .tami__leader-photo:has(> .tami__lightbox-link:focus-visible) {
	outline: 3px solid var(--tami-accent-ink);
	outline-offset: 3px;
}

@supports not selector(:has(> .tami__lightbox-link)) {
	.tami .tami__leader-photo:focus-within {
		outline: 3px solid var(--tami-accent-ink);
		outline-offset: 3px;
	}
}

/* §23 thickens every §15 ring to 4px; this is §15's ring drawn one box
   out, and keeps that promise. Two rules, not one list: a browser without
   :has() drops a whole selector list that contains it. */
@media (prefers-contrast: more) {
	.tami .tami__leader-photo:has(> .tami__lightbox-link:focus-visible) {
		outline-width: 4px;
	}

	.tami .tami__leader-photo:focus-within {
		outline-width: 4px;
	}
}

.tami.tami__lightbox {
	align-items: center;
	background: rgb(9 14 11 / 88%);
	display: flex;
	inset: 0;
	justify-content: center;
	/* The §1 / §27.1 root box the .tami class brings with it. */
	margin: 0;
	padding: clamp(1rem, 4vw, 3rem);
	position: fixed;
	/* Above Divi's fixed header and its slide-in mobile menu (99999). */
	z-index: 100000;
}

.tami.tami__lightbox .tami__lightbox-figure {
	align-items: center;
	display: flex;
	flex-direction: column;
	gap: 0.75rem;
	margin: 0;
	max-block-size: 92vh;
	max-inline-size: min(96vw, 1400px);
}

/* (0,4,0): §20.2's image rule is (0,3,1) and would otherwise put its
   resting card shadow under the full-size picture. */
.tami.tami__lightbox .tami__lightbox-figure .tami__lightbox-image {
	block-size: auto;
	border-radius: 10px;
	box-shadow: 0 20px 60px rgb(0 0 0 / 55%);
	inline-size: auto;
	max-block-size: 82vh;
	max-inline-size: 100%;
	object-fit: contain;
}

.tami.tami__lightbox .tami__lightbox-caption {
	color: #fff;
	font-size: 0.95rem;
	margin: 0;
	max-inline-size: 70ch;
	padding: 0;
	text-align: center;
}

.tami.tami__lightbox .tami__lightbox-close {
	align-items: center;
	background: rgb(255 255 255 / 12%);
	border: 0;
	border-radius: 50%;
	color: #fff;
	cursor: pointer;
	display: inline-flex;
	font-family: inherit;
	font-size: 1.75rem;
	inset-block-start: 1rem;
	inset-inline-end: 1rem;
	justify-content: center;
	line-height: 1;
	margin: 0;
	/* WCAG 2.5.5 target, and the one control the dialog has. */
	min-block-size: 44px;
	min-inline-size: 44px;
	padding: 0;
	position: absolute;
	transition: background-color var(--tami-dur, 220ms) var(--tami-ease, ease-out);
}

.tami.tami__lightbox .tami__lightbox-close:hover {
	background: rgb(255 255 255 / 24%);
}

/* White ring on the dark backdrop: the ink ring §15 gives every button is
   about 1.4:1 here, the same reason the hero's ring is white. (0,4,0)
   against §15's (0,2,1). */
.tami.tami__lightbox .tami__lightbox-close:focus-visible {
	outline: 3px solid #fff;
	outline-offset: 3px;
}

/*
 * Fade-in without @keyframes (rule 3 of this file's header). The overlays
 * transition their opacity from an @starting-style of 0, which is the CSS
 * way to animate an element's arrival in the DOM with no class juggling in
 * the script. A browser without @starting-style simply shows them — never a
 * stuck-invisible overlay — and reduced-motion users get no fade at all.
 * The base sheet's reduced-motion rule covers `.tami *` (descendants),
 * not the .tami root the overlay IS, so it is restated here.
 */
.tami.tami__lightbox,
.tami.tami__modal {
	opacity: 1;
	transition: opacity var(--tami-dur, 220ms) var(--tami-ease, ease-out);
}

@starting-style {
	.tami.tami__lightbox,
	.tami.tami__modal {
		opacity: 0;
	}
}

@media (prefers-reduced-motion: reduce) {
	.tami.tami__lightbox,
	.tami.tami__modal,
	.tami.tami__lightbox .tami__lightbox-close {
		transition: none;
	}
}

/*
 * THE THIRD SANCTIONED OUT-OF-SCOPE RULE (after §17 and §20.4). The page
 * cannot be stopped from scrolling behind a fixed overlay from inside
 * .tami; only <body> can do that. Both classes are set by our own script
 * for exactly as long as an overlay is open and removed with it, so outside
 * those moments not one declaration applies — the same gate §17 uses.
 */
body.tami-lightbox-open,
body.tami-modal-open {
	overflow: hidden;
}

/* -------------------------------------------------------------------------
 * 30.6  The "thank you" modal (assets/js/tami-form.js, after Save draft
 *       or Submit for review).
 *
 * Same overlay pattern as the lightbox, one layer higher, over a light
 * dialog: a thank-you must never be hidden behind a picture somebody left
 * open. The dialog scrolls inside itself on a short phone rather than
 * letting its button fall below the fold.
 * ------------------------------------------------------------------------- */

.tami.tami__modal {
	align-items: center;
	background: rgb(9 14 11 / 72%);
	display: flex;
	inset: 0;
	justify-content: center;
	margin: 0;
	padding: clamp(1rem, 4vw, 3rem);
	position: fixed;
	z-index: 100001;
}

.tami.tami__modal .tami__modal-dialog {
	background: var(--tami-color-surface, #fff);
	border-radius: 14px;
	box-shadow: 0 24px 64px rgb(0 0 0 / 35%);
	color: var(--tami-ink);
	inline-size: 100%;
	max-block-size: 92vh;
	max-inline-size: 34rem;
	overflow: auto;
	padding: clamp(1.5rem, 4vw, 2.5rem);
	position: relative;
	text-align: center;
}

/* §27.2 start-aligns every h2 under .tami at (0,1,1); the title of a
   centred dialog is the one heading that must not obey it. (0,3,0). The
   type is the h2 token, as the section titles use. */
.tami.tami__modal .tami__modal-title {
	color: var(--tami-ink);
	font-family: var(--tami-font-heading, inherit);
	font-size: var(--tami-size-h2, clamp(1.5rem, 1.25rem + 1.1vw, 2.125rem));
	font-weight: var(--tami-weight-heading, 700);
	letter-spacing: -0.01em;
	line-height: 1.18;
	margin-block: 0 0.75rem;
	padding: 0;
	text-align: center;
	text-wrap: balance;
}

.tami.tami__modal .tami__modal-body {
	color: var(--tami-body-ink);
	font-size: 1.05rem;
	line-height: 1.6;
	margin-block: 0 1rem;
	padding: 0;
}

.tami.tami__modal .tami__modal-countdown {
	color: var(--tami-muted-ink);
	font-size: 0.95rem;
	/* The number ticks down every second; tabular figures stop the line
	   jittering as "10" becomes "9". */
	font-variant-numeric: tabular-nums;
	margin-block: 0 1.25rem;
	padding: 0;
}

.tami.tami__modal .tami__modal-actions {
	align-items: center;
	display: flex;
	flex-wrap: wrap;
	gap: 0.75rem;
	justify-content: center;
	margin: 0;
	padding: 0;
}

/*
 * There is deliberately NO rule for `.tami__modal-close`. When the form
 * script has no region page to redirect to, its dismiss control is a
 * labelled `<button class="tami__button tami__modal-close">` INSIDE
 * .tami__modal-actions: the second class is the script's hook, and the
 * pill it wears is .tami__button (0,1,0), the same one the "Go there
 * now" link wears in the same row. An earlier draft of this section keyed a
 * corner "×" treatment — absolute, 50% radius, zero padding, 1.5rem type —
 * on that class; at (0,3,0) it out-ranked the pill and pinned the word
 * "Close" over the title while the actions row stood empty. Any corner
 * control this dialog ever grows must carry a class of its own.
 */

/* -------------------------------------------------------------------------
 * 30.7  Submission form — 30px from the heading to the first fieldset.
 *
 * Measured on the rendered form at 1280px before this change: the H1's
 * margin (2rem = 32px) plus Divi's `h1 … { padding-bottom: 10px }`, then
 * TWO empty <p role="status"> live regions that are each still a flex item
 * of the form's 2rem-gap column — one of them 1.4em tall by design, because
 * §26 reserves the line — put the fieldset's border well over 100px below
 * the heading.
 *
 * The heading keeps exactly 30px, and the two live regions collapse while
 * they are empty. NOT with display:none — a live region that is
 * display:none when its text arrives is not announced by most screen
 * readers, because it was not in the accessibility tree before the change.
 * Instead each empty region loses its reserved height and pulls the
 * column's gap back with a negative margin equal to it, so it stays in the
 * tree at zero height and costs nothing; the moment it has text it is a
 * normal flex item again. The layout shift §26 was avoiding is accepted
 * here: the client would rather have the gap right than the line reserved.
 * ------------------------------------------------------------------------- */

.tami.tami--submission-form .tami__page-title {
	margin-block-end: 30px;
	padding-block-end: 0; /* countering Divi's `h1, h2, h3 … { padding-bottom: 10px }` */
}

.tami.tami--submission-form .tami__status:empty,
.tami.tami--submission-form .tami__autosave:empty {
	margin-block: 0 calc(-1 * var(--tami-space-row, 2rem));
	min-block-size: 0;
	padding: 0;
}

/* §26 resets fieldset margins already; restated so the 30px cannot be
   undone by a theme rule on `fieldset`. */
.tami.tami--submission-form .tami__form > .tami__fieldset:first-of-type {
	margin-block-start: 0;
}

/* -------------------------------------------------------------------------
 * 31.  REVIEW QUEUE ON A PHONE — the row becomes a card
 *
 * WHICH REVIEW QUEUE. This is the FRONT-END one: the `[tami_review_queue]`
 * shortcode, `templates/review-queue.php`, `<table class="tami__table">`.
 * The plugin also has an admin queue at Admin\ReviewQueue.php built on
 * WP_List_Table, and that one is fine on a phone — core hides its secondary
 * columns behind a "Show more details" toggle. The two are unrelated, share a
 * name, and confusing them has already cost one wrong fix; nothing here
 * touches the admin table.
 *
 * WHAT WAS BROKEN. Six columns do not fit a handset, so the wrapper scrolled
 * sideways: §0 gives the table `min-inline-size: 38rem` and the wrap
 * `overflow-x: auto`, which is the WCAG 1.4.10 exception for a data table,
 * taken deliberately. Measured at a true 390px viewport: the wrap is 351px
 * against a 762px table, so the Actions cell — the note box and the Approve,
 * Reject and Request-changes buttons — begins 192px past the visible edge,
 * with nothing on screen to say it is there. 54% of every row was off-stage.
 * A reviewer on a phone could read the queue and could not act on it, which
 * is the one thing the screen exists for.
 *
 * A horizontal scroll is a poor answer to that even when it is discoverable.
 * The skin's earlier mitigation pinned the title cell so the row could be
 * read while scrolling; it made the scroll navigable, it did not make it
 * unnecessary. This does: below 48rem the row stops being a row.
 *
 * WHAT THIS DOES. The header row is hidden, each `<tr>` becomes a bordered
 * card, each cell becomes a full-width block, and the column name comes back
 * as `content: attr(data-label)` from the attribute the template now writes.
 * Nothing is off-screen, so nothing scrolls: the wrap's `overflow-x` and the
 * table's `min-inline-size` are both released here and handed back at 48rem.
 *
 * THE TRADE-OFF, STATED. Changing a table's display drops it out of the table
 * formatting context, and with it the row/column semantics an assistive
 * technology would announce. That is the known cost of this pattern and it is
 * accepted here: on a 390px screen a six-column grid was not conveying
 * relationships either, and the per-cell label carries the same meaning in a
 * form the reader can actually reach. Operability was the failure; semantics
 * were the price, and it is the cheaper of the two.
 *
 * `[data-label]` guards the generated content so the title and actions cells
 * — which have no label, being the card's heading and its controls — do not
 * render an empty box before themselves.
 *
 * Phone-first, matching this sheet: the card IS the default and the table is
 * restored at `min-width: 48rem`, the tier the queue's other rules already
 * use. Logical properties throughout, so Farsi mirrors with no RTL sheet.
 * ------------------------------------------------------------------------- */

.tami.tami--review-queue .tami__table-wrap {
	overflow-x: visible;
}

.tami.tami--review-queue .tami__table {
	min-inline-size: 0;
}

.tami.tami--review-queue .tami__table thead {
	display: none;
}

.tami.tami--review-queue .tami__row {
	border: 1px solid var(--tami-line, #e3e6e8);
	display: block;
	margin-block-end: var(--tami-step-3, 1rem);
	padding: var(--tami-step-2, 0.625rem);
}

.tami.tami--review-queue .tami__cell {
	border-block-end: 0;
	display: block;
	padding-block: 0.25rem;
	padding-inline: 0;
}

.tami.tami--review-queue .tami__cell[data-label]::before {
	color: var(--tami-muted-ink, #5f6b6d);
	content: attr(data-label);
	display: block;
	font-size: 0.75rem;
	letter-spacing: 0.06em;
	text-transform: uppercase;
}

/* A story with no ministry or no region would otherwise print a label with
   nothing under it — the card reads "MINISTRY" followed by a gap, which looks
   like a rendering fault rather than an absent value. An empty cell drops its
   label and collapses. `:empty` is exact here because the template escapes an
   empty string into the cell, leaving no text node behind; a cell with a value
   is unaffected. */
.tami.tami--review-queue .tami__cell[data-label]:empty {
	padding-block: 0;
}

.tami.tami--review-queue .tami__cell[data-label]:empty::before {
	content: none;
}

/* The story title is the card's heading, so it carries the weight the hidden
   column header used to. */
.tami.tami--review-queue .tami__cell--title {
	font-size: 1.0625rem;
	padding-block-end: var(--tami-step-2, 0.625rem);
}

/* The controls are the point of the card, so they get a rule above them and
   the full width of it. §0's 13rem minimum is a table-column measure and
   means nothing to a block. */
.tami.tami--review-queue .tami__cell--actions {
	border-block-start: 1px solid var(--tami-line, #e3e6e8);
	margin-block-start: var(--tami-step-2, 0.625rem);
	min-inline-size: 0;
	padding-block-start: var(--tami-step-2, 0.625rem);
}

/* From 48rem the six columns fit and the table comes back exactly as §0 left
   it. Every property released above is restored here rather than left to
   cascade, so the desktop queue does not depend on which rules happened to
   be inherited. */
@media (min-width: 48rem) {

	.tami.tami--review-queue .tami__table-wrap {
		overflow-x: auto;
	}

	.tami.tami--review-queue .tami__table {
		min-inline-size: 38rem;
	}

	.tami.tami--review-queue .tami__table thead {
		display: table-header-group;
	}

	.tami.tami--review-queue .tami__row {
		border: 0;
		display: table-row;
		margin-block-end: 0;
		padding: 0;
	}

	.tami.tami--review-queue .tami__cell {
		border-block-end: 1px solid var(--tami-line, #e3e6e8);
		display: table-cell;
		padding-block: 0.6rem;
		padding-inline: 0.7rem;
	}

	.tami.tami--review-queue .tami__cell[data-label]::before {
		content: none;
	}

	.tami.tami--review-queue .tami__cell--title {
		font-size: inherit;
		padding-block-end: 0.6rem;
	}

	.tami.tami--review-queue .tami__cell--actions {
		border-block-start: 0;
		margin-block-start: 0;
		min-inline-size: 13rem;
		padding-block-start: 0.6rem;
	}
}
