/*
 * eKlektiv directory pattern (Kevin, 11 Sep 2026).
 *
 * Listora's search-and-filter layout (/listings) is the house pattern for the
 * Spaces directory and Events: a rounded search bar with a teal Search button,
 * one row of pill chips that scrolls sideways, a quiet "Filters" toggle with a
 * count, and a white filter panel. The values below are Listora 1.7.0's rendered
 * ones on this site, so the three directories read as one family. One change:
 * Listora's pale uppercase panel labels (about 2.4:1 on white) are darkened here
 * to about 4.8:1.
 */
:root {
	/* Declared 13 Sep 2026 for the dark-mode pass. Three of these
	   (--ek-dir-line, --ek-dir-muted, --ek-dir-chip) were already being USED
	   across the Upcoming, queue and share styles as `var( --ek-dir-line,
	   #E4E7EC )` and friends — written token-ready but never actually declared,
	   so every one of them silently fell back to its light literal and no theme
	   could reach them. --ek-dir-surface and --ek-dir-heading replace raw
	   #FFFFFF backgrounds and #101828 headings for the same reason. */
	--ek-dir-surface:       #FFFFFF;
	--ek-dir-sticker:       rgba( 255, 255, 255, 0.94 );
	--ek-dir-sticker-ink:   #101828;
	--ek-dir-line:          #E4E7EC;
	--ek-dir-muted:         #667085;
	--ek-dir-chip:          #F2F4F7;
	--ek-dir-heading:       #101828;
	/* --ek-teal-text was the last `var( x, literal )` with no declaration
	   behind it: the date sticker's month label. Same class of bug as
	   --ek-dir-line above. */
	--ek-teal-text:         #0A7A6F;
	/* Split out 13 Sep 2026. --ek-teal-text was doing two jobs: ELEVEN uses as
	   `color` (ink, which must lift on a dark ground) and FIVE as `background`
	   (a filled control carrying white text, which must NOT). Lifting the one
	   token turned the "Count me in" buttons into mint with white type at
	   1.64:1 — the same split-by-role trap as `#FFFFFF` earlier in this sheet,
	   walked straight into a second time. Fills never change with the theme. */
	--ek-teal-fill:         #0A7A6F;
	--ek-dir-danger:        #B42318;
	--ek-dir-warn:          #B54708;

	--ek-dir-border:        #E3E3E3;
	--ek-dir-chip-border:   #E6E6E6;
	--ek-dir-shadow:        0 1px 2px rgba(0, 0, 0, 0.04), 0 2px 4px rgba(0, 0, 0, 0.04);
	--ek-dir-radius-bar:    20px;
	--ek-dir-radius-panel:  14px;
	--ek-dir-radius-ctrl:   6px;
	--ek-dir-teal:          #0B8478;
	--ek-dir-teal-hover:    #0A7A6F;
	--ek-dir-teal-wash:     rgba(11, 132, 120, 0.10);
	--ek-dir-teal-ink:      #07564E;
	--ek-dir-ink:           #404855;
	--ek-dir-strong:        #1B1F24;
	--ek-dir-label:         #6B7280;
	--ek-dir-hint:          #5C6470;
	--ek-dir-hover:         #F4F6F8;
	--ek-dir-search-icon:   url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='18' height='18' viewBox='0 0 24 24' fill='none' stroke='%23808891' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='7'/%3E%3Cpath d='m20 20-3.5-3.5'/%3E%3C/svg%3E");
}

/* ══ Spaces directory (/spaces/) ═══════════════════════════════════════════
   BuddyNext 1.1.7 templates/spaces/directory.php, restyled; companion
   Chrome/SpacesDirectory.php adds the Search button and the Filters row.
   Order: heading, search bar, chips + sort, Filters row, results. The Filters
   row is printed right after the search strip, so it is moved here. */
.bn-sd-stack { gap: 14px; }
.bn-sd-stack > .bn-section-head   { order: -4; }
.bn-sd-stack > .bn-filter-strip   { order: -3; }
.bn-sd-stack > .bn-sd-filter-row  { order: -2; }
.bn-sd-stack > .ek-sd-tools       { order: -1; }

/* Search bar */
.bn-sd-stack > .bn-filter-strip {
	margin: 0;
	padding: 8px;
	background: var(--ek-dir-surface);
	border: 1px solid var(--ek-dir-border);
	border-radius: var(--ek-dir-radius-bar);
	box-shadow: var(--ek-dir-shadow);
	transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
.bn-sd-stack > .bn-filter-strip:focus-within {
	border-color: var(--ek-dir-teal);
	box-shadow: 0 0 0 3px var(--ek-dir-teal-wash), var(--ek-dir-shadow);
}
.bn-sd-stack > .bn-filter-strip .bn-filter-strip__form {
	flex: 1 1 auto;
	flex-wrap: nowrap;
	width: 100%;
	margin: 0;
	gap: 8px;
}
.bn-sd-stack > .bn-filter-strip .bn-filter-strip__form .bn-input {
	flex: 1 1 auto;
	width: auto;
	min-width: 0;
	height: 46px;
	padding: 0 12px 0 40px;
	border: 0;
	box-shadow: none;
	background: transparent var(--ek-dir-search-icon) no-repeat 12px 50%;
	font-size: 17px;
	color: #111111;
}
.bn-sd-stack > .bn-filter-strip .bn-filter-strip__form .bn-input:focus {
	outline: none;
	box-shadow: none;
}
.ek-sd-search-btn {
	flex: 0 0 auto;
	display: inline-flex;
	align-items: center;
	gap: 6px;
	min-height: 46px;
	padding: 0 18px;
	border: 1px solid var(--ek-dir-teal);
	border-radius: var(--ek-dir-radius-ctrl);
	background: var(--ek-dir-teal);
	color: #FFFFFF;
	font-family: inherit;
	font-size: 14px;
	font-weight: 600;
	cursor: pointer;
}
.ek-sd-search-btn:hover { background: var(--ek-dir-teal-hover); }
.ek-sd-search-btn:focus-visible { outline: 2px solid var(--ek-dir-teal-ink); outline-offset: 2px; }

/* Chips (All Spaces, My Spaces, categories) in one scrolling row, Sort beside */
.bn-sd-stack .bn-sd-filter-row {
	flex-direction: row;
	flex-wrap: nowrap;
	align-items: center;
	gap: 10px;
}
.bn-sd-stack .bn-sd-filter-row .bn-sd-chips {
	flex: 1 1 auto;
	min-width: 0;
	flex-wrap: nowrap !important;
	gap: 6px;
	padding: 2px 0;
	overflow-x: auto;
	overflow-y: hidden;
	scrollbar-width: none;
	scroll-snap-type: x proximity;
	-webkit-mask-image: linear-gradient(to right, #000 calc(100% - 28px), transparent);
	mask-image: linear-gradient(to right, #000 calc(100% - 28px), transparent);
}
.bn-sd-stack .bn-sd-chips::-webkit-scrollbar { display: none; }

/* Phones: the chips get the row to themselves (Kevin, 13 Sep 2026: "Sort is
   interfering with buttons").

   The single row above is right on a wide screen and wrong on a narrow one.
   Measured at 375px: the row is 351px, Sort is `flex-shrink: 0` at 167px, and
   the chip strip is left with **174px to scroll 1,743px of content across
   fourteen chips**. The first chip fits; the second ("Your groups", 109px) is
   sliced down the middle right where Sort begins. The two controls are
   actually 10px apart — it is the CLIPPING that reads as a collision, which is
   exactly what it looked like.

   Worth naming: BuddyNext's own rule for this row is `flex-wrap: wrap`
   (bn-spaces.css). The `nowrap` above is OURS, from the 11 Sep directory pass,
   and it is what removed the vendor's escape hatch at small widths. So this is
   not a vendor bug being worked around; it is our own rule being given the
   width condition it always needed.

   Sort drops beneath and sits right, where it reads as an ordering control
   rather than a fifteenth chip. The strip keeps its mask, because 1,743px still
   has to scroll in 351px — a chip cut at a hard edge reads as a fault, the same
   cut under a fade reads as "more this way". */
@media ( max-width: 700px ) {
	.bn-sd-stack .bn-sd-filter-row {
		flex-wrap: wrap;
		row-gap: 8px;
	}

	.bn-sd-stack .bn-sd-filter-row .bn-sd-chips {
		flex: 1 1 100%;
	}

	.bn-sd-stack .bn-sd-filter-row .bn-sd-sort {
		flex: 0 0 auto;
		margin-inline-start: auto;
	}
}
.bn-sd-stack .bn-sd-chips .bn-sd-chip {
	flex: 0 0 auto;
	min-height: 44px; /* Listora's chip height, and a comfortable tap target */
	gap: 6px;
	padding: 6px 14px;
	border: 1px solid var(--ek-dir-chip-border);
	border-radius: 9999px;
	background: transparent;
	color: var(--ek-dir-ink);
	font-size: 15px;
	font-weight: 500;
	box-shadow: none;
	scroll-snap-align: start;
}
/* Category icons as Listora's quiet line marks, not BuddyNext's filled colour
   swatches: a row of 12 coloured discs competes with the selected chip, which is
   the only state that should stand out. Category colour still reads on the cards. */
.bn-sd-stack .bn-sd-chips .bn-sd-chip__icon {
	width: 16px;
	height: 16px;
	background: transparent !important;
	color: inherit !important;
	box-shadow: none !important;
}
.bn-sd-stack .bn-sd-chips .bn-sd-chip__icon svg {
	width: 16px;
	height: 16px;
}
.bn-sd-stack .bn-sd-chips .bn-sd-chip::after { display: none; }
.bn-sd-stack .bn-sd-chips .bn-sd-chip:hover { background: var(--ek-dir-surface); border-color: #D6D6D6; }
.bn-sd-stack .bn-sd-chips .bn-sd-chip[aria-selected="true"] {
	background: var(--ek-dir-teal-wash) !important;
	border-color: var(--ek-dir-teal-edge, var(--ek-dir-teal)) !important;
	color: var(--ek-dir-teal-ink) !important;
	box-shadow: var(--ek-dir-shadow);
}
/* Sort in Listora's dropdown shape: 44px, 10px corners, the same light border
   as the bar, regular 13px text. It stays beside the chips rather than moving
   into a results bar of its own, which would give the row back. */
.bn-sd-stack .bn-sd-filter-row .bn-sd-sort { flex: 0 0 auto; align-self: center; }
.bn-sd-stack .bn-sd-filter-row .bn-sd-sort__trigger {
	inline-size: auto;
	min-height: 44px;
	padding: 0 14px;
	border: 1px solid var(--ek-dir-border);
	border-radius: 10px;
	background: var(--ek-dir-surface);
	color: var(--ek-dir-ink);
	font-size: 13px;
	font-weight: 400;
	letter-spacing: 0;
}
.bn-sd-stack .bn-sd-filter-row .bn-sd-sort__trigger:hover { border-color: #D6D6D6; }
.bn-sd-stack .bn-sd-filter-row .bn-sd-sort__trigger:focus-visible { outline: 2px solid var(--ek-dir-teal); outline-offset: 2px; }
/* The panel's "Include sub-spaces" replaces the vendor's link button. */
.bn-sd-stack .bn-sd-filter-row .bn-sd-subspaces-toggle { display: none !important; }

/* Filters row: toggle, applied-filter chips, inline panel */
.ek-sd-tools {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 8px;
}
.ek-sd-toggle {
	display: inline-flex;
	align-items: center;
	gap: 6px;
	min-height: 40px;
	padding: 0 12px;
	border: 1px solid transparent;
	border-radius: var(--ek-dir-radius-ctrl);
	background: transparent;
	color: var(--ek-dir-ink);
	font-family: inherit;
	font-size: 14px;
	font-weight: 500;
	cursor: pointer;
}
.ek-sd-toggle:hover,
.ek-sd-toggle[aria-expanded="true"] { background: var(--ek-dir-hover); }
.ek-sd-toggle:focus-visible { outline: 2px solid var(--ek-dir-teal); outline-offset: 2px; }
.ek-sd-toggle__count {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-width: 20px;
	height: 20px;
	padding: 0 6px;
	border-radius: 9999px;
	background: var(--ek-dir-teal);
	color: #FFFFFF;
	font-size: 12px;
	font-weight: 700;
}
.ek-sd-applied {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 6px;
}
.ek-sd-applied__chip {
	display: inline-flex;
	align-items: center;
	gap: 6px;
	min-height: 32px;
	padding: 0 10px 0 12px;
	border: 1px solid var(--ek-dir-teal);
	border-radius: 9999px;
	background: var(--ek-dir-teal-wash);
	color: var(--ek-dir-teal-ink) !important;
	font-size: 13px;
	font-weight: 600;
	text-decoration: none !important;
}
.ek-sd-applied__clear {
	padding: 6px 4px;
	color: var(--ek-dir-teal-ink) !important;
	font-size: 13px;
	font-weight: 600;
	text-decoration: underline;
}
.ek-sd-panel {
	flex: 1 0 100%;
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
	gap: 17px;
	padding: 17px;
	background: var(--ek-dir-surface);
	border: 1px solid var(--ek-dir-border);
	border-radius: var(--ek-dir-radius-panel);
}
.ek-sd-panel[hidden] { display: none !important; }
.ek-sd-panel__group {
	display: flex;
	flex-direction: column;
	gap: 8px;
	min-width: 0;
	margin: 0;
	padding: 0;
	border: 0;
}
.ek-sd-panel__label {
	padding: 0;
	font-size: 12.75px;
	font-weight: 600;
	letter-spacing: 0.05em;
	text-transform: uppercase;
	color: var(--ek-dir-label);
}
.ek-sd-check {
	display: flex;
	align-items: flex-start;
	gap: 10px;
	cursor: pointer;
}
.ek-sd-check input {
	flex: 0 0 auto;
	width: 18px;
	height: 18px;
	margin: 2px 0 0;
	accent-color: var(--ek-dir-teal);
}
.ek-sd-check__label { display: block; font-size: 15px; font-weight: 600; color: var(--ek-dir-strong); }
.ek-sd-check__hint  { display: block; font-size: 13px; color: var(--ek-dir-hint); }
.ek-sd-panel__actions {
	grid-column: 1 / -1;
	display: flex;
	align-items: center;
	justify-content: flex-end;
	gap: 10px;
}
.ek-sd-clear {
	padding: 10px 6px;
	border: 0;
	background: none;
	color: var(--ek-dir-ink);
	font-family: inherit;
	font-size: 14px;
	font-weight: 600;
	text-decoration: underline;
	cursor: pointer;
}
.ek-sd-apply {
	display: inline-flex;
	align-items: center;
	min-height: 46px;
	padding: 0 18px;
	border: 1px solid var(--ek-dir-teal);
	border-radius: var(--ek-dir-radius-ctrl);
	background: var(--ek-dir-teal);
	color: #FFFFFF;
	font-family: inherit;
	font-size: 14px;
	font-weight: 600;
	cursor: pointer;
}
.ek-sd-apply:hover { background: var(--ek-dir-teal-hover); }
.ek-sd-clear:focus-visible,
.ek-sd-apply:focus-visible,
.ek-sd-applied__chip:focus-visible { outline: 2px solid var(--ek-dir-teal-ink); outline-offset: 2px; }

@media (max-width: 480px) {
	/* Keep chips and Sort on one line (vendor stacks them at this width). */
	.bn-sd-stack .bn-sd-filter-row { flex-direction: row; align-items: center; }
	.bn-sd-stack .bn-sd-sort { align-self: center; }
	.bn-sd-stack .bn-sd-sort__trigger { inline-size: auto; }
	.ek-sd-search-btn span { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
	.ek-sd-search-btn { padding: 0 14px; }
	.ek-sd-panel__actions { justify-content: stretch; }
	.ek-sd-apply { flex: 1 1 auto; justify-content: center; }
}

/* ══ Events (Eventonomy 1.6.0, search-filter block) ═════════════════════════
   Same bar and chips. Eventonomy's accent (olive #4D7C0F) comes from
   --evnm-accent → --evnm-accent-override → --evnm-brand (assets/css/evnm-ui.css);
   set both the override and the resolved tokens on the block so every accent use
   (Create event, active view, chips, Search) turns teal. */
html:root {
	--evnm-accent-override: #0B8478;
	--evnm-accent-hover-override: #0A7A6F;
	--evnm-accent-soft-override: rgba(11, 132, 120, 0.10);
	--evnm-accent-contrast-override: #FFFFFF;
}
html .evnm-scope {
	--evnm-accent: #0B8478;
	--evnm-accent-hover: #0A7A6F;
	--evnm-accent-soft: rgba(11, 132, 120, 0.10);
	--evnm-accent-contrast: #FFFFFF;
}
.evnm-scope .evnm-search-filter__controls {
	align-items: center;
	gap: 8px;
	padding: 8px;
	background: var(--ek-dir-surface);
	border: 1px solid var(--ek-dir-border);
	border-radius: var(--ek-dir-radius-bar);
	box-shadow: var(--ek-dir-shadow);
	transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
.evnm-scope .evnm-search-filter__controls:focus-within {
	border-color: var(--ek-dir-teal);
	box-shadow: 0 0 0 3px var(--ek-dir-teal-wash), var(--ek-dir-shadow);
}
.evnm-scope .evnm-search-filter__controls > .evnm-search-filter__field {
	flex: 1 1 220px;
	min-width: 0;
}
.evnm-scope .evnm-search-filter__input {
	width: 100%;
	height: 46px;
	padding: 0 12px 0 40px;
	border: 0 !important;
	box-shadow: none !important;
	background: transparent var(--ek-dir-search-icon) no-repeat 12px 50%;
	font-size: 17px;
}
.evnm-scope .evnm-search-filter__input:focus { outline: none; }
.evnm-scope .evnm-search-filter__daterange {
	display: flex;
	align-items: center;
	gap: 8px;
}
.evnm-scope .evnm-search-filter__daterange > * { position: relative; }
.evnm-scope .evnm-search-filter__daterange .evnm-search-filter__field-label {
	position: absolute;
	top: 5px;
	left: 12px;
	font-size: 10.5px;
	font-weight: 600;
	letter-spacing: 0.05em;
	text-transform: uppercase;
	color: var(--ek-dir-label);
	pointer-events: none;
}
.evnm-scope .evnm-search-filter__daterange input {
	height: 46px;
	padding: 14px 10px 0 12px;
	border: 1px solid var(--ek-dir-border);
	border-radius: var(--ek-dir-radius-ctrl);
	background: var(--ek-dir-surface);
}
.evnm-scope .evnm-search-filter__button {
	min-height: 46px;
	padding: 0 18px;
	border-radius: var(--ek-dir-radius-ctrl);
	font-size: 14px;
	font-weight: 600;
}
.evnm-scope .evnm-search-filter__chips {
	display: flex;
	flex-wrap: nowrap;
	gap: 6px;
	overflow-x: auto;
	scrollbar-width: none;
	-webkit-mask-image: linear-gradient(to right, #000 calc(100% - 28px), transparent);
	mask-image: linear-gradient(to right, #000 calc(100% - 28px), transparent);
}
.evnm-scope .evnm-search-filter__chips::-webkit-scrollbar { display: none; }
.evnm-scope .evnm-search-filter__chip {
	flex: 0 0 auto;
	min-height: 40px;
	padding: 6px 14px;
	border-color: var(--ek-dir-chip-border);
	background: transparent;
	color: var(--ek-dir-ink);
	font-size: 15px;
	font-weight: 500;
}
.evnm-scope .evnm-search-filter__chip.is-active {
	background: var(--ek-dir-teal-wash);
	border-color: var(--ek-dir-teal);
	color: var(--ek-dir-teal-ink);
}
@media (max-width: 600px) {
	/* Eventonomy stacks the controls in a column here; in a column the search
	   field's 220px flex-basis became its HEIGHT (a 346px bar). Keep wrapping
	   rows instead: search full width, dates side by side, Search full width. */
	.evnm-scope .evnm-search-filter__controls { flex-direction: row; flex-wrap: wrap; }
	.evnm-scope .evnm-search-filter__controls > .evnm-search-filter__field { flex: 1 1 100%; }
	.evnm-scope .evnm-search-filter__daterange { flex: 1 1 100%; }
	.evnm-scope .evnm-search-filter__daterange > * { flex: 1 1 0; min-width: 0; }
	.evnm-scope .evnm-search-filter__daterange input { width: 100%; }
	.evnm-scope .evnm-search-filter__button { flex: 1 1 100%; justify-content: center; }
}

/* ══ Type: Listora's control sizes, and our faces ═══════════════════════════
   Kevin, 11 Sep 2026: land on Listora's styling, and use our fonts on all three
   directories. Outfit ships site-wide from the child theme but only the
   messenger used it: BuddyNext, Listora and Eventonomy all render in Inter.
   Outfit takes the display roles (page and card titles, chips, tabs, buttons,
   small uppercase labels); Inter keeps body copy, meta lines, counts, hints and
   form inputs, where it reads better at small sizes. */
:root {
	--ek-dir-display: "Outfit", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
}

/* Listora's control type: 13px, medium weight (ours were 14px semibold). */
.bn-sd-stack .bn-filter-strip .ek-sd-search-btn { font-size: 13px; font-weight: 500; }
.ek-sd-tools .ek-sd-toggle { min-height: 46px; font-size: 13px; font-weight: 500; }

/* Spaces */
.bn-sd-stack .bn-section-head h1,
.bn-sd-stack .bn-section-head__title,
.bn-sd-stack .bn-sd-card__name,
.bn-sd-stack .bn-sd-chips .bn-sd-chip,
.bn-sd-stack .bn-sd-filter-row .bn-sd-sort__trigger,
.bn-sd-stack .bn-sd-sort__option,
.ek-sd-search-btn,
.ek-sd-tools .ek-sd-toggle,
.ek-sd-apply,
.ek-sd-clear,
.ek-sd-applied__chip,
.ek-sd-applied__clear,
.ek-sd-panel__label,
.ek-sd-check__label {
	font-family: var(--ek-dir-display);
}

/* Listora (/listings) */
.listora-card__title,
.listora-row-title,
.listora-search__type-tab,
.listora-search__submit,
.listora-search__toggle-btn,
.listora-search__filter-label,
.listora-grid__count,
.listora-btn {
	font-family: var(--ek-dir-display);
}

/* Events (Eventonomy) */
.evnm-scope .evnm-search-filter__heading,
.evnm-scope .evnm-search-filter__view,
.evnm-scope .evnm-search-filter__create,
.evnm-scope .evnm-search-filter__button,
.evnm-scope .evnm-search-filter__chip,
.evnm-scope .evnm-search-filter__field-label,
.evnm-scope .evnm-card-title {
	font-family: var(--ek-dir-display);
}

/* The two places our display face lost the cascade (measured 11 Sep 2026):
   - Spaces: BuddyNext prints `.bn-app button, .bn-app .bn-btn { font-family:
     var(--bn-theme-heading-font) }` inline, which outranks a single class.
   - Listora: its card title reads its own `--listora-card-title-font` token, and
     its chips and buttons are set to `inherit` by more specific rules in
     listora-base/components.css, so they fell back to the page font.
   Same intent as the block above, with enough specificity to land. */
.bn-app .ek-sd-search-btn,
.bn-app .ek-sd-toggle,
.bn-app .ek-sd-apply,
.bn-app .ek-sd-clear,
.bn-app .ek-sd-applied__chip,
.bn-app .ek-sd-applied__clear {
	font-family: var(--ek-dir-display);
}
html:root { --listora-card-title-font: var(--ek-dir-display); }
html body .listora-card__title,
html body .listora-row-title,
html body .listora-search .listora-search__type-tab,
html body .listora-search .listora-search__submit,
html body .listora-search .listora-search__toggle-btn,
html body .listora-search .listora-search__filter-label,
html body .listora-grid .listora-grid__count {
	font-family: var(--ek-dir-display);
}

/* ── Listora's map block with no tile source (Kevin, 11 Sep 2026) ──────────
   Listora ships no default map tiles on purpose (OpenStreetMap's public tiles
   are not licensed for plugin-scale use), so an unset tile source renders a
   "The map is not available." band above the listings
   (blocks/listing-map/render.php:288-300, .listora-map__unconfigured inside the
   block wrapper). Hide the block in that state and give the space back. It is
   self-healing: set a tile source in Listora → Settings → Maps and the real map
   renders, so the notice (and this rule) no longer match. */
.listora-map-wrapper:has(.listora-map__unconfigured) { display: none !important; }
/* Fallback for browsers without :has(): at least drop the notice itself. */
.listora-map__unconfigured { display: none !important; }

/* ── Group Events tab: the short add-an-event form (Kevin, 12 Sep 2026) ──────
   Markup from the companion (Events/CreateForm.php). Folded behind a <details>
   summary so the tab still opens on the events themselves; no script, so it
   works on the first paint. */

.ek-space-events__added {
	margin: 0 0 14px;
	padding: 10px 14px;
	border-radius: 10px;
	background: rgba( 11, 132, 120, 0.10 );
	color: var( --ek-teal-text, #0A7A6F );
	font-family: var( --ek-dir-body, Inter, system-ui, sans-serif );
	font-size: 14px;
	font-weight: 600;
}

.ek-event-form {
	margin: 0 0 18px;
	border: 1px solid var( --ek-dir-line, #E4E7EC );
	border-radius: 12px;
	background: var(--ek-dir-surface);
}

.ek-event-form__summary {
	padding: 12px 16px;
	cursor: pointer;
	font-family: var( --ek-dir-display, Outfit, system-ui, sans-serif );
	font-size: 15px;
	font-weight: 600;
	color: var( --ek-teal-text, #0A7A6F );
	list-style: none;
}

.ek-event-form__summary::-webkit-details-marker { display: none; }

.ek-event-form__summary::before {
	content: "+";
	display: inline-block;
	width: 1.1em;
	font-weight: 700;
}

.ek-event-form[open] .ek-event-form__summary::before { content: "–"; }

.ek-event-form__body {
	padding: 4px 16px 18px;
	border-top: 1px solid var( --ek-dir-line, #E4E7EC );
}

.ek-event-form__field {
	display: flex;
	flex-direction: column;
	gap: 5px;
	margin: 14px 0 0;
}

.ek-event-form__field label {
	font-family: var( --ek-dir-display, Outfit, system-ui, sans-serif );
	font-size: 13px;
	font-weight: 600;
}

.ek-event-form__field input {
	width: 100%;
	padding: 9px 12px;
	border: 1px solid var( --ek-dir-line, #E4E7EC );
	border-radius: 10px;
	font-family: var( --ek-dir-body, Inter, system-ui, sans-serif );
	font-size: 14px;
	background: var(--ek-dir-surface);
}

.ek-event-form__field input:focus-visible {
	outline: 2px solid var( --ek-button, #0B8478 );
	outline-offset: 1px;
}

.ek-event-form__row {
	display: flex;
	flex-wrap: wrap;
	gap: 14px;
}

.ek-event-form__row .ek-event-form__field {
	flex: 1 1 190px;
	min-width: 0;
}

.ek-event-form__hint {
	font-family: var( --ek-dir-body, Inter, system-ui, sans-serif );
	font-size: 12px;
	color: var( --ek-dir-muted, #667085 );
}

.ek-event-form__error {
	font-family: var( --ek-dir-body, Inter, system-ui, sans-serif );
	font-size: 12px;
	font-weight: 600;
	color: var(--ek-dir-danger);
}

.ek-event-form__images {
	margin: 18px 0 0;
	padding: 0;
	border: 0;
	/* A fieldset defaults to min-width: min-content, so it refuses to shrink
	   and grows to fit the whole picture row instead of letting it scroll —
	   which pushed the page itself sideways. */
	min-width: 0;
}

.ek-event-form__images legend {
	padding: 0;
	font-family: var( --ek-dir-display, Outfit, system-ui, sans-serif );
	font-size: 13px;
	font-weight: 600;
}

/* One swipeable row, not a wrapping grid (Kevin, 12 Sep 2026: "this is not a
   good use of space"). Six tiles wrapped to three rows on a phone and pushed
   the Add button off the screen. The same scrolling row the Groups directory
   chips use, with the scrollbar hidden the same way; a partly visible tile at
   the edge is the affordance. Nothing in the stack ships a gallery component
   to borrow — BuddyNext has a DM media modal and nothing reusable. */
.ek-event-form__tiles {
	display: flex;
	gap: 8px;
	margin-top: 8px;
	padding-bottom: 2px;
	overflow-x: auto;
	scrollbar-width: none;
	-ms-overflow-style: none;
	overscroll-behavior-x: contain;
	scroll-snap-type: x proximity;
	touch-action: pan-x;
	max-width: 100%;
}

.ek-event-form__tiles::-webkit-scrollbar {
	display: none;
}

.ek-event-form__tiles:focus-visible {
	outline: 2px solid var( --ek-button, #0B8478 );
	outline-offset: 3px;
	border-radius: 10px;
}

.ek-event-form__tile {
	position: relative;
	flex: 0 0 96px;
	width: 96px;
	cursor: pointer;
	scroll-snap-align: start;
}

.ek-event-form__tile input {
	position: absolute;
	opacity: 0;
	pointer-events: none;
}

.ek-event-form__tile img {
	display: block;
	width: 100%;
	aspect-ratio: 3 / 2;
	object-fit: cover;
	border-radius: 9px;
	border: 3px solid transparent;
	box-shadow: 0 0 0 1px var( --ek-dir-line, #E4E7EC );
	transition: border-color 120ms ease, filter 120ms ease;
}

/* The group's own picture says so on the tile, so the row stays one tile tall. */
.ek-event-form__tile-badge {
	position: absolute;
	left: 4px;
	bottom: 4px;
	padding: 1px 6px;
	border-radius: 999px;
	background: rgba( 0, 0, 0, 0.6 );
	color: #fff;
	font-family: var( --ek-dir-body, Inter, system-ui, sans-serif );
	font-size: 10px;
	font-weight: 600;
	letter-spacing: 0.01em;
}

/* Chosen: a teal frame AND a tick, because a frame alone was too quiet
   (Kevin, 12 Sep 2026). The tick is decorative — the radio carries the state
   for a screen reader — so it is aria-hidden in the markup. */
.ek-event-form__tick {
	position: absolute;
	top: 6px;
	right: 6px;
	display: none;
	width: 22px;
	height: 22px;
	align-items: center;
	justify-content: center;
	border-radius: 50%;
	background: var( --ek-button, #0B8478 );
	color: #fff;
	font-size: 14px;
	line-height: 1;
	box-shadow: 0 1px 4px rgba( 0, 0, 0, 0.28 );
}

.ek-event-form__tile input:checked ~ .ek-event-form__tick {
	display: flex;
}

.ek-event-form__tile input:checked ~ img {
	border-color: var( --ek-button, #0B8478 );
	box-shadow: 0 0 0 1px var( --ek-button, #0B8478 );
}

.ek-event-form__tile:hover img {
	filter: brightness( 0.96 );
}

.ek-event-form__tile input:focus-visible ~ img {
	outline: 2px solid var( --ek-button, #0B8478 );
	outline-offset: 2px;
}

.ek-event-form__actions {
	display: flex;
	align-items: center;
	flex-wrap: wrap;
	gap: 10px;
	margin: 18px 0 0;
}

/* ── Single event page: close the gap above the card (Kevin, 12 Sep 2026) ────
   Two paddings stacked above the hero on a phone: Reign's .site-content (40px)
   and Eventonomy's .evnm-page (32px), so the card started 72px down with
   nothing in between. Scoped with :has() to the single-event page only, so
   every other page keeps the theme's own rhythm. */

.evnm-page:has( > .evnm-single-event ) {
	padding-top: 0;
}

.site-content:has( .evnm-single-event ) {
	padding-top: 20px;
}

@media ( max-width: 782px ) {
	.site-content:has( .evnm-single-event ) {
		padding-top: 10px;
	}
}

/* The hosting group on an event card (Kevin, 12 Sep 2026). Borrows the venue
   line's shape so it reads as one of the card's own meta rows, a shade
   quieter than the venue since it is context rather than detail. */
.ek-event-card-group a {
	color: inherit;
	text-decoration: none;
}

.ek-event-card-group a:hover,
.ek-event-card-group a:focus-visible {
	color: var( --ek-teal-text, #0A7A6F );
	text-decoration: underline;
}

/* Who is it for — the audience choice on the group event form
   (Kevin, 12 Sep 2026). Two stacked choices rather than a select, so the
   consequence of each is readable without opening anything. */
.ek-event-form__who {
	margin: 18px 0 0;
	padding: 0;
	border: 0;
	min-width: 0;
}

.ek-event-form__who legend {
	padding: 0;
	font-family: var( --ek-dir-display, Outfit, system-ui, sans-serif );
	font-size: 13px;
	font-weight: 600;
}

.ek-event-form__choice {
	display: flex;
	align-items: flex-start;
	gap: 9px;
	margin-top: 8px;
	padding: 9px 11px;
	border: 1px solid var( --ek-dir-line, #E4E7EC );
	border-radius: 10px;
	cursor: pointer;
}

.ek-event-form__choice input {
	margin: 2px 0 0;
	accent-color: var( --ek-button, #0B8478 );
	flex: 0 0 auto;
}

.ek-event-form__choice > span {
	display: flex;
	flex-direction: column;
	gap: 2px;
	min-width: 0;
}

.ek-event-form__choice strong {
	font-family: var( --ek-dir-display, Outfit, system-ui, sans-serif );
	font-size: 14px;
	font-weight: 600;
}

.ek-event-form__choice:has( input:checked ) {
	border-color: var( --ek-button, #0B8478 );
	box-shadow: inset 0 0 0 1px var( --ek-button, #0B8478 );
}

.ek-event-form__choice:has( input:focus-visible ) {
	outline: 2px solid var( --ek-button, #0B8478 );
	outline-offset: 2px;
}

/* Managing a group's events, in the group's settings (Kevin, 13 Sep 2026).
   The public Events tab is read-only; this list is what a leader works from. */
.ek-events-manage__title {
	margin: 0 0 4px;
	font-family: var( --ek-dir-display, Outfit, system-ui, sans-serif );
	font-size: 18px;
	font-weight: 600;
}

.ek-events-manage__intro,
.ek-events-manage__empty {
	margin: 0 0 16px;
	font-family: var( --ek-dir-body, Inter, system-ui, sans-serif );
	font-size: 13px;
	color: var( --ek-dir-muted, #667085 );
}

.ek-events-manage__list {
	margin: 18px 0 0;
	padding: 0;
	list-style: none;
	border-top: 1px solid var( --ek-dir-line, #E4E7EC );
}

.ek-events-manage__item {
	display: flex;
	align-items: baseline;
	flex-wrap: wrap;
	gap: 4px 12px;
	padding: 11px 0;
	border-bottom: 1px solid var( --ek-dir-line, #E4E7EC );
	font-family: var( --ek-dir-body, Inter, system-ui, sans-serif );
	font-size: 14px;
}

.ek-events-manage__item.is-cancelled .ek-events-manage__name {
	text-decoration: line-through;
	color: var( --ek-dir-muted, #667085 );
}

.ek-events-manage__when {
	flex: 0 0 auto;
	min-width: 96px;
	color: var( --ek-dir-muted, #667085 );
	font-variant-numeric: tabular-nums;
}

.ek-events-manage__name {
	flex: 1 1 160px;
	font-weight: 600;
}

.ek-events-manage__who {
	flex: 0 0 auto;
	padding: 1px 8px;
	border-radius: 999px;
	background: var( --ek-dir-chip, #F2F4F7 );
	font-size: 12px;
	color: var( --ek-dir-muted, #667085 );
}

.ek-events-manage__actions {
	display: flex;
	align-items: center;
	gap: 12px;
	font-size: 13px;
}

.ek-events-manage__off {
	display: inline;
	margin: 0;
}

.ek-events-manage__actions a,
.ek-events-manage__actions button {
	padding: 0;
	border: 0;
	background: none;
	font: inherit;
	color: var( --ek-dir-muted, #667085 );
	text-decoration: none;
	cursor: pointer;
}

.ek-events-manage__actions a:hover,
.ek-events-manage__actions a:focus-visible {
	color: var( --ek-teal-text, #0A7A6F );
	text-decoration: underline;
}

.ek-events-manage__actions button:hover,
.ek-events-manage__actions button:focus-visible {
	color: var(--ek-dir-danger);
	text-decoration: underline;
}

.ek-event-form__stop {
	font-family: var( --ek-dir-body, Inter, system-ui, sans-serif );
	font-size: 13px;
	color: var( --ek-dir-muted, #667085 );
}

/* The leader's "Add an event" button. messaging.js lifts it into the group
   header's own action row; until then, and if the script never runs, it sits
   as a small bar directly under the hero (Kevin, 13 Sep 2026). */
.ek-space-leader-actions {
	display: flex;
	justify-content: flex-end;
	gap: 8px;
	margin: 10px 0 0;
}

.bn-sh-hero__actions .bn-btn svg,
.ek-space-leader-actions .bn-btn svg {
	width: 16px;
	height: 16px;
}

/* "Group Chat" — the Chat tab's replacement (Kevin, 14 Sep 2026). Teal primary
   is the vendor's own `data-variant="primary"`, pinned to the brand fill in both
   themes (Appearance.php:156-165), so nothing here sets a colour on the button.
   The unread count rides on it as a white pill with the fill teal as ink — the
   fill never changes with the theme, so neither does this pair. */
.bn-sh-hero__actions .ek-group-chat,
.ek-space-leader-actions .ek-group-chat {
	gap: 6px;
}

.ek-group-chat__count {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-width: 20px;
	height: 20px;
	padding: 0 6px;
	border-radius: 9999px;
	background: #FFFFFF;
	color: var(--ek-teal-fill);
	font-family: var(--ek-dir-display);
	font-size: 12px;
	font-weight: 700;
	line-height: 1;
}

/* ── A group's Events tab: a grid of cards, grouped by when ─────────────────
   (Kevin, 13 Sep 2026: "we don't need to make these full width… we need cards
   in a grid like in the normal events listing".)

   The vendor's grid is `repeat( auto-fit, minmax( 280px, 1fr ) )`, and auto-FIT
   collapses the empty tracks — so a group with one event got a single card
   stretched across the whole column. auto-FILL keeps the tracks, so one card is
   card-sized and two sit side by side. Scoped to our tab; the site-wide
   directory keeps the vendor's own behaviour. */

.ek-space-events .evnm-events-list__items {
	grid-template-columns: repeat( auto-fill, minmax( 230px, 1fr ) );
	gap: 16px;
}

/* The "This week" / "Next week" headings we inject (Events/Cards.php) are list
   items inside that grid, so they have to span every track or they would sit in
   a single cell as if they were a card. */
.ek-space-events .ek-event-bucket {
	grid-column: 1 / -1;
	margin: 10px 0 -4px;
	font-family: var( --ek-dir-display, Outfit, system-ui, sans-serif );
	font-size: 13px;
	font-weight: 600;
	letter-spacing: 0.02em;
	text-transform: uppercase;
	color: var( --ek-dir-muted, #667085 );
}

.ek-space-events .ek-event-bucket:first-child {
	margin-top: 0;
}

/* Shorter cards, at the SAME shape as the picker tiles a leader chooses from.
   The approved library images are 1200x800, i.e. 3:2, so a 3:2 box crops them
   not at all — and because the picker tile is also 3:2, what a leader sees when
   choosing is what the card shows (Kevin, 13 Sep 2026: "I am concerned the
   image will be cropped funny").

   A group BANNER is a different shape entirely — 1600x500 on this site, a 3.2
   panorama — so it centre-crops to about half its width in any card-shaped box.
   That is inherent to using a banner as a card image, not something a ratio can
   fix; the picker shows the leader exactly that crop before they pick it. */
.ek-space-events .evnm-events-list__media {
	aspect-ratio: 3 / 2;
}

.ek-space-events .evnm-events-list__image {
	width: 100%;
	height: 100%;
	object-fit: cover;
}

.ek-space-events .evnm-events-list__title {
	font-size: 15px;
	line-height: 1.3;
}

.ek-space-events .evnm-events-list__body {
	padding: 10px 12px 12px;
}

/* Every event is free at the proof of concept (no gateways, donations off), so
   a "Free" chip on every card is noise rather than information. */
.ek-space-events .evnm-events-list__pill--price,
.ek-space-events .evnm-events-list__price {
	display: none;
}

/* Phones: a stacked poster card ran to 366px, nearly half the screen, for one
   event. A row — picture left, words right — is about a third of that, so three
   fit where one did, which is the point of a list you scan
   (Kevin, 13 Sep 2026: "on mobile they are too big too"). */
@media ( max-width: 600px ) {
	.ek-space-events .evnm-events-list__items {
		grid-template-columns: 1fr;
		gap: 10px;
	}

	/* The vendor's card is a flex COLUMN, and its picture carries negative
	   margins so it bleeds to the card's edges in that stack. Turning the card
	   on its side means undoing both, or the 116px basis sizes the height and
	   the bleed pulls the picture out of the row. */
	.ek-space-events .evnm-events-list__item {
		display: flex;
		flex-direction: row;
		align-items: stretch;
		gap: 0;
		overflow: hidden;
	}

	/* Landscape here too, and the same 3:2 as everywhere else — stretching the
	   thumbnail to the row's full height made a portrait box, which crops a
	   landscape photograph hardest of all. */
	.ek-space-events .evnm-events-list__media {
		flex: 0 0 132px;
		width: 132px;
		aspect-ratio: 3 / 2;
		margin: 0;
		align-self: center;
		border-radius: 8px;
		overflow: hidden;
	}

	.ek-space-events .evnm-events-list__image {
		width: 100%;
		height: 100%;
		object-fit: cover;
	}

	/* The date chip overlays the picture, and at 132px it covers a third of it.
	   The body already spells the date out underneath. */
	.ek-space-events .evnm-events-list__datechip {
		display: none;
	}

	.ek-space-events .evnm-events-list__body {
		flex: 1 1 auto;
		min-width: 0;
		padding: 10px 12px;
	}

	.ek-space-events .evnm-events-list__title {
		font-size: 14px;
	}


}

/* ── Upcoming ─────────────────────────────────────────────────────────────
   The member's own next thirty days: what their groups are putting on, plus
   what they have said they are coming to (vocabulary doc §10, companion
   Events/Upcoming.php).

   The cards are ours rather than Eventonomy's — a list that mixes groups needs
   the group ON the card, and rewriting vendor markup card by card to add it was
   the thing the 12 Sep register entry ruled out. The SHAPE deliberately matches
   the group Events tab above: same 230px track, same 3:2 picture box, same
   turn-to-a-row on a phone. A member moving between the two screens should not
   feel they have changed products. */

.ek-upcoming {
	max-width: 100%;
}

.ek-upcoming__heading {
	margin: 0 0 14px;
	font-family: var( --ek-dir-display, Outfit, system-ui, sans-serif );
	font-size: 22px;
	font-weight: 600;
	line-height: 1.2;
}

.ek-upcoming__list {
	display: grid;
	grid-template-columns: repeat( auto-fill, minmax( 230px, 1fr ) );
	gap: 16px;
	margin: 0;
	padding: 0;
	list-style: none;
}

/* The bucket headings are list items inside the grid, so they have to span
   every track or they would sit in one cell as if they were a card — the same
   rule the group tab's headings need. */
.ek-upcoming__bucket {
	grid-column: 1 / -1;
	margin: 10px 0 -4px;
	font-family: var( --ek-dir-display, Outfit, system-ui, sans-serif );
	font-size: 13px;
	font-weight: 600;
	letter-spacing: 0.02em;
	text-transform: uppercase;
	color: var( --ek-dir-muted, #667085 );
}

.ek-upcoming__bucket:first-child {
	margin-top: 0;
}

.ek-upcoming__card {
	display: flex;
	flex-direction: column;
	overflow: hidden;
	border: 1px solid var( --ek-dir-line, #E4E7EC );
	border-radius: 12px;
	background: var(--ek-dir-surface);
}

/* A cancelled event stays in the list — the people who need telling are the
   ones who were counting on it — but it must not read as an invitation. */
.ek-upcoming__card--off {
	opacity: 0.72;
}

.ek-upcoming__card--off .ek-upcoming__title {
	text-decoration: line-through;
	text-decoration-thickness: 1px;
}

.ek-upcoming__media {
	position: relative;
	display: block;
	aspect-ratio: 3 / 2;
	background: var( --ek-dir-line, #E4E7EC );
}

.ek-upcoming__image {
	width: 100%;
	height: 100%;
	object-fit: cover;
	display: block;
}

.ek-upcoming__chip {
	position: absolute;
	top: 8px;
	left: 8px;
	display: flex;
	flex-direction: column;
	align-items: center;
	min-width: 40px;
	padding: 4px 6px 5px;
	border-radius: 8px;
	background: var(--ek-dir-sticker);
	box-shadow: 0 1px 3px rgba( 16, 24, 40, 0.18 );
	font-family: var( --ek-dir-body, Inter, system-ui, sans-serif );
	line-height: 1;
}

.ek-upcoming__chip-mon {
	font-size: 10px;
	font-weight: 700;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: var( --ek-teal-text, #0A7A6F );
}

.ek-upcoming__chip-day {
	margin-top: 2px;
	font-size: 17px;
	font-weight: 700;
	color: var(--ek-dir-sticker-ink);
}

.ek-upcoming__body {
	display: flex;
	flex-direction: column;
	gap: 3px;
	padding: 10px 12px 12px;
	min-width: 0;
}

.ek-upcoming__title {
	margin: 0;
	font-family: var( --ek-dir-display, Outfit, system-ui, sans-serif );
	font-size: 15px;
	font-weight: 600;
	line-height: 1.3;
}

.ek-upcoming__title a {
	color: inherit;
	text-decoration: none;
}

.ek-upcoming__title a:hover,
.ek-upcoming__title a:focus {
	text-decoration: underline;
}

.ek-upcoming__group,
.ek-upcoming__when,
.ek-upcoming__where {
	margin: 0;
	font-family: var( --ek-dir-body, Inter, system-ui, sans-serif );
	font-size: 13px;
	line-height: 1.4;
	color: var( --ek-dir-muted, #667085 );
	overflow-wrap: anywhere;
}

.ek-upcoming__group a {
	color: var( --ek-teal-text, #0A7A6F );
	font-weight: 600;
	text-decoration: none;
}

.ek-upcoming__group a:hover,
.ek-upcoming__group a:focus {
	text-decoration: underline;
}

/* The member's own answer, and the cancellation, read as state rather than as
   another line of description — so they are chips, not paragraphs. */
.ek-upcoming__flag {
	align-self: flex-start;
	margin: 4px 0 0;
	padding: 2px 8px;
	border-radius: 999px;
	font-family: var( --ek-dir-body, Inter, system-ui, sans-serif );
	font-size: 12px;
	font-weight: 600;
	line-height: 1.5;
}

.ek-upcoming__flag--going {
	background: rgba( 11, 132, 120, 0.12 );
	color: var( --ek-teal-text, #0A7A6F );
}

.ek-upcoming__flag--maybe {
	background: rgba( 102, 112, 133, 0.14 );
	color: #475467;
}

.ek-upcoming__flag--off {
	background: rgba( 217, 45, 32, 0.10 );
	color: var(--ek-dir-danger);
}

.ek-upcoming__empty {
	padding: 28px 20px;
	border: 1px solid var( --ek-dir-line, #E4E7EC );
	border-radius: 12px;
	background: var(--ek-dir-surface);
	text-align: center;
}

.ek-upcoming__empty-lead {
	margin: 0 0 6px;
	font-family: var( --ek-dir-display, Outfit, system-ui, sans-serif );
	font-size: 17px;
	font-weight: 600;
}

.ek-upcoming__empty-body {
	margin: 0 auto 16px;
	max-width: 42ch;
	font-family: var( --ek-dir-body, Inter, system-ui, sans-serif );
	font-size: 14px;
	line-height: 1.5;
	color: var( --ek-dir-muted, #667085 );
}

.ek-upcoming__empty-cta {
	display: inline-block;
	padding: 9px 18px;
	border-radius: 999px;
	background: var( --ek-teal-fill, #0A7A6F );
	color: #fff;
	font-family: var( --ek-dir-body, Inter, system-ui, sans-serif );
	font-size: 14px;
	font-weight: 600;
	text-decoration: none;
}

/* Phones: a stacked poster card is nearly half the screen for one event, which
   is the wrong trade on a list you scan. Turn it on its side — picture left,
   words right — exactly as the group Events tab does. */
@media ( max-width: 600px ) {
	.ek-upcoming__list {
		grid-template-columns: 1fr;
		gap: 10px;
	}

	.ek-upcoming__card {
		flex-direction: row;
		align-items: center;
		gap: 0;
		padding: 8px;
	}

	.ek-upcoming__media {
		flex: 0 0 116px;
		width: 116px;
		border-radius: 8px;
		overflow: hidden;
	}

	/* At 116px the date chip covers a third of the picture, and the body spells
	   the date out beside it anyway. */
	.ek-upcoming__chip {
		display: none;
	}

	.ek-upcoming__body {
		flex: 1 1 auto;
		padding: 0 0 0 12px;
	}

	.ek-upcoming__title {
		font-size: 14px;
	}
}

/* Who's going, and the folded repeats (Dana, 13 Sep 2026).

   The card said what, when and where and nothing about WHO, which on a
   community site is the whole decision. Only the viewer's own Contacts are
   named; everyone else is a number — see Events/Attendance.php for why that
   rule is the design rather than a nicety. */

.ek-upcoming__whos {
	display: flex;
	align-items: center;
	gap: 7px;
	margin: 5px 0 0;
	min-width: 0;
}

.ek-upcoming__faces { display: flex; flex: 0 0 auto; }

/* Overlapped, with a ring in the CARD's colour so the stack reads as a stack
   rather than as one smeared shape. */
.ek-upcoming__face {
	display: block;
	width: 20px;
	height: 20px;
	margin-right: -6px;
	border: 1.5px solid #fff;
	border-radius: 999px;
	overflow: hidden;
	background: var( --ek-dir-line, #E4E7EC );
}

.ek-upcoming__face:last-child { margin-right: 0; }

.ek-upcoming__face-img,
.ek-upcoming__face img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
	border-radius: 999px;
}

.ek-upcoming__whos-text {
	min-width: 0;
	font-family: var( --ek-dir-body, Inter, system-ui, sans-serif );
	font-size: 12px;
	line-height: 1.35;
	color: var( --ek-dir-muted, #667085 );
	overflow-wrap: anywhere;
}

.ek-upcoming__whos-text b {
	font-weight: 600;
	color: var(--ek-dir-heading);
}

/* "Mondays · and 4 more" — the rest of a repeating meeting, linking to the
   group's Events tab, which is the surface that legitimately lists them all. */
.ek-upcoming__more {
	margin: 3px 0 0;
	font-family: var( --ek-dir-body, Inter, system-ui, sans-serif );
	font-size: 12px;
	font-weight: 600;
	line-height: 1.35;
}

.ek-upcoming__more a {
	color: var( --ek-teal-text, #0A7A6F );
	text-decoration: none;
}

.ek-upcoming__more a:hover,
.ek-upcoming__more a:focus { text-decoration: underline; }

/* A cancelled card keeps its faces — the people who were coming are exactly
   who the cancellation is about — but it must not read as an invitation. */
.ek-upcoming__card--off .ek-upcoming__whos { opacity: 0.8; }

/* ── The decision queue ──────────────────────────────────────────────────
   "Needs you", at the top of Upcoming (Dana, 13 Sep 2026). Three asks at
   most, nothing further out than ten days — the cap is the safety rail that
   keeps a queue from becoming nagging, and it holds whether a member answers
   everything or nothing.

   Deliberately NOT card-shaped like the events below it. An ask is a question
   the page is putting to you, not an object in a list; giving it the same
   border and radius as an event card would file it as one more thing to
   scroll past. */

.ek-queue {
	margin: 0 0 22px;
}

.ek-queue__head {
	margin: 0 0 10px;
	font-family: var( --ek-dir-display, Outfit, system-ui, sans-serif );
	font-size: 13px;
	font-weight: 600;
	letter-spacing: 0.05em;
	text-transform: uppercase;
	color: var(--ek-dir-warn);
}

.ek-queue__ask {
	margin-bottom: 10px;
	padding: 13px 15px 12px;
	border: 1px solid rgba( 11, 132, 120, 0.30 );
	border-radius: 12px;
	background: var(--ek-dir-surface);
	box-shadow: 0 1px 2px rgba( 16, 24, 40, 0.05 );
}

/* A cancellation is not an invitation, so it does not wear the accent. */
.ek-queue__ask--cancelled {
	border-color: var( --ek-dir-line, #E4E7EC );
}

.ek-queue__q {
	margin: 0 0 3px;
	font-family: var( --ek-dir-display, Outfit, system-ui, sans-serif );
	font-size: 15px;
	font-weight: 600;
	line-height: 1.32;
	color: var(--ek-dir-heading);
}

.ek-queue__why {
	margin: 0 0 10px;
	font-family: var( --ek-dir-body, Inter, system-ui, sans-serif );
	font-size: 13px;
	line-height: 1.45;
	color: var( --ek-dir-muted, #667085 );
}

.ek-queue__ask .ek-upcoming__whos {
	margin: 2px 0 10px;
}

.ek-queue__actions {
	display: flex;
	flex-wrap: wrap;
	gap: 8px;
}

.ek-queue__actions form {
	margin: 0;
}

.ek-queue__btn {
	padding: 8px 16px;
	border: 1px solid transparent;
	border-radius: 999px;
	font-family: var( --ek-dir-body, Inter, system-ui, sans-serif );
	font-size: 13px;
	font-weight: 600;
	line-height: 1.3;
	cursor: pointer;
	transition: transform 0.12s ease, background 0.16s ease;
}

.ek-queue__btn:active { transform: scale( 0.97 ); }

.ek-queue__btn--yes {
	background: var( --ek-teal-fill, #0A7A6F );
	color: #fff;
}

.ek-queue__btn--yes:hover,
.ek-queue__btn--yes:focus { background: #086257; }

.ek-queue__btn--no {
	background: transparent;
	border-color: var( --ek-dir-line, #E4E7EC );
	color: var( --ek-dir-muted, #667085 );
}

.ek-queue__btn--no:hover,
.ek-queue__btn--no:focus {
	color: var(--ek-dir-heading);
	border-color: var( --ek-dir-muted, #667085 );
}

/* Shown once, on the way back from answering the last one — never as a
   standing banner. It is a reward for finishing, and a permanent one would
   be furniture. */
.ek-queue__cleared {
	display: flex;
	align-items: center;
	gap: 10px;
	margin: 0 0 20px;
	padding: 12px 14px;
	border: 1px solid rgba( 11, 132, 120, 0.30 );
	border-radius: 12px;
	background: rgba( 11, 132, 120, 0.10 );
	font-family: var( --ek-dir-body, Inter, system-ui, sans-serif );
	font-size: 14px;
	font-weight: 600;
	color: var( --ek-teal-text, #0A7A6F );
}

.ek-queue__tick {
	display: grid;
	place-items: center;
	flex: 0 0 auto;
	width: 22px;
	height: 22px;
	border-radius: 999px;
	background: var( --ek-teal-fill, #0A7A6F );
	color: #fff;
	font-size: 12px;
}

.ek-queue__problem {
	margin: 0 0 16px;
	padding: 11px 14px;
	border-radius: 10px;
	background: rgba( 180, 35, 24, 0.10 );
	font-family: var( --ek-dir-body, Inter, system-ui, sans-serif );
	font-size: 13px;
	font-weight: 600;
	color: var(--ek-dir-danger);
}

/* Phones: "Count me in" and "Can't make it" together run past 375px, so they
   stack rather than wrap raggedly (Kevin picked the labels knowing they were
   the longer pair). */
@media ( max-width: 400px ) {
	.ek-queue__actions {
		flex-direction: column;
		align-items: stretch;
	}

	.ek-queue__btn {
		width: 100%;
	}
}


/* ── Share to a group ─────────────────────────────────────────────────────
   Where Android's share sheet lands a member who picked eKlektiv (companion
   Chrome/ShareTarget.php). Deliberately plain and short: the member arrived
   mid-task from another app and wants to finish, not to browse. One decision
   on the screen — which group — and everything else out of its way. */

.ek-share { max-width: 640px; }

.ek-share__heading {
	margin: 0 0 16px;
	font-family: var( --ek-dir-display, Outfit, system-ui, sans-serif );
	font-size: 22px;
	font-weight: 600;
	line-height: 1.2;
}

/* What they shared, shown back so they can see it arrived intact. */
.ek-share__card {
	margin: 0 0 18px;
	padding: 12px 14px;
	border: 1px solid var( --ek-dir-line, #E4E7EC );
	border-left: 3px solid var( --ek-teal-text, #0A7A6F );
	border-radius: 10px;
	background: var(--ek-dir-surface);
}

.ek-share__card-title {
	margin: 0;
	font-family: var( --ek-dir-display, Outfit, system-ui, sans-serif );
	font-size: 15px;
	font-weight: 600;
	line-height: 1.35;
	color: var(--ek-dir-heading);
	overflow-wrap: anywhere;
}

.ek-share__card-text,
.ek-share__card-url {
	margin: 3px 0 0;
	font-family: var( --ek-dir-body, Inter, system-ui, sans-serif );
	font-size: 13px;
	line-height: 1.45;
	color: var( --ek-dir-muted, #667085 );
	overflow-wrap: anywhere;
}

.ek-share__card-url { font-weight: 600; color: var( --ek-teal-text, #0A7A6F ); }

.ek-share__label {
	display: block;
	margin: 0 0 6px;
	font-family: var( --ek-dir-body, Inter, system-ui, sans-serif );
	font-size: 13px;
	font-weight: 600;
	color: var(--ek-dir-heading);
}

.ek-share__message {
	width: 100%;
	margin: 0 0 18px;
	padding: 10px 12px;
	border: 1px solid var( --ek-dir-line, #E4E7EC );
	border-radius: 10px;
	background: var(--ek-dir-surface);
	font-family: var( --ek-dir-body, Inter, system-ui, sans-serif );
	font-size: 15px; /* 16px or more, or iOS zooms the page on focus; 15 is safe at this weight */
	line-height: 1.45;
	resize: vertical;
}

.ek-share__message:focus {
	outline: 2px solid var( --ek-teal-text, #0A7A6F );
	outline-offset: 1px;
}

.ek-share__groups {
	margin: 0 0 20px;
	padding: 0;
	list-style: none;
	display: grid;
	gap: 8px;
}

/* A whole-row target: the member is one-handed on a phone, mid-task. */
.ek-share__group {
	display: flex;
	align-items: center;
	gap: 10px;
	min-height: 48px;
	padding: 10px 14px;
	border: 1px solid var( --ek-dir-line, #E4E7EC );
	border-radius: 10px;
	background: var(--ek-dir-surface);
	font-family: var( --ek-dir-body, Inter, system-ui, sans-serif );
	font-size: 15px;
	cursor: pointer;
}

.ek-share__group:hover { border-color: var( --ek-dir-muted, #667085 ); }

.ek-share__group:has( input:checked ) {
	border-color: var( --ek-teal-text, #0A7A6F );
	background: rgba( 11, 132, 120, 0.06 );
	font-weight: 600;
}

.ek-share__group input { width: 18px; height: 18px; accent-color: var( --ek-teal-text, #0A7A6F ); }

.ek-share__post {
	width: 100%;
	padding: 13px 20px;
	border: 0;
	border-radius: 999px;
	background: var( --ek-teal-fill, #0A7A6F );
	color: #fff;
	font-family: var( --ek-dir-body, Inter, system-ui, sans-serif );
	font-size: 15px;
	font-weight: 600;
	cursor: pointer;
}

.ek-share__post:hover,
.ek-share__post:focus { background: #086257; }

.ek-share__problem {
	margin: 0 0 16px;
	padding: 11px 14px;
	border-radius: 10px;
	background: rgba( 180, 35, 24, 0.10 );
	font-family: var( --ek-dir-body, Inter, system-ui, sans-serif );
	font-size: 13px;
	font-weight: 600;
	color: var(--ek-dir-danger);
}

.ek-share__empty {
	padding: 24px 20px;
	border: 1px solid var( --ek-dir-line, #E4E7EC );
	border-radius: 12px;
	background: var(--ek-dir-surface);
	text-align: center;
}

.ek-share__empty-lead {
	margin: 0 0 6px;
	font-family: var( --ek-dir-display, Outfit, system-ui, sans-serif );
	font-size: 17px;
	font-weight: 600;
}

.ek-share__empty-body {
	margin: 0 auto 16px;
	max-width: 42ch;
	font-family: var( --ek-dir-body, Inter, system-ui, sans-serif );
	font-size: 14px;
	line-height: 1.5;
	color: var( --ek-dir-muted, #667085 );
}

.ek-share__empty-cta {
	display: inline-block;
	padding: 9px 18px;
	border-radius: 999px;
	background: var( --ek-teal-fill, #0A7A6F );
	color: #fff;
	font-family: var( --ek-dir-body, Inter, system-ui, sans-serif );
	font-size: 14px;
	font-weight: 600;
	text-decoration: none;
}

/* ──────────────────────────────────────────────────────────────────────────
 * Search results: the answer comes before the controls (Kevin, 13 Sep 2026).
 *
 * Kevin, on the search results page on his phone: "are you kidding me? This
 * sucks." He was right, and it is measurable rather than a matter of taste.
 * Measured at 375x812 on the sandbox, searching a word with exactly one hit:
 *
 *     hero            y=101   h=127
 *     tabs            y=308   h=44
 *     filter aside    y=384   h=1341   <- five cards
 *     the one result  y=1780  h=110
 *     page            h=2130
 *
 * The member scrolled 1,341px — one and a half screens of Date, Sort by,
 * Advanced member filters, Saved searches and Related searches — to reach a
 * 110px row sitting 84% of the way down the page. On the screen they land on
 * after searching, the one thing not visible was the result.
 *
 * The cause is the vendor's own rule, and it is deliberate rather than a slip:
 *
 *     @media (max-width: 1024px) { .bn-search-aside { order: -1; } }
 *     — buddynext/assets/css/bn-search.css:506-513
 *
 * Hoisting the filters makes sense on a tablet, where the aside becomes a
 * single wrapped row above a full-width result list and costs one card's
 * height. On a phone the same rule stacks that row into a column and the cost
 * becomes the whole screen. One breakpoint is doing two jobs.
 *
 * So: results first. The aside keeps every card and every control — nothing is
 * hidden and nothing is reordered within it — it simply sits after the thing
 * the member came for, which is where a refinement belongs.
 *
 * Specificity, not load order: `eklektiv-directories` depends on
 * `eklektiv-child`, not on `bn-search`, so there is no promise about which
 * stylesheet lands second. The vendor's selector is (0,1,0); the child
 * combinator below makes ours (0,2,0) and it wins either way.
 *
 * Measured again after the change, same device and same query: the result row
 * moved from y=1780 to **y=419** — fully visible without scrolling.
 *
 * **What this does not fix.** The aside is still 1,337px tall on a phone. A
 * first pass here also trimmed its padding and gaps; that was removed, because
 * measuring it showed the cards are content-bound rather than padding-bound —
 * four 35px radio rows and a title come to within ~18px of the card's height,
 * so the trim bought 4px of 1,341 and the comment claiming a third was wrong.
 * Making that block genuinely shorter means showing fewer controls on a phone
 * (Saved searches and Advanced member filters are the candidates), which is a
 * product call rather than a CSS one, so it is Kevin's to make and is not made
 * here.
 *
 * Vendor request 10 proposes fixing it upstream, where the phone case should
 * have its own breakpoint.
 * ────────────────────────────────────────────────────────────────────────── */

@media (max-width: 1024px) {

	.bn-search-layout > .bn-search-results {
		order: 0;
	}

	.bn-search-layout > .bn-search-aside {
		order: 1;
	}
}

/* ──────────────────────────────────────────────────────────────────────────
 * Search result rows: one species, not three (Kevin, 13 Sep 2026).
 *
 * Four notes from Kevin, once posts became clickable at all:
 *
 *   1. "it would be nice if it was the card that was clickable like the others
 *      and not the actual post"
 *   3. "the fonts are not the same size and maybe not the same typeface"
 *   4. "Remove the Listen button on the members if you can it is just too much"
 *   5. "Remove the Join on the Groups. I want them visiting the groups and
 *      profiles and then taking action...not from search"
 *
 * (His point 2, the author name, is not here — it cannot be done in CSS. See
 * the note at the end.)
 * ────────────────────────────────────────────────────────────────────────── */

/*
 * 1. The whole card, not just the sentence.
 *
 * A member or group row IS an anchor — the vendor wraps everything inside
 * `.bn-search-row__link` — so the entire card is one target. Our post anchor
 * can only be injected around the row's text (the part gives nowhere else), so
 * it was a smaller target than its neighbours in a list they sit in together.
 *
 * Stretching it costs no JavaScript: the card becomes the positioning context
 * and the anchor grows a transparent overlay across it. The anchor is still a
 * real link — keyboard, copy-link and JS-off all behave — it is only its hit
 * area that grows.
 *
 * Known trade, and the reason it is acceptable: an overlay sits above the text,
 * so the snippet can no longer be selected with the mouse. Member and group
 * rows already behave exactly that way, being anchors end to end, so this makes
 * the three consistent rather than introducing something new.
 */
.bn-search-row--post {
	position: relative;
}

.bn-search-row--post .ek-search-row__link {
	color: inherit;
	text-decoration: none;
}

.bn-search-row--post .ek-search-row__link::after {
	content: "";
	position: absolute;
	inset: 0;
	border-radius: inherit;
}

.bn-search-row--post .ek-search-row__link:hover {
	text-decoration: underline;
	text-underline-offset: 2px;
}

/* The ring belongs to the card now, because the card is the target. */
.bn-search-row--post:has(.ek-search-row__link:focus-visible) {
	box-shadow: var(--bn-ring);
}

.bn-search-row--post .ek-search-row__link:focus-visible {
	outline: none;
	box-shadow: none;
}

/* The highlight keeps its own colour inside the link. */
.bn-search-row--post .ek-search-row__link mark {
	color: var(--bn-ink);
}

/*
 * 3. One type scale across the three row types.
 *
 * Measured on the sandbox before changing anything, because "maybe not the same
 * typeface" was worth checking rather than assuming: the typeface is the same
 * everywhere — Inter — and it is the SIZES that differ, by role.
 *
 *   member / group   title  15px/600 --bn-ink     meta 13px/400 --bn-ink-3
 *   post             author 12px/600 --bn-ink-2   text 13px/400 --bn-ink-2
 *
 * A post row had no title tier at all: its biggest line was 13px body, so next
 * to a 15px member name it read as a different kind of object in the same list.
 * Now that our post rows lead with the event's name, that mattered more.
 *
 * So the post's text takes the lead line's size and ink, and its head takes the
 * supporting scale. Weight is deliberately NOT raised to 600: a member row's
 * lead is a name, a post row's lead is a sentence, and a sentence set in
 * semibold shouts. Same scale, same ink, honest about being prose.
 *
 * Vendor tokens throughout — nothing hardcoded — so this follows their theme.
 *
 * A judgement call, and Dana owns screens: easy to redirect, it is five
 * declarations.
 */
.bn-search-row--post .bn-search-row__text {
	font-size: var(--bn-text-base);
	color: var(--bn-ink);
}

.bn-search-row--post .bn-search-row__head {
	font-size: var(--bn-text-sm);
}

/*
 * 4 and 5. No Follow ("Listen") and no Join from a search result.
 *
 * Kevin: "I want them visiting the groups and profiles and then taking
 * action...not from search." A search result is a signpost; the decision to
 * follow someone or join a group belongs on their profile or the group's own
 * page, where there is enough context to make it.
 *
 * Both are the same shape in the vendor's markup — a `.bn-btn` that is a DIRECT
 * child of the row, sibling to the row's link (members part :165-177, spaces
 * part :171-183) — so one selector each, and the child combinator keeps it from
 * ever reaching a button inside a row's content.
 *
 * `display: none` rather than visually hiding it: this must leave the tab order
 * and the accessibility tree too, or a keyboard or screen-reader member would
 * still land on a control nobody can see.
 *
 * Nothing is lost. Follow and Join both live on the destination pages, which is
 * where Kevin wants the decision made, and neither part has a filter to
 * suppress the button at source — vendor request §11.
 */
.bn-search-row--member > .bn-btn,
.bn-search-row--space > .bn-btn {
	display: none;
}

/*
 * 2. The author name is NOT fixed here, and cannot be.
 *
 * Kevin: "Note the author is not clickable like the others." Correct, and it is
 * the one of the five with no CSS answer. The vendor prints it as
 * `esc_html( $author_name )` inside a plain `<span>` (posts part :140), so
 * there is no anchor to style and no seam to inject one through — the row's
 * only injectable output is the snippet, via `highlight_fn`. Making it a link
 * needs either the vendor's fix (requested, §11) or a script that rewrites the
 * span client-side, which is a DOM rewrite of a vendor surface rather than a
 * skin, and so is Kevin's call rather than a default.
 */

/*
 * 6. The post avatar is the same size as the others.
 *
 * Kevin: "the avatar for posts is not as big as it is for Groups and Members."
 * The vendor asks for a smaller one in the markup — posts part :137 renders
 * `data-size="sm"` while the members (:145) and spaces (:141) parts both render
 * `data-size="md"` — and the base sheet sizes those at 28px and 36px
 * (bn-base.css:2997-2998). Three rows in one list, two avatar sizes.
 *
 * The attribute is in the template so it cannot be changed from here, but the
 * size it resolves to can: `sm` inside a post row is given the `md` values, the
 * font size included so the initials stay in proportion. Scoped to the post row
 * so every other `sm` avatar on the site is untouched. Vendor request §11.
 */
.bn-search-row--post .bn-avatar[data-size="sm"] {
	width: 36px;
	height: 36px;
	font-size: 13px;
}

/*
 * 7. No "Member" badge on a person's result row.
 *
 * Kevin, asked whether the singular badge should read Member, Person, or go:
 * remove it. It labels a person as a person, beside their own name, inside a
 * section already headed People — it carries nothing. Same treatment as Listen
 * and Join: `display: none`, so it leaves the accessibility tree too rather
 * than being read aloud to somebody who cannot see how redundant it is.
 *
 * Scoped to the member row on purpose. The post row's "Post" badge and the
 * group row's "Space" badge are arguably just as redundant under their own
 * headings, but Kevin asked about this one, so this one goes and the other two
 * are raised rather than assumed.
 *
 * BuddyNext Pro's member labels (Verified, Expert, Staff) render as
 * `.bn-badge.bn-member-label` in the same row (Pro ProfileLabelInjector.php:357)
 * and are exempt: Kevin kept them as badges, 15 Sep 2026.
 */
.bn-search-row--member .bn-badge:not(.bn-member-label) {
	display: none;
}

/* ══════════════════════════════════════════════════════════════════════════
 * One header rhythm for Groups, Directory and Events (Kevin, 13 Sep 2026).
 *
 * "We need these to be consistent and tight … I like the Events page best."
 *
 * Measured on the sandbox at 1171px before changing anything — top of the
 * content column to the top of the first card:
 *
 *   Events      165px   title+views+Create (42) · search (64) · count (16)
 *   Groups      309px   title+subtitle (80) · search (64) · chips (47) · Filters (46)
 *   Directory   324px   42px of NOTHING · search (64) · chips (46) · Filters
 *                       · a 66px toolbar band for "Showing 1–20 of 114"
 *
 * Events wins because its first band does three jobs on one line — identity,
 * view switching and the primary action. The other two spend a whole band on
 * each job, and Directory opens with 42px of empty page.
 *
 * Worth recording, because it changes what "consistent" can mean here: all
 * three content columns are ALREADY the same width (1156 / 1156 / 1171).
 * Groups only looks fuller because BuddyNext's shell fills its margins with a
 * rail and a sidebar — its card grid is in fact the narrowest of the three.
 * Those rails come from Groups being a BuddyNext hub; Directory is Listora's
 * page and Events is Eventonomy's, and giving them that shell would mean
 * rebuilding vendor pages (CLAUDE.md rule 3). So the frames stay as they are
 * and the HEADER BANDS are what is made to match.
 *
 * The rhythm, one value each, applied to all three:
 *
 *   --ek-dirhead-gap    the space between bands
 *   title band  ~48px   identity and actions on ONE line
 *   search band  64px   (all three already agree)
 *   chip band    46px   chips and the Filters control on ONE line
 *   count line   ~20px  a line of text, not a band
 * ══════════════════════════════════════════════════════════════════════════ */

:root {
	--ek-dirhead-gap: 12px;
}

/* ── Groups ──────────────────────────────────────────────────────────────
 * Two bands are recovered. The subtitle joins the title on its line, and the
 * Filters control joins the chips on theirs — which also gets Sort out of the
 * chip row, the crowding that caused "Sort is interfering with buttons" on
 * 13 Sep. The stack already carries our order values (-4…-1 above); turning it
 * into a wrapping ROW lets the two adjacent ones share a line without touching
 * the markup.
 */
.bn-sd-stack {
	flex-direction: row;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--ek-dirhead-gap);
}

.bn-sd-stack > * {
	flex: 1 1 100%;
	min-width: 0;
}

.bn-sd-stack > .bn-sd-filter-row {
	flex: 1 1 320px;
}

.bn-sd-stack > .ek-sd-tools {
	flex: 0 0 auto;
}

/* Title and count on one line, sharing a baseline. */
.bn-app__region .bn-section-head {
	padding-block: 0;
}

.bn-app__region .bn-section-head__text {
	display: flex;
	align-items: baseline;
	flex-wrap: wrap;
	gap: 4px 10px;
}

.bn-app__region .bn-section-head__subtitle {
	margin: 0;
}

/* ── Directory ───────────────────────────────────────────────────────────
 * The 42px of empty page at the top is the whole reason this screen reads as
 * unanchored, and it buys nothing. The toolbar band is a 66px white strip
 * holding one sentence and two controls; at Events' weight that is a line of
 * text with the controls beside it.
 */
/* Kevin moved /listings/ and /events/ off Listora's full-width page template
 * onto the default one, 13 Sep 2026. Two consequences, and they pull opposite
 * ways:
 *
 *   WON  Directory now renders the theme's `header.entry-header > h1.entry-title`
 *        — a real "Directory" H1, which is exactly the thing CSS could not add
 *        honestly and which was left open as needing his call. Closed.
 *
 *   LOST every rule below used to be scoped to `.listora-page-wrap`, which the
 *        default template does not render, so all of it silently stopped
 *        applying and the header went 217px -> 479px. That was this
 *        stylesheet's fault, not the template's: anchoring to a wrapper that
 *        belongs to one page template made the rules only as durable as that
 *        choice.
 *
 * So they are re-anchored to Listora's own block classes, which travel with the
 * blocks regardless of which template renders them. `.listora-page-wrap` keeps
 * its one padding rule because the full-width template still exists and other
 * pages may yet use it.
 */
.listora-page-wrap.listora-page-wrap {
	padding-block-start: 0;
}

/* Chips and Filters on one line, the same move Groups makes above: Listora
 * renders them as siblings (`__type-tabs` then `__actions-row`) inside
 * `.listora-search`, so a wrapping row puts them together without touching the
 * markup. */
.listora-search {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--ek-dirhead-gap);
	margin-block-end: var(--ek-dirhead-gap);
}

.listora-search > * {
	flex: 1 1 100%;
	min-width: 0;
}

.listora-search > .listora-search__type-tabs {
	flex: 1 1 320px;
	margin-block-start: 0;
}

.listora-search > .listora-search__actions-row {
	flex: 0 0 auto;
}

/* The toolbar was a 66px white band holding one sentence and two controls. */
.listora-grid__toolbar {
	padding-block: 0;
	margin-block: var(--ek-dirhead-gap) 0;
	align-items: center;
}

.listora-grid__count {
	font-size: 13px;
	color: var(--ek-dir-hint);
}

/* The new title band. `:has()` scopes this to the page holding Listora's
 * blocks rather than to a page id or to every `.entry-header` on the site. */
article:has(.listora-search) .entry-header {
	margin-block-end: var(--ek-dirhead-gap);
}

article:has(.listora-search) .entry-content > *:first-child {
	margin-block-start: 0;
}

/* ── Events ──────────────────────────────────────────────────────────────
 * The model, so it is left alone but for the gap below its count line, which
 * was 27px against everything else's 12.
 */
.evnm-events-list__count {
	margin-block: 0 var(--ek-dirhead-gap);
	font-size: 13px;
	color: var(--ek-dir-hint);
}

/*
 * One gap between the blocks, not each block's own margin.
 *
 * Re-anchoring brought the bands back but the page still measured 298px of
 * header against Groups' 196, and the bands themselves only account for 202 of
 * it — the other ~96px was four inter-block gaps of ~24px each. Listora's
 * blocks carry their own vertical margins and the block editor adds its gap on
 * top, so `--ek-dirhead-gap` was being set on one element and then doubled by
 * the next one's margin.
 *
 * Owning the spacing in one place fixes it: the content column becomes a flex
 * column with a single gap, and the blocks' own margins are zeroed so they
 * cannot add to it. Scoped by `:has()` to the page holding Listora's blocks, so
 * no other page's `.entry-content` changes.
 */
article:has(.listora-search) .entry-content {
	display: flex;
	flex-direction: column;
	gap: var(--ek-dirhead-gap);
}

article:has(.listora-search) .entry-content > * {
	margin-block: 0;
}

/* Title band: match the scale Groups uses, so the two pages open the same way
 * rather than one shouting. Reign's `.entry-title` is sized for an article. */
article:has(.listora-search) .entry-title {
	font-size: 26px;
	line-height: 1.25;
	margin-block: 0;
}

/* ══════════════════════════════════════════════════════════════════════════
 * The three page titles read as one (Kevin, 13 Sep 2026).
 *
 * "Directory is the best one now. Events has too much padding at the top.
 *  Groups has some random home icon and a line below the title that both need
 *  to go. Make sure the 'Directory', 'Upcoming Events' and 'Groups' are all the
 *  same size and weight Outfit font." — and, a moment later, "Remove the count
 *  of groups it is not needed."
 *
 * Measured before changing anything, because "same font" was worth checking
 * rather than assumed — they were three different settings and only one of the
 * three was even the house face:
 *
 *   Groups      Outfit  22px  600   <- taken as canonical
 *   Events      Outfit  24px  700
 *   Directory   Inter   26px  500
 *
 * Directory was Inter because Reign's `.entry-title` is styled for an article,
 * and the earlier pass here set its SIZE without ever setting its family — the
 * kind of half-fix that looks right in a diff and wrong on the page.
 *
 * One spec now, from Groups: `--ek-font` (the child theme's Outfit stack),
 * 22px, 600.
 * ══════════════════════════════════════════════════════════════════════════ */

/* Doubled class on the Eventonomy selector for the same reason as Listora's:
 * `eklektiv-directories` depends on `eklektiv-child` and on neither vendor's
 * sheet, so load order promises nothing. The single-class version lost silently
 * — the heading kept 24px/700 while the other two moved. Third time today that
 * an un-weighted selector quietly did nothing; the habit here is to out-specify
 * a vendor rule rather than hope to follow it. */
.bn-app__region .bn-section-head__title,
article:has(.listora-search) .entry-title,
.evnm-search-filter__heading.evnm-search-filter__heading {
	font-family: var(--ek-font);
	font-size: 22px;
	font-weight: 600;
	line-height: 1.2;
	margin-block: 0;
}

/*
 * Groups: the home icon, the rule, and the count all go.
 *
 * The icon is a house glyph beside a title that already says Groups, on a page
 * reached from a nav item that also says Groups — it names the page a third
 * time in a different alphabet. The rule under the title is the only horizontal
 * line in any of the three headers, so it reads as a divider between the title
 * and a section that isn't there. The count was Kevin's separate call: a
 * member does not come to this page to learn there are nine groups.
 *
 * `display: none` on all three so they leave the accessibility tree with the
 * pixels — a screen reader should not announce a count the page no longer
 * shows, and the icon is decorative either way.
 */
/* Scoped to the GROUPS directory's own stack, not to every BuddyNext hub.
 * The first version of this used `.bn-app__region`, which also reaches the
 * member directory (`.bn-md-stack`) — and it silently hid "27 members in the
 * community" on /members/, a page Kevin had not asked about. Removing chrome
 * he asked to remove is the job; deciding for him on another screen is not. */
.bn-sd-stack .bn-section-head {
	border-block-end: 0;
}

.bn-sd-stack .bn-section-head__icon,
.bn-sd-stack .bn-section-head__subtitle {
	display: none;
}

/*
 * Events: the 32px it opens with is `.evnm-page`'s own padding, and it is the
 * only one of the three that pads above its first band — Groups starts at its
 * title and Directory at its H1.
 */
.evnm-page.evnm-page {
	padding-block-start: 0;
}

/* ══════════════════════════════════════════════════════════════════════════
 * The member directory joins the pattern (Kevin, 13 Sep 2026: "do both").
 *
 * Measured at 315px of header — the tallest of the four — against Groups 189,
 * Events 189, Directory 256. Two causes, and Kevin called both:
 *
 *   1. the same redundancy Groups had: a house icon and "27 members in the
 *      community" stacked under a title that already says Members;
 *   2. `.bn-md-strip__form` is already `display: flex` in a row with an 8px
 *      gap, but every child claims a full line, so it wraps into three:
 *      search (42) · chips (39) · then Online only + sort + view toggle (40).
 *
 * The second is the interesting one. Nothing needed restructuring — the row was
 * always a row. The children simply had no basis telling them they could share
 * it, so a control strip that fits comfortably on one line was occupying three.
 * ══════════════════════════════════════════════════════════════════════════ */

.bn-md-stack .bn-section-head {
	border-block-end: 0;
}

.bn-md-stack .bn-section-head__icon,
.bn-md-stack .bn-section-head__subtitle {
	display: none;
}

/* BuddyNext 1.1.7 markup only. 1.2.0 replaces the chips with a type dropdown
 * (`select.bn-md-strip__type`, parts/member-directory-filter-bar.php:196-207)
 * and lays search, type, online and sort out as one row with search capped at
 * 420px (bn-members.css:697-707). Kevin, 15 Sep 2026: take the vendor's row.
 * So every rule below stands down once the dropdown exists — no second deploy
 * at update time, and nothing here fights the new cap.
 *
 * The search keeps its own line; the chips take what is left and the three
 * controls sit beside them at their natural width. */
.bn-md-stack .bn-md-strip__form:not(:has(> .bn-md-strip__type)) > .bn-md-strip__search {
	flex: 1 1 100%;
}

/* 180px, not 260: the form measures 619px wide and the three controls beside
 * the chips need 362 of it (136 + 120 + 82 plus gaps). At a 260px basis the
 * chips grew to 347 and pushed the view toggle onto a line of its own, so the
 * strip stayed three rows tall and the first fix bought nothing. Measured, not
 * guessed — the first guess is what wrapped it. */
.bn-md-stack .bn-md-strip__form:not(:has(> .bn-md-strip__type)) > .bn-md-chips {
	flex: 1 1 180px;
	min-width: 0;
}

.bn-md-stack .bn-md-strip__form:not(:has(> .bn-md-strip__type)) > .bn-md-strip__online,
.bn-md-stack .bn-md-strip__form:not(:has(> .bn-md-strip__type)) > .bn-md-strip__sort,
.bn-md-stack .bn-md-strip__form:not(:has(> .bn-md-strip__type)) > .bn-md-filters__view {
	flex: 0 0 auto;
}

/* The strip sat 49px clear of the first card, against the 12px every other
 * band on these screens now uses. */
.bn-md-stack .bn-md-strip {
	padding-block-end: 0;
	margin-block-end: var(--ek-dirhead-gap);
}

/* ══════════════════════════════════════════════════════════════════════════
 * Dark mode (Kevin, 13 Sep 2026: "We need to do a dark mode audit. Look at the
 * events page search bar....that border is too beefy" — and, on the Upcoming
 * screen, "needs to follow the dark style rules we didn't know they existed
 * when we created it").
 *
 * **What he was actually looking at.** Not a heavy border. The Events search
 * bar's container was `background: #FFFFFF` with a `#E3E3E3` border, hardcoded,
 * while the inputs inside it took the vendor's dark values — so a white box was
 * showing around dark fields and reading as a thick pale ring. Everything this
 * stylesheet owns had the same problem: 148 colour literals and **not one**
 * `prefers-color-scheme` or theme-attribute block in any of our three sheets.
 * The house directory pattern was authored in light only.
 *
 * **The trigger, verified rather than assumed.** Reign's toggle writes
 * `data-bx-mode="dark"` or `"light"` on `<html>` and remembers it in
 * `localStorage['bx-color-mode']` — confirmed by reading the attribute either
 * side of a click. BuddyNext documents the same attribute as one of a canonical
 * trio and keys its own dark tokens off all three
 * (`bn-base.css:397-407`), so the trio is what is matched here.
 *
 * No `prefers-color-scheme` block: the attribute is always present and always
 * explicit, so the media query would be a second source of truth that could
 * disagree with the toggle the member actually used.
 *
 * **Why the values are BuddyNext's tokens rather than hexes of our own.**
 * `--bn-surface`, `--bn-line` and the ink scale resolve on every page we touch
 * — checked on `/events/` and `/listings/`, not only on BuddyNext's own hubs —
 * so borrowing them means our chrome sits at exactly the vendor's depth in both
 * themes, and follows if they retune. Only the brand teal stays ours.
 *
 * The teal stays put for FILLED controls (white on #0B8478 holds up on a dark
 * ground) but `--ek-dir-teal-ink` moves to the vendor's accent, because #07564E
 * as text on a dark surface is unreadable — it was chosen against white.
 * ══════════════════════════════════════════════════════════════════════════ */

[data-bn-theme="dark"],
[data-theme="dark"],
[data-bx-mode="dark"] {
	/* An explicit value, NOT var(--bn-surface) — the second time today that
	   borrowing a vendor token went wrong for the same reason as --bn-accent.
	   The token exists on every page, but it RESOLVES DIFFERENTLY: Reign
	   overrides it to #1a2028 on BuddyNext's hubs, while elsewhere it stays
	   BuddyNext's own oklch(19% 0.01 183.6). So the Groups bar came out
	   rgb(26,32,40), Listora's own bar the same by its own route, and the
	   Events bar a visibly different, slightly teal-tinted grey — on three
	   pages whose grounds are all identically rgb(35,38,47), which is exactly
	   what Kevin saw. Pinning the value is what makes the three bars agree.
	   Nothing else moves: every other surface using this token sits on a
	   BuddyNext hub, where --bn-surface was already #1a2028. */
	--ek-dir-surface:       #1a2028;
	/* The date sticker rides on an event photo, so it is not a page surface: it
	   flips to a dark chip with light type rather than borrowing --bn-surface,
	   which would leave it invisible against a dark image. */
	--ek-dir-sticker:       rgba( 20, 22, 28, 0.88 );
	--ek-dir-sticker-ink:   var(--bn-ink);
	--ek-dir-line:          var(--bn-line);
	--ek-dir-border:        var(--bn-line);
	--ek-dir-chip-border:   var(--bn-line);
	--ek-dir-chip:          var(--bn-raised);
	--ek-dir-hover:         var(--bn-raised);

	--ek-dir-heading:       var(--bn-ink);
	--ek-dir-strong:        var(--bn-ink);
	--ek-dir-ink:           var(--bn-ink-2);
	/* #A0A7B2, not var(--bn-ink-3) (14 Sep 2026). BuddyNext's ink-3 is oklch 60%,
	   which measured 4.17:1 on Eventonomy's 10.5px date labels — under the 4.5
	   floor for text that small. The 13 Sep sweep reported these clean because
	   its scanner could not read oklch() at all. #A0A7B2 clears the floor on
	   both dark surfaces while staying a step below --bn-ink-2, so muted text
	   still reads as secondary. All 21 uses are text; the two borders that
	   also take --ek-dir-muted simply get a clearer edge. */
	--ek-dir-muted:         #A0A7B2;
	--ek-dir-label:         #A0A7B2;
	--ek-dir-hint:          #A0A7B2;

	/* A 4%-black shadow is invisible on a dark ground; depth has to come from a
	   heavier scrim, the same move the vendor makes for its own overlays. */
	--ek-dir-shadow:        0 1px 2px rgba(0, 0, 0, 0.40), 0 2px 6px rgba(0, 0, 0, 0.32);

	/* Readable as TEXT on a dark surface; the light value (#07564E) was picked
	   against white and fails here.
	   
	   An explicit value, NOT var(--bn-accent). The first version of this line
	   borrowed the vendor's accent on the reasoning that BuddyNext's dark tokens
	   resolve on every page we touch — which is true, but this site overrides
	   --bn-accent to the brand teal #0B8478, so the "lift" resolved to the very
	   colour it was meant to replace. The selected chip measured 3.75:1 against
	   its own wash: below the 4.5 floor, and exactly what Kevin saw ("it is hard
	   to read the text"). Checking that a token EXISTS is not checking what it
	   RESOLVES TO. */
	--ek-dir-teal-ink:      #6FDCCB;
	--ek-dir-teal-wash:     rgba(11, 132, 120, 0.24);

	/* The selected chip's edge had the same problem as its text: #0B8478 is a
	   fill colour, and as a 1px line on a dark ground it barely separates. UI
	   components need 3:1, not 4.5:1, so this sits between the two teals. */
	--ek-dir-teal-edge:     #2FA093;

	/* Found by sweeping for contrast failures rather than by eye, after the
	   selected chip turned one up: the date sticker's month label sat at
	   3.38:1 and the queue's "Needs you" heading at 2.78:1, both because a
	   colour chosen against white was left to fend for itself on a dark
	   ground. Status colours need lifting in dark exactly as brand ones do. */
	--ek-teal-text:         #6FDCCB;
	--ek-dir-danger:        #FF9A8F;
	--ek-dir-warn:          #FDB022;
}

/*
 * One vendor surface with the same fault, on a page Kevin lives on.
 *
 * Eventonomy prints each card's date in the brand teal — `color: #0B8478`,
 * 14px/600, on the card surface. That is a FILL colour used as ink, and on a
 * dark card it measures **3.23:1**: the identical mistake our own selected chip
 * and date sticker were making, in somebody else's stylesheet. Skinning a
 * vendor surface with CSS is the posture D18 asks for, and this is one
 * declaration rather than a template.
 *
 * Light is untouched — the rule only exists inside the dark selector, where the
 * lifted ink already lives.
 */
[data-bn-theme="dark"] .evnm-events-list__date,
[data-theme="dark"] .evnm-events-list__date,
[data-bx-mode="dark"] .evnm-events-list__date {
	color: var(--ek-teal-text);
}

/* ══════════════════════════════════════════════════════════════════════════
 * Events: one bar, not boxes inside a box (Kevin, 13 Sep 2026).
 *
 * "that container behind the search bar and date pickers in the Events page is
 *  causing it to look wonky and not consistent with the Directory search bar
 *  and the Groups search bar. Find a way to fix it or hide it...it doesn't seem
 *  to add any value."
 *
 * Measured against the two he compared it to, and the container is not the odd
 * one out — it is identical to theirs:
 *
 *   Groups  .bn-filter-strip            pill: bg, border, radius 20, pad 8, h 64
 *           .bn-input                   inner: TRANSPARENT, no border
 *   Events  .evnm-search-filter__controls  pill: bg, border, radius 20, pad 8, h 64
 *           .evnm-search-filter__input     inner: OWN filled box, radius 8
 *           date inputs                    inner: OWN filled box, radius 8
 *
 * So the container is right and the contents are wrong: three filled boxes
 * sitting inside a fourth. Hiding the container would have made Events the only
 * one of the three without the house pill; making the fields transparent makes
 * it read as one bar, which is what Groups and Directory already do.
 *
 * **Why `!important`, which is not the habit here.** The rule above already
 * escalated `border` and `box-shadow` and left `background` alone, and the
 * background never applied — `background-image` computed to `none`, so the
 * whole declaration was being dropped. Tested rather than assumed: raising the
 * selector to `html body .evnm-scope … .evnm-search-filter__input` changed
 * nothing, while the same declaration with `!important` took effect
 * immediately. The winning declaration is a vendor `!important`, which
 * specificity cannot outrank. So this matches what the neighbouring lines
 * already had to do, rather than escalating on a hunch.
 * ══════════════════════════════════════════════════════════════════════════ */

.evnm-scope .evnm-search-filter__input {
	background: transparent var(--ek-dir-search-icon) no-repeat 12px 50% !important;
	/* The padding has to be escalated for the same reason the background did.
	   Once the icon finally painted at 12px, the text was still starting at
	   12px too and running straight through it: the `padding: 0 12px 0 40px`
	   on the earlier rule was being dropped by the same vendor `!important`,
	   so the icon arrived without the room it needs. Groups' input measures
	   `0px 12px 0px 40px`; this now matches it. */
	padding: 0 12px 0 40px !important;
}

.evnm-scope .evnm-search-filter__daterange input {
	background: transparent !important;
	border: 0 !important;
	box-shadow: none !important;
	border-radius: var(--ek-dir-radius-ctrl);
}

/*
 * Directory's selected filter, the sibling of the Groups chip fixed earlier.
 *
 * Kevin: "Note the selected filter on Directory still shows text too dark to
 * read. You fixed this on Group filter button." Correct — and it was a
 * different owner, which is why the earlier fix did not reach it. Groups' chip
 * is ours; Listora paints its own active pill from `--listora-primary-text`,
 * and its comment says that one token colours the directory type pill, the grid
 * view toggle and the dashboard nav item alike — all three darkened to pass
 * contrast against WHITE.
 *
 * So the token is overridden rather than the rule, which fixes all three at
 * once. Checked first that it is safe to lift: fourteen live uses are `color`,
 * and the only two that feed a background sit inside a comment block as
 * documentation examples — the ink/fill split that caught me twice today, so
 * this time it was verified before the change rather than after.
 *
 * `html[…]` rather than a bare attribute: Listora declares the token on
 * `:root`, which is the same (0,1,0) weight, and our sheet has no declared
 * order against theirs.
 */
html[data-bn-theme="dark"],
html[data-theme="dark"],
html[data-bx-mode="dark"] {
	--listora-primary-text: #6FDCCB;
}

/*
 * Avatar initials in dark, where there is no photo (Kevin, 13 Sep 2026).
 *
 * A vendor gap, not ours. BuddyNext's base rule pairs a pale background with
 * dark type — `background: var(--bn-accent-200); color: var(--bn-accent-700)`
 * (`bn-base.css:2982-2994`) — which is a LIGHT-theme pairing. Its dark override
 * then reaches only avatars carrying a tone:
 *
 *     [data-bx-mode="dark"] .bn-avatar[data-tone] { … color: oklch(96% …) }
 *     — bn-base.css:3053-3059
 *
 * The avatars on the search results page carry `data-size` and no `data-tone`,
 * so they fall straight through it. In dark the two accent steps resolve to
 * oklch L 0.374 for the disc and L 0.442 for the letters — two mid-tones within
 * 0.07 of each other, which is why the initials read as barely-there smudges.
 *
 * Only the colour is set, and at the vendor's own 96% lightness, so a toneless
 * avatar now matches what they already do for a toned one rather than inventing
 * a second treatment. The disc keeps its colour. Avatars holding a photo are
 * unaffected — the image covers the letters either way.
 */
[data-bn-theme="dark"] .bn-avatar[data-size]:not([data-tone]),
[data-theme="dark"] .bn-avatar[data-size]:not([data-tone]),
[data-bx-mode="dark"] .bn-avatar[data-size]:not([data-tone]) {
	color: oklch(96% 0.01 183.6);
}

/*
 * The Pro upsell on the search filters comes off (Kevin, 13 Sep 2026).
 *
 * "This text on this page needs to be hidden it is bad vendor practice and
 *  shows the plugin we use: Plan, group and label filters appear when BuddyNext
 *  Pro is active."
 *
 * He is right on both counts. It advertises a product the member cannot buy and
 * names the plugin the site is built on, in the middle of a filter panel — a
 * licensing detail wearing the clothes of a help hint.
 *
 * `.bn-search-aside__hint` appears exactly ONCE in the whole vendor template
 * set (`templates/search/results.php:794`), and that once is this sentence, so
 * hiding the class cannot take a useful hint down with it — checked rather than
 * assumed, because a generic-sounding class name is exactly the kind that
 * usually has three other jobs.
 *
 * `display: none` so it leaves the accessibility tree too: a screen-reader
 * member should not be read an upsell that nobody else can see.
 */
.bn-search-aside__hint {
	display: none;
}

/* ══════════════════════════════════════════════════════════════════════════
 * Dark re-sweep, now able to read oklch() (Kevin, 14 Sep 2026: R1 "Do this
 * now", R6 "Fix it", R7 "Fold into the R1 re-run").
 *
 * Why this pass exists: the contrast scanner used on 13 Sep could not parse
 * oklch() and silently skipped every colour written in it — and BuddyNext
 * authors its whole palette that way — so that day's "zero failures" covered
 * only rgb() colours. The scanner now converts OKLCH to relative luminance
 * directly, and skips (and counts) any text sitting on a background-IMAGE,
 * because a backgroundColor lookup cannot see a gradient or a photo.
 *
 * It still produced one false positive worth recording so nobody chases it:
 * Reign's header Login / Register buttons measured 1.08:1 and are plainly
 * readable — pale-blue fill, dark type. Their visible fill does not come from
 * the anchor's own background-color, so the walk up the tree composited them
 * against the dark header instead. Checked by eye; deliberately not touched.
 *
 * Everything below was measured AND confirmed. Each is the same mistake the
 * 13 Sep pass kept meeting — a colour chosen against white, left to fend for
 * itself on a dark ground — and each is fixed at its own element rather than
 * by moving a shared token, because every token involved paints fills too.
 * ══════════════════════════════════════════════════════════════════════════ */

/* Login page — "Forgot password?" and the password "Show" toggle.
 * Both are `color: var(--bn-accent)` (bn-auth.css:867, :899), and this site
 * sets --bn-accent to the brand teal #0B8478, a FILL colour: 3.58:1 as text on
 * the dark auth card. */
[data-bn-theme="dark"] .bn-auth-link,
[data-theme="dark"] .bn-auth-link,
[data-bx-mode="dark"] .bn-auth-link,
[data-bn-theme="dark"] .bn-auth-pw__toggle,
[data-theme="dark"] .bn-auth-pw__toggle,
[data-bx-mode="dark"] .bn-auth-pw__toggle {
	color: #6FDCCB;
}

/* Profile — the "Member" role under each group in a member's group list.
 * `color: var(--bn-ink-4)` (bn-profile.css:1607) — the faintest ink step, at
 * 10px mono uppercase: 2.21:1. Moved two steps up the vendor's own ink scale
 * rather than to a colour of ours, so it stays in their system. */
[data-bn-theme="dark"] .bn-space-role,
[data-theme="dark"] .bn-space-role,
[data-bx-mode="dark"] .bn-space-role {
	color: var(--bn-ink-2);
}

/* People — the "1st" connection-degree badge (R6).
 * `color: var(--bn-accent)` over a 14% accent tint of the surface
 * (bn-members.css:336-348): 3.58:1. The 2nd-degree variant already uses
 * --bn-ink-2 and passes, so it is excluded rather than overwritten. */
[data-bn-theme="dark"] .bn-md-card__degree:not([data-degree="2"]),
[data-theme="dark"] .bn-md-card__degree:not([data-degree="2"]),
[data-bx-mode="dark"] .bn-md-card__degree:not([data-degree="2"]) {
	color: #6FDCCB;
}

/* Events on a phone — the active Grid / List / Month / Upcoming tab.
 * At <=640px Eventonomy turns the segmented control into underline tabs, and
 * the active one becomes brand-teal TEXT on a transparent ground
 * (`build/blocks/search-filter/style.css`, the max-width:640px block): 3.3:1.
 * Scoped to that breakpoint on purpose — on desktop the same tab is a teal
 * FILL carrying white text, and lifting its colour there would put light teal
 * on teal. */
@media (max-width: 640px) {
	[data-bn-theme="dark"] .wp-block-eventonomy-search-filter .evnm-search-filter__view.is-active,
	[data-theme="dark"] .wp-block-eventonomy-search-filter .evnm-search-filter__view.is-active,
	[data-bx-mode="dark"] .wp-block-eventonomy-search-filter .evnm-search-filter__view.is-active {
		color: #6FDCCB;
		border-block-end-color: #6FDCCB;
	}
}

/* Listora's rating badge on a listing photo, in dark.
 *
 * `.listora-card__rating` (blocks/listing-card/style.css:172-187) is a fixed
 * `rgba(0,0,0,0.7)` scrim in BOTH themes, but its text is
 * `var(--listora-fg-inverse)` — "text on an inverted surface" — which Listora
 * flips from #ffffff to #121212 in dark. So in dark the "5.0" became near-black
 * on near-black and vanished, while light was fine.
 *
 * Fixed on the element, not the token: --listora-fg-inverse is used 82 times
 * as text but 28 times as a BACKGROUND, so lifting it would repaint fills all
 * over the directory. White, because the scrim under it never changes.
 *
 * For the record, Listora gets its trigger right: it follows the site toggle
 * via [data-bx-mode] and deliberately does not honour a bare OS dark
 * preference (listora-base.css:95-101), so no toggle bridge is needed here.
 */
[data-bn-theme="dark"] .listora-card__rating,
[data-theme="dark"] .listora-card__rating,
[data-bx-mode="dark"] .listora-card__rating {
	color: #FFFFFF;
}

/* Notifications sidecard headers ("Recent actors", "Preferences"), in dark.
 * `color: var(--bn-ink-4)` (bn-notifications.css:325-330) — BuddyNext's faintest
 * ink, oklch 45% in dark — at 2xs mono: 2.21:1. Given the site's own muted tier
 * rather than moved up the vendor scale, because --bn-ink-4 is used 53 times
 * and a scale that needs its faintest step lighter than its third to pass is a
 * vendor palette question, not ours to re-order. */
[data-bn-theme="dark"] .bn-notif-sidecard__head,
[data-theme="dark"] .bn-notif-sidecard__head,
[data-bx-mode="dark"] .bn-notif-sidecard__head {
	color: #A0A7B2;
}

/* ══════════════════════════════════════════════════════════════════════════
 * The ten badge tones, readable in dark (morning brief D6, Kevin 14 Sep 2026:
 * "Override all ten tones").
 *
 * Measured by injecting one `.bn-badge` of each tone on a dark search result
 * card (#1a2028) and reading the RESOLVED colours — not the declared ones,
 * after --bn-accent turned out to resolve differently on this site than
 * BuddyNext declares it:
 *
 *   neutral 7.71  warn 4.87  (already pass — left as they are)
 *   info 3.93  events 3.91  jetonomy 3.83  media 3.77
 *   success 3.46  danger 3.45  paid 3.26  accent 1.79
 *
 * The cause is one gap in the vendor's dark block. `bn-base.css:438-446`
 * re-declares every tone's BACKGROUND (`--bn-info-bg: oklch(25% …)`) and none
 * of their TEXT tokens, so each badge keeps its light-mode ink
 * (`--bn-info: oklch(58% …)`, lines 88-105) on a newly dark tint.
 *
 * Fixed on the badge rather than by lifting --bn-info, --bn-success and the
 * rest: those are semantic status colours used well beyond badges, and their
 * reach was not measured. Each tone keeps its own hue — through BuddyNext's own
 * --bn-hue-* and --bn-chroma for the four integration tones — and only its
 * lightness rises, to 78–80%, so a badge still reads as its colour.
 *
 * `:is()` keeps the trio in one selector at (0,3,0), above the vendor's
 * (0,2,0) `.bn-badge[data-tone="…"]`.
 * ══════════════════════════════════════════════════════════════════════════ */
:is([data-bn-theme="dark"], [data-theme="dark"], [data-bx-mode="dark"]) .bn-badge[data-tone="info"]     { color: oklch(80% 0.12 230); }
:is([data-bn-theme="dark"], [data-theme="dark"], [data-bx-mode="dark"]) .bn-badge[data-tone="success"]  { color: oklch(80% 0.13 145); }
:is([data-bn-theme="dark"], [data-theme="dark"], [data-bx-mode="dark"]) .bn-badge[data-tone="danger"]   { color: oklch(78% 0.13 25); }
:is([data-bn-theme="dark"], [data-theme="dark"], [data-bx-mode="dark"]) .bn-badge[data-tone="events"]   { color: oklch(80% var(--bn-chroma) var(--bn-hue-events)); }
:is([data-bn-theme="dark"], [data-theme="dark"], [data-bx-mode="dark"]) .bn-badge[data-tone="jetonomy"] { color: oklch(80% var(--bn-chroma) var(--bn-hue-jetonomy)); }
:is([data-bn-theme="dark"], [data-theme="dark"], [data-bx-mode="dark"]) .bn-badge[data-tone="media"]    { color: oklch(80% var(--bn-chroma) var(--bn-hue-media)); }
:is([data-bn-theme="dark"], [data-theme="dark"], [data-bx-mode="dark"]) .bn-badge[data-tone="paid"]     { color: oklch(80% var(--bn-chroma) var(--bn-hue-paid)); }
/* Accent takes the same lifted teal as the pending --bn-accent fix, so the two
   agree whichever way Kevin decides that. */
:is([data-bn-theme="dark"], [data-theme="dark"], [data-bx-mode="dark"]) .bn-badge[data-tone="accent"]   { color: #8FE6D8; }

/*
 * Post search results: the author's name is its own link (morning brief D7).
 *
 * The card is one big target — `.ek-search-row__link::after` is stretched across
 * it — so the author link has to sit ABOVE that overlay or every click on the
 * name would land on the post instead. The two anchors are siblings, never
 * nested: the post link wraps only the snippet, the name lives in the header.
 */
.bn-search-row--post .ek-search-row__author-link {
	position: relative;
	z-index: 1;
	color: inherit;
	text-decoration: none;
}

.bn-search-row--post .ek-search-row__author-link:hover {
	text-decoration: underline;
	text-underline-offset: 2px;
}

.bn-search-row--post .ek-search-row__author-link:focus-visible {
	outline: 2px solid transparent;
	outline-offset: 2px;
	box-shadow: var(--bn-ring);
	border-radius: var(--bn-r-sm, 4px);
}

/* ══════════════════════════════════════════════════════════════════════════
 * Jobs and Courses join the pattern (Kevin, 14 Sep 2026).
 *
 * "I added two new capabilities to the site: Jobs and Courses.. Apply the same
 *  standards for the pages for these plugins which we did for Events and
 *  Directory so we have full consistency across the site for look and feel"
 *
 * WP Career Board 1.7.0 (/find-jobs-2/, /companies-2/, /jobs/) and Learnomy
 * 1.9.5 (/courses/). Measured in dark at 1200px before changing anything:
 *
 *   Directory  title Outfit 22/600 at the top of the column · 64px pill
 *              search with a teal button · one gap of 12px · 13px count line
 *   Jobs       no title at all · 24px of shell padding above · a square 53px
 *              search with a pale-blue button and DARK text on it · two rows
 *              of selects (86px) · sort, count and sidebar below
 *   Companies  title Inter 25.5/700 · square 44px search · 24px gaps
 *   Courses    a "LEARN" eyebrow · title Inter 32/600 starting 75px down ·
 *              a 960px column where every other page is 1140 · blue Search
 *
 * Why both are blue on a teal site: each vendor adopts the THEME's accent,
 * Reign's `--reign-colors-theme` (#1d76da light, #97c0ee dark) — WCB through
 * integrations/reign/assets/reign-compat.css:19-26, Learnomy through its
 * Theme_Bridge inline block on `:root,.lrn-app`. Neither reads BuddyNext's
 * teal. Sources and line numbers: docs/research/Research - Jobs and Courses
 * skin (14 Sep 2026).md.
 *
 * The same moves as Events and Directory, and no more: the accent, the title
 * spec, one gap, the pill search bar, the dropdown shape, the display face,
 * the dark tokens. Neither vendor's layout is rebuilt (CLAUDE.md rule 3):
 * Jobs and Companies keep their filter sidebar, Courses keeps its filter row.
 * ══════════════════════════════════════════════════════════════════════════ */

/* ── Accent ────────────────────────────────────────────────────────────────
 * `html:root` (0,1,1) outranks both vendors' `:root` (0,1,0). Learnomy's
 * bridge also re-declares its tokens on `.lrn-app`, and its derived tokens
 * (`--lrn-accent-bg`, the color-mix hovers) are computed wherever the accent
 * is declared, so the override has to land on `.lrn-app` as well. */
html:root {
	--wcb-primary:       #0B8478;
	--wcb-primary-dark:  #0A7A6F;
	--wcb-on-primary:    #FFFFFF;
	--lrn-accent:        #0B8478;
	--lrn-accent-hover:  #0A7A6F;
}

html .lrn-app {
	--lrn-accent:        #0B8478;
	--lrn-accent-hover:  #0A7A6F;
}

/* Learnomy in LIGHT needs the same split one step down. Its course cards sit on
 * Reign's off-white body colour rather than white, and the brand teal as text
 * there measured 4.42:1 ("Enroll", "Buy", "Members only") — under the floor by
 * a hair. So its ink takes --ek-teal-text (#0A7A6F), the house's own teal for
 * text on light, and the fill token is pinned to the brand teal so the Search
 * and Enroll buttons stay the colour of every other button. `:not(…dark)` so
 * the dark block below keeps its own values without an order dependency. */
html:root:not([data-bx-mode="dark"]):not([data-bn-theme="dark"]):not([data-theme="dark"]),
html:not([data-bx-mode="dark"]):not([data-bn-theme="dark"]):not([data-theme="dark"]) .lrn-app {
	--lrn-accent:             #0A7A6F;
	--lrn-accent-hover:       #07564E;
	--lrn-accent-solid:       #0B8478;
	--lrn-accent-hover-solid: #0A7A6F;
}

/* Dark: the ink/fill split this sheet already makes for its own tokens
 * (--ek-teal-text lifts, --ek-teal-fill never moves).
 *
 * Both vendors use the accent token as TEXT far more than as a fill —
 * Learnomy's stylesheets hold 167 `color` uses against 60 backgrounds — and on
 * this site it is ALREADY a light ink in dark, because Reign's dark accent is
 * the pale #97c0ee. So lifting to #6FDCCB keeps the shape of what both vendors
 * ship today, in the house colour: every accent-coloured label and outline
 * stays readable. The fills that carry text are then handled explicitly:
 *
 *   - WCB paints text on its accent in `--wcb-on-primary` (wcb-ui.css:1313),
 *     so that becomes the dark teal ink BuddyNext's own dark accent uses.
 *   - Learnomy's primary button reads `--lrn-accent-solid` (learnomy.css:
 *     776-780), a token it keeps separate for exactly this reason; it is
 *     pinned to the fill teal so white text holds.
 *   - The Search buttons are the house control and are set below.
 *
 * `html:root[data-…]` (0,2,1) outranks reign-compat's `:root[data-bx-mode=
 * "dark"]` (0,2,0); `html[data-…] .lrn-app` (0,2,1) outranks the bridge's
 * `[data-bx-mode="dark"] .lrn-app` (0,2,0). */
html:root[data-bn-theme="dark"],
html:root[data-theme="dark"],
html:root[data-bx-mode="dark"] {
	--wcb-primary:       #6FDCCB;
	--wcb-primary-dark:  #8FE6D8;
	--wcb-on-primary:    #0B1F1C;
	/* The initials disc on a job card with no logo. Reign's bridge sets it to
	   the HEADING colour (reign-compat.css:61-63), which is white in dark, and
	   the initials are white too — so every logo-less job showed a blank white
	   square. Measured: background and text both rgb(255, 255, 255). */
	--wcb-avatar-bg:     #2A3441;
	--lrn-accent:        #6FDCCB;
	--lrn-accent-hover:  #8FE6D8;
	--lrn-accent-solid:  #0B8478;
	--lrn-accent-hover-solid: #0A7A6F;
}

html[data-bn-theme="dark"] .lrn-app,
html[data-theme="dark"] .lrn-app,
html[data-bx-mode="dark"] .lrn-app {
	--lrn-accent:        #6FDCCB;
	--lrn-accent-hover:  #8FE6D8;
	--lrn-accent-solid:  #0B8478;
	--lrn-accent-hover-solid: #0A7A6F;
}

/* ── Title band ────────────────────────────────────────────────────────────
 * The one spec, from Groups: --ek-font, 22px, 600.
 *
 * Jobs had no title at all; the child theme now prints the page's own title
 * in WCB's heading class (functions.php, "Find Jobs gets the page title").
 *
 * Learnomy pins every heading in its container to its body-text token with
 * `.lrn-container :is(h1…h6):not(…):not(…)` (learnomy.css:580), which weighs
 * (0,3,1) — hence the doubled class to reach (0,4,0). That rule is also why
 * "All Courses" was body grey rather than heading white. */
.wcb-archive-shell .wcb-page-heading.wcb-page-heading,
.lrn-container .lrn-archive-header .lrn-archive-header__title.lrn-archive-header__title {
	font-family: var(--ek-font);
	font-size: 22px;
	font-weight: 600;
	line-height: 1.2;
	letter-spacing: 0;
	margin-block: 0;
	color: var(--ek-dir-heading);
}

/* ── Jobs and Companies: one column, one gap ───────────────────────────────
 * The shell's 24px top padding (frontend-components.css:919-925) is the only
 * space above a title on any of these pages. Beneath it, each block and each
 * toolbar row brings its own 16–24px margin; the fix is the one Directory got —
 * the column owns a single gap and the children's margins are zeroed. */
.wcb-archive-shell.wcb-archive-shell {
	padding-block-start: 0;
}

.wcb-page-article.wcb-page-article,
.wcb-archive-shell .wcb-job-listings.wcb-job-listings,
.wcb-archive-shell .wcb-company-archive.wcb-company-archive {
	display: flex;
	flex-direction: column;
	gap: var(--ek-dirhead-gap);
}

.wcb-page-article.wcb-page-article > *,
.wcb-archive-shell .wcb-job-listings.wcb-job-listings > *,
.wcb-archive-shell .wcb-company-archive.wcb-company-archive > * {
	margin-block: 0;
}

/* The count is a line of text, not a band (Events: 13px, hint colour). */
.wcb-archive-shell .wcb-listings-toolbar .wcb-results-count.wcb-results-count {
	font-size: 13px;
	font-weight: 400;
	color: var(--ek-dir-hint);
}

/* ── Jobs: the search bar ──────────────────────────────────────────────────
 * WCB's job-search block is a joined square (job-search/style.css:17-30); it
 * becomes the house pill — 8px inside, 20px corners, a transparent field with
 * the search mark, and the teal button inside the bar.
 *
 * `flex-direction: row` is stated because the vendor stacks the field and the
 * button into a column at 480px and drops the pill; the house bar stays one
 * bar on a phone, as Groups and Events do. */
.wcb-archive-shell .wp-block-wp-career-board-job-search .wcb-search-form.wcb-search-form {
	flex-direction: row;
	align-items: center;
	gap: 8px;
	padding: 8px;
	overflow: visible;
	background: var(--ek-dir-surface);
	border: 1px solid var(--ek-dir-border);
	border-radius: var(--ek-dir-radius-bar);
	box-shadow: var(--ek-dir-shadow);
	transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.wcb-archive-shell .wp-block-wp-career-board-job-search .wcb-search-form.wcb-search-form:focus-within {
	border-color: var(--ek-dir-teal);
	box-shadow: 0 0 0 3px var(--ek-dir-teal-wash), var(--ek-dir-shadow);
}

.wcb-archive-shell .wp-block-wp-career-board-job-search .wcb-search-form .wcb-search-input[type="search"] {
	height: 46px;
	min-height: 46px;
	padding: 0 12px 0 40px;
	border: 0;
	border-radius: 0;
	box-shadow: none;
	background: transparent var(--ek-dir-search-icon) no-repeat 12px 50%;
	font-size: 17px;
	color: var(--ek-dir-strong);
}

.wcb-archive-shell .wp-block-wp-career-board-job-search .wcb-search-form .wcb-search-input[type="search"]:focus {
	outline: none;
	border: 0;
	box-shadow: none;
}

.wcb-archive-shell .wp-block-wp-career-board-job-search .wcb-search-form .wcb-search-button.wcb-search-button {
	flex: 0 0 auto;
	min-height: 46px;
	padding: 0 18px;
	border-radius: var(--ek-dir-radius-ctrl);
	background: var(--ek-dir-teal);
	color: #FFFFFF;
	font-family: var(--ek-dir-display);
	font-size: 13px;
	font-weight: 500;
}

.wcb-archive-shell .wp-block-wp-career-board-job-search .wcb-search-form .wcb-search-button.wcb-search-button:hover,
.wcb-archive-shell .wp-block-wp-career-board-job-search .wcb-search-form .wcb-search-button.wcb-search-button:focus {
	background: var(--ek-dir-teal-hover);
	color: #FFFFFF;
}

.wcb-archive-shell .wp-block-wp-career-board-job-search .wcb-search-form .wcb-search-button.wcb-search-button:focus-visible {
	outline: 2px solid var(--ek-dir-teal-ink);
	outline-offset: 2px;
}

/* ── Companies (and the /jobs/ archive): the search row ────────────────────
 * These pages use WCB's shared toolbar search instead (templates/parts/
 * archive-toolbar.php), a field with no button because it filters as you
 * type. It takes the same 64px pill so the band is the same height as every
 * other search on the site.
 *
 * `!important` on the start padding only: reign-compat.css:88-90 sets
 * `padding-inline-start: 2.25rem !important` on this field, which no
 * specificity can outrank, and the search mark moves 8px right with the
 * wider pill. */
.wcb-archive-shell .wcb-search-sort-row .wcb-search-wrap .wcb-listings-search.wcb-listings-search {
	height: 64px;
	min-height: 64px;
	padding-block: 0;
	padding-inline: 48px 16px !important;
	background: var(--ek-dir-surface);
	border: 1px solid var(--ek-dir-border);
	border-radius: var(--ek-dir-radius-bar);
	box-shadow: var(--ek-dir-shadow);
	font-size: 17px;
	color: var(--ek-dir-strong);
	transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.wcb-archive-shell .wcb-search-sort-row .wcb-search-wrap .wcb-listings-search.wcb-listings-search:focus {
	outline: 2px solid transparent;
	border-color: var(--ek-dir-teal);
	box-shadow: 0 0 0 3px var(--ek-dir-teal-wash), var(--ek-dir-shadow);
}

.wcb-archive-shell .wcb-search-sort-row .wcb-search-wrap .wcb-search-icon.wcb-search-icon {
	inset-inline-start: 20px;
}

/* ── Dropdowns: Listora's shape ────────────────────────────────────────────
 * 44px, 10px corners, the bar's light border, 13px regular — the Groups Sort
 * control. `background-color` rather than `background`, so the vendors' own
 * painted carets survive. */
.wcb-archive-shell .wcb-sort-select.wcb-sort-select,
.wcb-archive-shell .wcb-filters-row .wcb-filter-select.wcb-filter-select,
.lrn-filter-bar .lrn-select.lrn-select {
	width: auto;
	height: 44px;
	min-height: 44px;
	padding-block: 0;
	padding-inline: 14px 36px;
	border: 1px solid var(--ek-dir-border);
	border-radius: 10px;
	background-color: var(--ek-dir-surface);
	color: var(--ek-dir-ink);
	font-family: var(--ek-dir-display);
	font-size: 13px;
	font-weight: 400;
	line-height: 42px;
}

.wcb-archive-shell .wcb-filters-row .wcb-filter-input.wcb-filter-input {
	height: 44px;
	padding-block: 0;
	padding-inline: 14px;
	border: 1px solid var(--ek-dir-border);
	border-radius: 10px;
	background: var(--ek-dir-surface);
	color: var(--ek-dir-ink);
	font-size: 13px;
}

.wcb-archive-shell .wcb-sort-select.wcb-sort-select:focus-visible,
.wcb-archive-shell .wcb-filters-row .wcb-filter-select.wcb-filter-select:focus-visible,
.wcb-archive-shell .wcb-filters-row .wcb-filter-input.wcb-filter-input:focus-visible,
.lrn-filter-bar .lrn-select.lrn-select:focus-visible {
	outline: 2px solid var(--ek-dir-teal);
	outline-offset: 2px;
}

/* ── Jobs: the filter row on ONE line ──────────────────────────────────────
 * Four selects each claimed `flex: 1` of a full row, which pushed salary and
 * Remote only onto a second line (job-filters/style.css:9-17). With a 150px
 * basis the seven controls share the 1140px column as one band — the chip
 * band every other directory has. */
.wcb-archive-shell .wcb-filters-row.wcb-filters-row {
	flex-wrap: wrap;
	align-items: center;
	gap: 8px;
}

.wcb-archive-shell .wcb-filters-row .wcb-filter-select.wcb-filter-select {
	flex: 1 1 150px;
	min-width: 0;
}

.wcb-archive-shell .wcb-filters-row .wcb-filter-salary.wcb-filter-salary {
	gap: 8px;
}

.wcb-archive-shell .wcb-filters-row .wcb-filter-salary .wcb-filter-input.wcb-filter-input {
	width: 110px;
}

.wcb-archive-shell .wcb-filters-row .wcb-filter-remote.wcb-filter-remote {
	padding-inline: 4px;
	font-size: 13px;
	color: var(--ek-dir-ink);
}

/* Phones: the vendor stacks all seven into a column (job-filters/style.css:
 * 52-62), which is 7 × 44px of controls before the first job. The house
 * answer is the chip row's: one line that scrolls sideways under a fade. */
@media (max-width: 640px) {
	.wcb-archive-shell .wcb-filters-row.wcb-filters-row {
		flex-direction: row;
		flex-wrap: nowrap;
		padding-block: 2px;
		overflow-x: auto;
		overflow-y: hidden;
		scrollbar-width: none;
		-webkit-mask-image: linear-gradient(to right, #000 calc(100% - 28px), transparent);
		mask-image: linear-gradient(to right, #000 calc(100% - 28px), transparent);
	}

	.wcb-archive-shell .wcb-filters-row.wcb-filters-row::-webkit-scrollbar { display: none; }

	.wcb-archive-shell .wcb-filters-row .wcb-filter-select.wcb-filter-select {
		flex: 0 0 auto;
		width: auto;
		min-width: 150px;
	}

	.wcb-archive-shell .wcb-filters-row .wcb-filter-salary.wcb-filter-salary {
		flex: 0 0 auto;
		width: auto;
	}

	.wcb-archive-shell .wcb-filters-row .wcb-filter-salary .wcb-filter-input.wcb-filter-input {
		flex: 0 0 96px;
		width: 96px;
	}

	.wcb-archive-shell .wcb-filters-row .wcb-filter-remote.wcb-filter-remote {
		flex: 0 0 auto;
	}
}

/* ── Grid/list toggles: one bordered control, the selected half in teal ─── */
.wcb-archive-shell .wcb-view-switcher.wcb-view-switcher,
.lrn-filter-bar .lrn-filter-bar__view-toggle.lrn-filter-bar__view-toggle {
	padding: 1px;
	gap: 2px;
	background: var(--ek-dir-surface);
	border: 1px solid var(--ek-dir-border);
	border-radius: 10px;
}

.wcb-archive-shell .wcb-view-switcher .wcb-layout-btn.wcb-layout-btn,
.lrn-filter-bar .lrn-btn.lrn-view-btn.lrn-view-btn {
	width: 40px;
	height: 40px;
	min-width: 40px;
	min-height: 40px;
	border: 0;
	border-radius: 8px;
	color: var(--ek-dir-muted);
	font-family: inherit;
}

.wcb-archive-shell .wcb-view-switcher .wcb-layout-btn.wcb-layout-btn.wcb-active,
.lrn-filter-bar .lrn-btn.lrn-view-btn.lrn-view-btn.is-active {
	background: var(--ek-dir-teal-wash);
	color: var(--ek-dir-teal-ink);
	box-shadow: none;
}

/* ── Jobs and Companies: the filter sidebar as the house panel ─────────────
 * The panel's own values (wcb-ui.css:837-975) replaced with the Groups
 * Filters panel's: the page surface, 14px corners, 17px inside, uppercase
 * labels in the label colour, 18px teal checkboxes. */
.wcb-archive-shell .wcb-filter-panel.wcb-filter-panel {
	padding: 17px;
	background: var(--ek-dir-surface);
	border: 1px solid var(--ek-dir-border);
	border-radius: var(--ek-dir-radius-panel);
	box-shadow: none;
}

.wcb-archive-shell .wcb-filter-panel .wcb-filter-panel__heading.wcb-filter-panel__heading {
	font-family: var(--ek-dir-display);
	font-size: 15px;
	font-weight: 600;
	color: var(--ek-dir-strong);
}

.wcb-archive-shell .wcb-filter-panel .wcb-filter-panel__group-title.wcb-filter-panel__group-title {
	font-family: var(--ek-dir-display);
	font-size: 12.75px;
	font-weight: 600;
	letter-spacing: 0.05em;
	color: var(--ek-dir-label);
}

.wcb-archive-shell .wcb-filter-panel .wcb-filter-panel__option.wcb-filter-panel__option {
	gap: 10px;
	font-size: 14px;
	color: var(--ek-dir-ink);
}

.wcb-archive-shell .wcb-filter-panel .wcb-filter-panel__option.wcb-filter-panel__option:hover {
	background: var(--ek-dir-hover);
	color: var(--ek-dir-strong);
}

.wcb-archive-shell .wcb-filter-panel .wcb-filter-panel__option input[type="checkbox"],
.wcb-archive-shell .wcb-filter-panel .wcb-filter-panel__option input[type="radio"],
.wcb-archive-shell .wcb-filters-row .wcb-filter-remote input[type="checkbox"] {
	width: 18px;
	height: 18px;
	accent-color: var(--ek-dir-teal);
}

/* ── Courses: the column, the header, one gap ──────────────────────────────
 * `:has(> .lrn-filter-bar)` picks out the catalog's container from Learnomy's
 * many others (lesson player, checkout, dashboards), so nothing else widens.
 *
 * Width: `.lrn-container` caps at 960px and pads 32px/16px (learnomy.css:
 * 567-571). The theme's content column is already 1140 on this page, exactly
 * as it is on Directory and Events, so the cap is lifted rather than a width
 * chosen. */
.lrn-container.lrn-container:has(> .lrn-filter-bar) {
	display: flex;
	flex-direction: column;
	gap: var(--ek-dirhead-gap);
	max-width: none;
	padding: 0;
}

.lrn-container.lrn-container:has(> .lrn-filter-bar) > * {
	margin-block: 0;
}

/* Title and count on one line, sharing a baseline — the Groups header before
 * its count was removed. The rule under the header goes for the reason the
 * Groups one did: it is the only divider in any of the headers.
 *
 * The "LEARN" eyebrow goes for the reason the Groups house icon did: it names
 * the page a second time, above a title reached from a nav item that says
 * Courses. `display: none`, so it leaves the accessibility tree with the
 * pixels. */
.lrn-container .lrn-archive-header.lrn-archive-header {
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	gap: 4px 10px;
	margin: 0;
	padding: 0;
	border: 0;
}

.lrn-container .lrn-archive-header .lrn-archive-header__eyebrow {
	display: none;
}

.lrn-container .lrn-archive-header .lrn-archive-header__count.lrn-archive-header__count {
	margin: 0;
	font-size: 13px;
	color: var(--ek-dir-hint);
}

/* ── Courses: the search bar ───────────────────────────────────────────────
 * Learnomy prints the field, the Search button, both selects and the view
 * toggle as five siblings in one form (templates/catalog/grid.php:65-127).
 * Groups and Events carry the button INSIDE the bar, so the form becomes a
 * two-row grid and the button shares the search field's cell: the field's
 * wrapper paints the pill, and the button sits in its right-hand end. The
 * markup does not change — the form, its submit and the typeahead (which is
 * positioned inside the same wrapper) all behave as they did. */
.lrn-filter-bar .lrn-filter-bar__form.lrn-filter-bar__form {
	display: grid;
	grid-template-columns: max-content max-content minmax(0, 1fr) auto;
	grid-template-areas:
		"search search search search"
		"cat    sort   .      view";
	align-items: center;
	gap: var(--ek-dirhead-gap) 8px;
}

.lrn-filter-bar__form > .lrn-filter-bar__search.lrn-filter-bar__search {
	grid-area: search;
	min-width: 0;
	padding: 8px;
	background: var(--ek-dir-surface);
	border: 1px solid var(--ek-dir-border);
	border-radius: var(--ek-dir-radius-bar);
	box-shadow: var(--ek-dir-shadow);
	transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.lrn-filter-bar__form > .lrn-filter-bar__search.lrn-filter-bar__search:focus-within {
	border-color: var(--ek-dir-teal);
	box-shadow: 0 0 0 3px var(--ek-dir-teal-wash), var(--ek-dir-shadow);
}

.lrn-filter-bar__form > .lrn-filter-bar__submit  { grid-area: search; }
.lrn-filter-bar__form > .lrn-filter-bar__category { grid-area: cat; }
.lrn-filter-bar__form > .lrn-filter-bar__sort     { grid-area: sort; }
.lrn-filter-bar__form > .lrn-filter-bar__view-toggle { grid-area: view; }

/* 104px of end padding is the button's width plus the 8px it sits in from the
 * pill's edge, so typed text never runs underneath it. */
.lrn-filter-bar .lrn-filter-bar__search .lrn-input.lrn-input {
	height: 46px;
	padding: 0 104px 0 40px;
	border: 0;
	border-radius: 0;
	box-shadow: none;
	background: transparent var(--ek-dir-search-icon) no-repeat 12px 50%;
	font-size: 17px;
	color: var(--ek-dir-strong);
}

.lrn-filter-bar .lrn-filter-bar__search .lrn-input.lrn-input:focus {
	outline: none;
	box-shadow: none;
}

.lrn-filter-bar .lrn-btn.lrn-filter-bar__submit.lrn-filter-bar__submit {
	justify-self: end;
	align-self: center;
	position: relative;
	z-index: 1;
	min-height: 46px;
	height: 46px;
	margin-inline-end: 9px; /* the pill's 8px padding plus its 1px border */
	padding: 0 18px;
	border: 1px solid var(--ek-dir-teal);
	border-radius: var(--ek-dir-radius-ctrl);
	background: var(--ek-dir-teal);
	color: #FFFFFF;
	font-family: var(--ek-dir-display);
	font-size: 13px;
	font-weight: 500;
}

.lrn-filter-bar .lrn-btn.lrn-filter-bar__submit.lrn-filter-bar__submit:hover {
	background: var(--ek-dir-teal-hover);
	border-color: var(--ek-dir-teal-hover);
	color: #FFFFFF;
}

.lrn-filter-bar .lrn-btn.lrn-filter-bar__submit.lrn-filter-bar__submit:focus-visible {
	outline: 2px solid var(--ek-dir-teal-ink);
	outline-offset: 2px;
}

/* Phones: category and sort share the second row; the toggle keeps its end. */
@media (max-width: 640px) {
	.lrn-filter-bar .lrn-filter-bar__form.lrn-filter-bar__form {
		grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) auto;
		grid-template-areas:
			"search search search"
			"cat    sort   view";
	}

	.lrn-filter-bar .lrn-select.lrn-select {
		width: 100%;
	}
}

/* ── Our faces ─────────────────────────────────────────────────────────────
 * Outfit takes the display roles here as on the other directories: page and
 * card titles, buttons, labels. Inter keeps body copy, meta and inputs. Both
 * vendors set `font-family: inherit` on these, so a class and a parent is
 * enough to land. */
.wcb-archive-shell .wcb-card-title,
.wcb-archive-shell .wcb-card-title-link,
.wcb-archive-shell .wcb-ca-name,
.wcb-archive-shell .wcb-cbtn,
.lrn-course-card .lrn-course-card__title {
	font-family: var(--ek-dir-display);
}

/* The initials on a logo-less job or company, in dark. The disc was fixed with
 * --wcb-avatar-bg above, but the letters take `--wcb-on-primary` — correct for
 * a teal button, and exactly wrong once that token became dark ink for the
 * lifted accent. Measured 1.36:1 after the first pass, on all three pages.
 * Light is untouched: there the disc is dark and the letters white. */
html[data-bn-theme="dark"] .wcb-archive-shell :is(.wcb-card-avatar, .wcb-ca-avatar),
html[data-theme="dark"] .wcb-archive-shell :is(.wcb-card-avatar, .wcb-ca-avatar),
html[data-bx-mode="dark"] .wcb-archive-shell :is(.wcb-card-avatar, .wcb-ca-avatar) {
	color: #E6E8EB;
}

/* Course card meta that failed in one theme or both. Learnomy's own values,
 * measured on the cards at /courses/:
 *
 *   review count "(3)"   body colour at 55% alpha   light 2.78  dark 3.77
 *   rating "★ 4.7"       --lrn-warn #d97706          light 3.08
 *   "Free"               --lrn-success #2ea44f       light 3.10
 *
 * The count takes the hint ink every other secondary line on these pages uses,
 * in both themes. The star takes --ek-dir-warn, the house status amber, which
 * is already #B54708 in light and #FDB022 in dark. "Free" (and "Included",
 * which shares its colour, learnomy.css:1064-1066) takes Learnomy's own darker
 * green, `--lrn-success-dark` (learnomy.css:107), in light only — that token
 * does not lift for dark, where the original green already passes. */
.lrn-course-card .lrn-course-card__review-count.lrn-course-card__review-count {
	color: var(--ek-dir-hint);
}

.lrn-course-card .lrn-course-card__rating.lrn-course-card__rating {
	color: var(--ek-dir-warn);
}

html:not([data-bx-mode="dark"]):not([data-bn-theme="dark"]):not([data-theme="dark"]) .lrn-course-card :is(.lrn-course-card__price--free, .lrn-course-card__price--included) {
	color: var(--lrn-success-dark, #1A7C3B);
}

/* Card corners: 12px, matching Companies, Courses and Events. The job card
 * alone came out at 6px, because its radius token reads Reign's global radius
 * first (frontend-tokens.css:43-44). */
.wcb-archive-shell .wcb-job-card.wcb-job-card {
	border-radius: 12px;
}

/* ══════════════════════════════════════════════════════════════════════════
 * Upcoming: the event name is a link in the asks, and the people going open
 * into a list (Kevin, 14 Sep 2026).
 *
 * "I need to be able to click the title of the event and go to the event
 *  page. I also want to find a way to click on the people coming and see a
 *  list of them that clicks through to the profile of the person."
 *
 * The card titles were links already (Upcoming::render_card) but styled as
 * heading text; the "Needs you" asks had no link at all. The event name in an
 * ask now carries `.ek-queue__event`, teal so it reads as somewhere to go.
 *
 * The faces line is a native <details>: no script, keyboard and screen-reader
 * behaviour for free, and it works inside the card's flow on a phone. The
 * summary is the exact line that was there; the disclosure is signalled by the
 * cursor and a small chevron, not by restyling the line.
 * ══════════════════════════════════════════════════════════════════════════ */
.ek-queue__q .ek-queue__event {
	color: var( --ek-teal-text, #0A7A6F );
	text-decoration: none;
}

.ek-queue__q .ek-queue__event:hover,
.ek-queue__q .ek-queue__event:focus-visible {
	text-decoration: underline;
	text-underline-offset: 2px;
}

details.ek-upcoming__whos {
	display: block;
}

.ek-upcoming__whos-summary {
	display: flex;
	align-items: center;
	gap: 7px;
	min-width: 0;
	list-style: none;
	cursor: pointer;
	border-radius: 6px;
}

.ek-upcoming__whos-summary::-webkit-details-marker { display: none; }

/* The chevron: after the text, turned when open. */
.ek-upcoming__whos-summary::after {
	content: "";
	flex: 0 0 auto;
	width: 8px;
	height: 8px;
	margin-left: 2px;
	border-right: 1.5px solid var( --ek-dir-muted, #667085 );
	border-bottom: 1.5px solid var( --ek-dir-muted, #667085 );
	transform: translateY(-2px) rotate(45deg);
	transition: transform 0.15s ease;
}

details[open] > .ek-upcoming__whos-summary::after {
	transform: translateY(1px) rotate(-135deg);
}

.ek-upcoming__whos-summary:hover .ek-upcoming__whos-text,
.ek-upcoming__whos-summary:focus-visible .ek-upcoming__whos-text {
	text-decoration: underline;
	text-underline-offset: 2px;
}

.ek-upcoming__whos-summary:focus-visible {
	outline: 2px solid var( --ek-dir-teal, #0B8478 );
	outline-offset: 2px;
}

.ek-upcoming__going {
	display: flex;
	flex-direction: column;
	gap: 2px;
	margin: 8px 0 0;
	padding: 8px 0 0;
	list-style: none;
	border-top: 1px solid var( --ek-dir-line, #E4E7EC );
}

.ek-upcoming__going-item { margin: 0; }

.ek-upcoming__going-link {
	display: flex;
	align-items: center;
	gap: 8px;
	min-height: 36px;
	padding: 4px 6px;
	margin: 0 -6px;
	border-radius: 8px;
	color: var( --ek-dir-heading, #101828 );
	text-decoration: none;
}

a.ek-upcoming__going-link:hover,
a.ek-upcoming__going-link:focus-visible {
	background: var( --ek-dir-hover, #F4F6F8 );
}

a.ek-upcoming__going-link:focus-visible {
	outline: 2px solid var( --ek-dir-teal, #0B8478 );
	outline-offset: -2px;
}

.ek-upcoming__going-img {
	flex: 0 0 auto;
	width: 24px;
	height: 24px;
	border-radius: 999px;
	object-fit: cover;
}

.ek-upcoming__going-name {
	min-width: 0;
	font-family: var( --ek-dir-display, Outfit, system-ui, sans-serif );
	font-size: 13px;
	font-weight: 600;
	line-height: 1.3;
	overflow-wrap: anywhere;
}

a.ek-upcoming__going-link:hover .ek-upcoming__going-name {
	text-decoration: underline;
	text-underline-offset: 2px;
}

.ek-upcoming__going-rest {
	margin: 2px 0 0;
	padding: 0 0 0 38px; /* under the names, past the avatar column */
	font-family: var( --ek-dir-body, Inter, system-ui, sans-serif );
	font-size: 12px;
	color: var( --ek-dir-muted, #667085 );
}

/* ══════════════════════════════════════════════════════════════════════════
 * Jobs and Companies: the filter panel collapses on a tablet as it does on a
 * phone (Kevin, 14 Sep 2026).
 *
 * "on my tablet, the jobs page shows all the filters before the cards. on
 *  mobile phone it collapses into a drop down. can we make it work the same
 *  on the tablet as on phone"
 *
 * Two vendor breakpoints that do not meet. WP Career Board stacks its two
 * columns — filter panel above the cards — at 900px (wcb-ui.css:747-751),
 * but only collapses the panel behind its chevron at 640px (:977-1043). So
 * every width between, which is every tablet held upright, gets the whole
 * panel — seven groups of checkboxes — before the first job. Nothing is
 * built here: the vendor's own collapse is a hidden checkbox, a <label>
 * chevron and sibling selectors, all present in the markup at every width;
 * these rules are its 640px block restated for the widths where the panel is
 * already stacked, so the two breakpoints finally agree. The chevron is the
 * vendor's; collapsed by default, as on a phone. Above 900px the panel is a
 * sidebar and stays open.
 * ══════════════════════════════════════════════════════════════════════════ */
@media (min-width: 641px) and (max-width: 900px) {
	.wcb-archive-shell .wcb-filter-panel .wcb-filter-panel__toggle {
		display: inline-flex;
		align-items: center;
		justify-content: center;
		width: 32px;
		height: 32px;
		margin-inline-start: auto;
		flex-shrink: 0;
		border-radius: var(--ek-dir-radius-ctrl);
		color: var(--ek-dir-muted);
		cursor: pointer;
	}

	.wcb-archive-shell .wcb-filter-panel .wcb-filter-panel__toggle:hover {
		background: var(--ek-dir-hover);
		color: var(--ek-dir-strong);
	}

	.wcb-archive-shell .wcb-filter-panel .wcb-filter-panel__toggle svg {
		width: 16px;
		height: 16px;
		transition: transform 0.2s ease;
	}

	.wcb-archive-shell .wcb-filter-panel .wcb-filter-panel__toggle-input:focus-visible ~ .wcb-filter-panel__header .wcb-filter-panel__toggle {
		outline: 2px solid var(--ek-dir-teal);
		outline-offset: 2px;
	}

	/* Collapsed: the header alone, no divider, no groups, no Clear all. */
	.wcb-archive-shell .wcb-filter-panel .wcb-filter-panel__toggle-input:not(:checked) ~ .wcb-filter-panel__header {
		padding-bottom: 0;
		border-bottom: 0;
		margin-bottom: 0;
	}

	.wcb-archive-shell .wcb-filter-panel .wcb-filter-panel__toggle-input:not(:checked) ~ .wcb-filter-panel__group,
	.wcb-archive-shell .wcb-filter-panel .wcb-filter-panel__toggle-input:not(:checked) ~ .wcb-filter-panel__header .wcb-filter-panel__clear {
		display: none;
	}

	/* Open: chevron turned, the header's divider back. */
	.wcb-archive-shell .wcb-filter-panel .wcb-filter-panel__toggle-input:checked ~ .wcb-filter-panel__header .wcb-filter-panel__toggle svg {
		transform: rotate(180deg);
	}
}

/* ══════════════════════════════════════════════════════════════════════════
 * Jobs and Companies: the header keeps its full width (Kevin, 14 Sep 2026).
 *
 * "Look at the header on the Jobs page. it has some padding on both left and
 *  right which reduces the width just enough to cause the last menu item to
 *  be ... can you remove that space only on the header so all below it stays
 *  as is?"
 *
 * WP Career Board puts `wcb-page` on the <body> of every page it owns
 * (core/class-plugin.php:564) and, at 1024px and below, pads that class on
 * both sides (wcb-ui.css:1202-1204, `padding-inline: var(--wcb-space-md)` =
 * 12px). Meant for its own content wrapper, on the body it narrows the site
 * header too — 957px against 996px on Events at the same width — which is
 * enough for Reign's menu to fold "Courses" into its "…" item.
 *
 * First cut gave the header the inverse margin and left the body's padding
 * for the content. Kevin, a minute later: "it is funny at the width right now
 * on the screen in this browser it adds the spacing left and right. larger
 * width does not include the spacing" — the padding only exists between 641
 * and 1024px, so a laptop window got a gutter a desktop one never did, and
 * the content sat 28px in (12 body + 16 shell) against Events' 15. So the
 * body padding goes entirely: `.wcb-archive-shell` already carries its own
 * 16px gutter (12px at ≤768, frontend-components.css:919-935), which is what
 * every wider width shows. Jobs now matches Events at every width. Doubled
 * class to outrank the vendor's single one at the same breakpoint.
 * ══════════════════════════════════════════════════════════════════════════ */
@media (max-width: 1024px) {
	body.wcb-page.wcb-page {
		padding-inline: 0;
	}
}

/* ══════════════════════════════════════════════════════════════════════════
 * Articles joins the pattern (Kevin, 15 Sep 2026: "apply our page styling for
 * light and dark mode to this page").
 *
 * /articles/ is a WordPress page holding WB Member Blog 4.1.0's
 * `[bp-member-blog-recent show_search="yes" show_filter="yes"]`. Measured at
 * 1200px in light before changing anything, against Directory on the same
 * 1140px column:
 *
 *   Directory  title Outfit 22/600 at 130 · 12px · 64px pill search with the
 *              teal button inside · 12px cards
 *   Articles   title Inter 38/500 at 130 with a 23px margin · a grey 76px
 *              panel holding a square 42px field, a 42px select and a 37px
 *              BLUE "Filter" button (Arial) · 10px cards, Inter titles
 *
 * Blue for the reason Jobs and Courses were: Member Blog's accent reads the
 * THEME's, `--bpmb-primary: var(--bx-color-accent, var(--color-theme-primary,
 * var(--reign-colors-theme, …)))` (public/css/bpmb-ui.css:68), which is Reign's
 * #1d76da in light and #97c0ee in dark. Dark-mode scan before: one failure,
 * white "Filter" on #97c0ee at 1.89:1; every other surface already follows
 * Reign's dark tokens (bpmb-ui.css:574-600,738-745).
 *
 * The same moves as the other directories and no more (CLAUDE.md rule 3): the
 * accent, the title spec, one gap, the pill search, the dropdown shape, the
 * display face. Member Blog's markup (PostCardRenderer::filter_bar(),
 * src/Rendering/PostCardRenderer.php:790-850) is untouched. Scoped to the
 * list's own wrapper and `article:has()` of it, never to a page id or template.
 * ══════════════════════════════════════════════════════════════════════════ */

/* ── Accent ────────────────────────────────────────────────────────────────
 * Member Blog's derived tokens (`--bpmb-primary-ink`, `-filled`, `-light`,
 * `-dark`) are computed on `:root` from the blue, so each one the list uses is
 * re-declared here with the house value rather than only `--bpmb-primary`.
 * The vendor's own split is kept: ink for accent text, filled for a surface
 * carrying `--bpmb-on-primary`. In dark the vendor expects a PALE accent with
 * dark text on it (bpmb-ui.css:582-590), so the dark values follow that shape
 * in the house teal: #6FDCCB ink, #0B1F1C on it. */
.bpmb-recent-posts-wrap {
	--bpmb-primary:        #0B8478;
	--bpmb-accent:         #0B8478;
	--bpmb-link-color:     #0A7A6F;
	--bpmb-primary-ink:    #0A7A6F;
	--bpmb-primary-filled: #0A7A6F;
	--bpmb-primary-dark:   #0A7A6F;
	--bpmb-primary-light:  rgba(11, 132, 120, 0.10);
	--bpmb-on-primary:     #FFFFFF;
}

:is([data-bn-theme="dark"], [data-theme="dark"], [data-bx-mode="dark"]) .bpmb-recent-posts-wrap {
	--bpmb-primary:        #6FDCCB;
	--bpmb-accent:         #6FDCCB;
	--bpmb-link-color:     #6FDCCB;
	--bpmb-primary-ink:    #6FDCCB;
	--bpmb-primary-filled: #6FDCCB;
	--bpmb-primary-dark:   #8FE6D8;
	--bpmb-primary-light:  rgba(111, 220, 203, 0.16);
	--bpmb-on-primary:     #0B1F1C;
}

/* Read More hovers to `--bpmb-primary` with `--bpmb-text-light` (white) on it
 * (bp-member-blog-shortcodes.css:326-329): fine on the light teal, too faint on
 * the pale dark one, so the dark hover carries the dark ink instead. */
:is([data-bn-theme="dark"], [data-theme="dark"], [data-bx-mode="dark"]) .bpmb-recent-posts-wrap .bpmb-read-more:hover {
	color: #0B1F1C;
}

/* ── Title band ────────────────────────────────────────────────────────────
 * Directory's rules (`article:has(.listora-search)` above), anchored to Member
 * Blog's list instead. */
article:has(.bpmb-recent-posts-wrap) .entry-header {
	margin-block-end: var(--ek-dirhead-gap);
}

article:has(.bpmb-recent-posts-wrap) .entry-title {
	font-family: var(--ek-dir-display);
	font-size: 22px;
	font-weight: 600;
	line-height: 1.2;
	letter-spacing: 0;
	margin-block: 0;
	color: var(--ek-dir-heading);
}

article:has(.bpmb-recent-posts-wrap) .entry-content > *:first-child {
	margin-block-start: 0;
}

/* ── The search bar ────────────────────────────────────────────────────────
 * Member Blog prints the search field, the category select and a Filter/Clear
 * actions group as siblings in one form. As on Courses, the form becomes a
 * two-row grid: the search field's wrapper paints the pill, the actions share
 * its cell at the right-hand end, and the select sits below. The grey panel
 * the vendor paints around the whole form (bp-member-blog-shortcodes.css:
 * 32-43) goes; the pill is the bar. A list with only a search, or only a
 * category, collapses to one row. */
.bpmb-recent-posts-wrap .bpmb-archive-filters.bpmb-archive-filters {
	display: grid;
	grid-template-columns: max-content minmax(0, 1fr);
	grid-template-areas:
		"search search"
		"cat    .";
	align-items: center;
	gap: var(--ek-dirhead-gap) 8px;
	margin: 0 0 var(--ek-dirhead-gap);
	padding: 0;
	background: none;
	border: 0;
	border-radius: 0;
}

.bpmb-recent-posts-wrap .bpmb-archive-filters.bpmb-archive-filters:not(:has(.bpmb-archive-filters__category)) {
	grid-template-areas: "search search";
}

.bpmb-recent-posts-wrap .bpmb-archive-filters.bpmb-archive-filters:not(:has(.bpmb-archive-filters__search)) {
	grid-template-areas: "cat actions";
}

.bpmb-archive-filters > .bpmb-archive-filters__search.bpmb-archive-filters__search {
	grid-area: search;
	min-width: 0;
	padding: 8px;
	background: var(--ek-dir-surface);
	border: 1px solid var(--ek-dir-border);
	border-radius: var(--ek-dir-radius-bar);
	box-shadow: var(--ek-dir-shadow);
	transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.bpmb-archive-filters > .bpmb-archive-filters__search.bpmb-archive-filters__search:focus-within {
	border-color: var(--ek-dir-teal);
	box-shadow: 0 0 0 3px var(--ek-dir-teal-wash), var(--ek-dir-shadow);
}

.bpmb-archive-filters > .bpmb-archive-filters__category.bpmb-archive-filters__category {
	grid-area: cat;
	min-width: 0;
}

.bpmb-archive-filters:has(.bpmb-archive-filters__search) > .bpmb-archive-filters__actions.bpmb-archive-filters__actions {
	grid-area: search;
	justify-self: end;
	position: relative;
	z-index: 1;
	margin-inline-end: 9px; /* the pill's 8px padding plus its 1px border */
}

.bpmb-archive-filters:not(:has(.bpmb-archive-filters__search)) > .bpmb-archive-filters__actions.bpmb-archive-filters__actions {
	grid-area: actions;
	justify-self: start;
}

/* 104px of end padding is the Filter button's width plus the 8px it sits in
 * from the pill's edge, so typed text never runs underneath it; Clear, shown
 * only while a search or category is applied, widens the group. */
.bpmb-recent-posts-wrap .bpmb-archive-filters .bpmb-archive-filters__search input[type="search"] {
	width: 100%;
	height: 46px;
	padding: 0 104px 0 40px;
	border: 0;
	border-radius: 0;
	box-shadow: none;
	background: transparent var(--ek-dir-search-icon) no-repeat 12px 50%;
	font-size: 17px;
	color: var(--ek-dir-strong);
}

.bpmb-recent-posts-wrap .bpmb-archive-filters:has(.bpmb-archive-filters__reset) .bpmb-archive-filters__search input[type="search"] {
	padding-inline-end: 176px;
}

.bpmb-recent-posts-wrap .bpmb-archive-filters .bpmb-archive-filters__search input[type="search"]:focus {
	outline: none;
	border: 0;
	box-shadow: none;
}

.bpmb-recent-posts-wrap .bpmb-archive-filters .bpmb-archive-filters__submit.bpmb-archive-filters__submit {
	min-height: 46px;
	height: 46px;
	padding: 0 18px;
	border: 1px solid var(--ek-dir-teal);
	border-radius: var(--ek-dir-radius-ctrl);
	background: var(--ek-dir-teal);
	color: #FFFFFF;
	font-family: var(--ek-dir-display);
	font-size: 13px;
	font-weight: 500;
	line-height: 1;
}

.bpmb-recent-posts-wrap .bpmb-archive-filters .bpmb-archive-filters__submit.bpmb-archive-filters__submit:hover,
.bpmb-recent-posts-wrap .bpmb-archive-filters .bpmb-archive-filters__submit.bpmb-archive-filters__submit:focus {
	background: var(--ek-dir-teal-hover);
	border-color: var(--ek-dir-teal-hover);
	color: #FFFFFF;
}

.bpmb-recent-posts-wrap .bpmb-archive-filters .bpmb-archive-filters__submit.bpmb-archive-filters__submit:focus-visible {
	outline: 2px solid var(--ek-dir-teal-ink);
	outline-offset: 2px;
}

.bpmb-recent-posts-wrap .bpmb-archive-filters .bpmb-archive-filters__reset.bpmb-archive-filters__reset {
	padding: 0 8px;
	color: var(--ek-dir-hint);
	font-family: var(--ek-dir-display);
	font-size: 13px;
}

.bpmb-recent-posts-wrap .bpmb-archive-filters .bpmb-archive-filters__reset.bpmb-archive-filters__reset:hover,
.bpmb-recent-posts-wrap .bpmb-archive-filters .bpmb-archive-filters__reset.bpmb-archive-filters__reset:focus {
	color: var(--ek-dir-danger);
}

/* ── Dropdown: Listora's shape ─────────────────────────────────────────────
 * 44px, 10px corners, the bar's border, 13px — the Groups Sort control, as on
 * Jobs and Courses. `background-color`, so a native caret survives. */
.bpmb-recent-posts-wrap .bpmb-archive-filters .bpmb-archive-filters__category select {
	width: auto;
	min-width: 200px;
	height: 44px;
	padding-block: 0;
	padding-inline: 14px 36px;
	border: 1px solid var(--ek-dir-border);
	border-radius: 10px;
	background-color: var(--ek-dir-surface);
	color: var(--ek-dir-ink);
	font-family: var(--ek-dir-display);
	font-size: 13px;
	font-weight: 400;
	line-height: 42px;
}

.bpmb-recent-posts-wrap .bpmb-archive-filters .bpmb-archive-filters__category select:focus {
	outline: none;
	border-color: var(--ek-dir-border);
}

.bpmb-recent-posts-wrap .bpmb-archive-filters .bpmb-archive-filters__category select:focus-visible {
	outline: 2px solid var(--ek-dir-teal);
	outline-offset: 2px;
}

/* ── Cards: 12px corners, the house surface, our faces ────────────────────── */
.bpmb-recent-posts-wrap .bpmb-post-item.bpmb-post-item {
	border-color: var(--ek-dir-border);
	border-radius: 12px;
	background: var(--ek-dir-surface);
}

.bpmb-recent-posts-wrap .bpmb-post-title,
.bpmb-recent-posts-wrap .bpmb-post-title a {
	font-family: var(--ek-dir-display);
}

/* Phones: the select takes the width under the pill. */
@media (max-width: 640px) {
	.bpmb-recent-posts-wrap .bpmb-archive-filters.bpmb-archive-filters {
		grid-template-columns: minmax(0, 1fr);
		grid-template-areas:
			"search"
			"cat";
	}

	.bpmb-recent-posts-wrap .bpmb-archive-filters .bpmb-archive-filters__category select {
		width: 100%;
		min-width: 0;
	}
}

/* BuddyNext's own Invite button in the group header is hidden; the QR invite
   (companion Invite/InviteSheet.php) takes its place (Kevin, 16 Sep 2026: the
   header button only — the Settings-page form stays). Here rather than in
   invite-sheet.css because that sheet loads only for viewers who may invite,
   while BuddyNext shows its button to every owner and moderator. The only
   stable hook is the Interactivity action (templates/parts/space-hero.php:255). */
.bn-sh-hero__actions [data-wp-on--click="actions.openInviteModal"] {
	display: none !important;
}

/* BuddyNext's own "Invite member" card on a group's Settings > Members panel is
   hidden: its route (buddynext/v1/spaces/{id}/invite) is closed by the companion
   (Invite/NativeInviteClosed.php; Kevin, 17 Sep 2026). Every invitation goes
   through the QR invite sheet. */
.bn-space-settings__panel:has([data-bn-invite-form]) {
	display: none !important;
}

/* The privacy badge in a group's heading, off (Build Brief §3: nothing
   member-facing shows a badge).

   BuddyNext welds it into the <h1> — "Tuesday Men's Group [Secret]"
   (templates/parts/space-hero.php:171). It names a mechanism, in the vendor's
   vocabulary, in the largest type on the page, to the one person who already
   knows: a leader is told his own group is Secret the moment it opens.

   Hidden here rather than filtered away in the companion, and that is the
   deliberate half of this. `buddynext_part_space_hero_args` CAN blank
   `privacy_label`, but the span is printed unconditionally and the heading's
   aria-label is built one line earlier as sprintf( '%s (%s)', name, label ) —
   so blanking it yields an empty pill and an accessible name reading "Tuesday
   Men's Group ()". Hiding the pill is the lesser of the two.

   KNOWN RESIDUE: the aria-label still says "(Secret)" to a screen reader. CSS
   cannot reach it and the vendor offers no seam, so it stands as a logged gap
   (docs/register.md) with a seam owed upstream — don't render the span on an
   empty label, and leave an empty label out of the aria-label. The counts that
   sat beside it are gone properly, through a real filter, in the companion
   (Chrome/GroupHeader.php).

   Doubled class for the load-order reason this file records above: this sheet
   depends on `eklektiv-child` and on no vendor sheet. */
.bn-sh-hero__name .bn-badge.bn-badge {
	display: none !important;
}

/*
 * Better Messages' push-notification toast, off the three screens we own end
 * to end (/start, /pending/*, /vouch/*).
 *
 * It offers to enable notifications "to receive private messages when you are
 * offline" — on the sign-up form, to someone who has no account yet; and on the
 * holding screen, to a pending leader who cannot reach messages at all because
 * PendingLeader\Isolation refuses him at three doors.
 *
 * **Moved here from pending.css on 17 Sep 2026, because it never worked on two
 * of the three.** The rules named all three body classes but lived in a
 * stylesheet the companion enqueues on the holding screen ONLY, so /start and
 * /vouch went on showing the toast — written correctly, loaded nowhere useful.
 * Seen on /start while walking WP6. This sheet loads for every visitor, which
 * is what a three-page rule needs.
 *
 * The whole Toastify container goes, not just the inner proposal: hiding only
 * the inner one left an empty white box with a close button, which says nothing
 * at all. These three pages have no toast of our own to lose.
 *
 * Hidden rather than suppressed at source — the toast is the vendor's and D18
 * says skin, do not rebuild.
 */
body.ek-pending-page .bm-toast-push-proposal-container,
body.ek-start-page .bm-toast-push-proposal-container,
body.ek-vouch-page .bm-toast-push-proposal-container,
body.ek-pending-page .Toastify__toast-container,
body.ek-start-page .Toastify__toast-container,
body.ek-vouch-page .Toastify__toast-container {
	display: none !important;
}

/* "Not open yet" on a pending group's own page (companion Chrome/GroupHeader.php).

   Its own --ek-gp-* block: this rides on a vendor surface that no eKlektiv token
   set governs, so it cannot borrow one (playbook §3.1). Ink and fill separate,
   and the fill is NOT lifted in dark — it sits behind white type. */
.ek-gp {
	--ek-gp-wash: #FFF6E5;
	--ek-gp-line: #F0D9A8;
	--ek-gp-ink:  #4A3A17;
	--ek-gp-link: #8A6A1F;

	background: var(--ek-gp-wash);
	border: 1px solid var(--ek-gp-line);
	border-radius: 12px;
	padding: 12px 14px;
	margin: 12px 0 0;
	color: var(--ek-gp-ink);
}

:is([data-bn-theme="dark"], [data-theme="dark"], [data-bx-mode="dark"]) .ek-gp {
	--ek-gp-wash: #2A2214;
	--ek-gp-line: #4E4024;
	--ek-gp-ink:  #EADFC6;
	--ek-gp-link: #E3C071;
}

.ek-gp__title {
	font-family: var(--ek-font);
	font-weight: 600;
	font-size: 15px;
	margin: 0;
}

.ek-gp__body {
	font-size: 14px;
	line-height: 1.5;
	margin: 4px 0 0;
}

.ek-gp__link {
	display: inline-flex;
	align-items: center;
	min-height: 44px;
	font-family: var(--ek-font);
	font-weight: 600;
	font-size: 14px;
	color: var(--ek-gp-link);
}
