/*
Theme Name:  eKlektiv (Reign child)
Theme URI:   https://eklektiv.org
Description: eKlektiv chrome and Aurora skin over Reign, BuddyNext and Better Messages. Build Brief §5 (9 Sep 2026).
Author:      eKlektiv
Template:    reign-theme
Version:     0.1.0
Requires PHP: 8.4
Text Domain: eklektiv-child
*/

/* ---------------------------------------------------------------------------
   Aurora tokens — Theme and Brand §3 (values as quoted in the Build Brief §5).
   Everything member-facing in this theme reads these; nothing hard-codes a hex.
   --------------------------------------------------------------------------- */
:root {
	--ek-ground:        #EAF2FB; /* page ground */
	--ek-button:        #0B8478; /* primary button fill, white text */
	--ek-teal-text:     #0A7A6F; /* teal text, links, @mentions */
	--ek-ink:           #1B1F24; /* body text */
	--ek-periwinkle:    #6C8CFF; /* avatar ring ONLY */
	--ek-peach:         #F0A15F; /* gatherings ONLY */
	--ek-midnight:      #151B23; /* live-Room strip */
	--ek-navy:          #002D79; /* the e. mark and wordmark (sampled from the site icon, 10 Sep 2026) */
	--ek-white:         #FFFFFF;
	--ek-teal-wash:     rgba(11, 132, 120, 0.14); /* own-message bubble */
	--ek-font:          "Outfit", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
	--ek-radius:        14px;
	--ek-radius-pill:   999px;
}

/* Header avatar ring and badges — Build Brief 5.11 */
.ek-avatar-ring,
.site-header .user-link img,
.bn-header .bn-avatar img {
	box-shadow: 0 0 0 2px var(--ek-periwinkle);
	border-radius: 50%;
}

.ek-badge,
.bm-unread-badge,
.bn-mobile-nav .bn-badge,
.site-header .bn-notifications-badge {
	background: var(--ek-button);
	color: var(--ek-white);
	font-family: var(--ek-font);
	font-weight: 600;
	border-radius: var(--ek-radius-pill);
	min-width: 18px;
	height: 18px;
	line-height: 18px;
	font-size: 11px;
	text-align: center;
	padding: 0 5px;
}

/* Phone header carries no inbox icon — Build Brief 5.2 (desktop keeps it).
   The icon is BuddyNext's .bn-header-msg markup, rendered by the child-theme
   override buddynext/blocks/header-user-menu.php. */
@media (max-width: 767px) {
	.bn-header-msg.ek-header-inbox { display: none !important; }
}

/* Better Messages skin is in assets/css/better-messages-aurora.css */

/* ── Install-the-app card (child theme; JS in assets/js/pwa-install.js) ──
   Solid white card on the Aurora ground, above the bottom bar on phones,
   bottom-right on desktop. Never glass. */
.ek-install {
	position: fixed;
	z-index: 10000;
	left: 12px;
	right: 12px;
	bottom: calc(12px + env(safe-area-inset-bottom, 0px) + 64px); /* clear the 5-slot bottom bar */
	display: grid;
	grid-template-columns: 48px 1fr;
	grid-template-areas: "icon text" "actions actions";
	gap: 10px 14px;
	padding: 14px 16px;
	background: var(--ek-white);
	color: var(--ek-ink);
	border-radius: var(--ek-radius);
	box-shadow: 0 8px 28px rgba(27, 31, 36, 0.18);
	font-family: var(--ek-font);
	opacity: 0;
	transform: translateY(12px);
	transition: opacity .25s ease, transform .25s ease;
}
.ek-install.is-visible { opacity: 1; transform: none; }
.ek-install__icon { grid-area: icon; width: 48px; height: 48px; border-radius: 12px; }
.ek-install__text { grid-area: text; min-width: 0; }
.ek-install__title { margin: 0 0 2px; font-weight: 600; font-size: 16px; }
.ek-install__body { margin: 0; font-size: 14px; opacity: .85; }
.ek-install__steps { margin: 8px 0 0; padding: 0; list-style: none; font-size: 14px; }
.ek-install__steps li { display: flex; align-items: center; gap: 8px; margin-top: 4px; color: var(--ek-teal-text); }
.ek-install__actions { grid-area: actions; display: flex; gap: 8px; justify-content: flex-end; }
.ek-btn--ghost { background: transparent; color: var(--ek-teal-text); }

@media (min-width: 768px) {
	.ek-install {
		left: auto;
		right: 24px;
		bottom: 24px;
		width: 380px;
	}
}

/* Footer copyright: the brand is "eKlektiv." with a lower-case e; Reign's
   footer capitalises text, which rendered it "EKlektiv." (10 Sep 2026). */
#reign-copyright-text,
#reign-copyright-text .reign-footer-site-title {
	text-transform: none;
}

/* ── Pronouns hidden (Kevin, 11 Sep 2026) ──────────────────────────────────
   The profile header drops them server-side (companion Chrome/Profile.php).
   Edit Profile has no per-field hook (BuddyNext templates/profile/edit.php
   field loop), so the field block is hidden here. Its input still posts the
   stored value, so a save never erases it. The header rule is a belt for any
   other surface that reuses the class. */
.bn-ep-field:has(#bn-field-pronouns),
.bn-pf-pronouns {
	display: none !important;
}

/* ── "Joined <date>" off member cards (interface walk B2, Kevin 11 Sep 2026) ─
   Space → Members prints it in p.bn-md-card__meta (BuddyNext 1.1.7
   templates/spaces/members.php:384; 1.2.0 parts/space-members-body.php:427; no
   filter); that class is used nowhere else. The profile header keeps its
   "Joined" line. */
p.bn-md-card__meta {
	display: none !important;
}

/* "Member since <year>" replaces the Joined line on space member cards
   (Kevin, 11 Sep 2026). Printed by the companion (Chrome/Profile.php) under the
   @handle, with the vendor's meta class for its type and colour. */
.bn-md-card__labels .ek-member-since {
	display: block;
	margin-top: 2px;
}

/* ── "Members only" audience hidden (Kevin, 15 Sep 2026) ────────────────────
   BuddyNext 1.2.0 adds it for site admins and space owners: the audience list
   item in the main feed composer, and a lock toggle in a space's tool row
   (templates/partials/composer.php:527-535, :622-634). eKlektiv is invite-only
   behind login, so a guest never reaches a post and the option only duplicates
   Public. No filter gates either control. Neither exists in 1.1.7. */
.bn-composer__privacy-pop li:has(> .bn-composer__privacy-opt[data-privacy="members"]),
.bn-composer__tool[data-wp-on--click="actions.toggleMembersOnly"] {
	display: none !important;
}

/* ── Profile row, member viewing member (interface walk B5, Kevin 11 Sep 2026)
   The Follow wrapper takes no box of its own so the shared control sits in the
   row like its siblings; the hidden attribute still removes it once connected.
   "✓ Connected" is status, not an action, so it sits under the row. */
.bn-pf-actions .ek-pf-follow {
	display: contents;
}
.bn-pf-actions .ek-pf-follow[hidden],
.bn-pf-actions .ek-disconnect-trigger {
	display: none !important;
}
.ek-pf-connected {
	display: flex;
	align-items: center;
	gap: 6px;
	margin: 10px 0 0;
	font-family: var(--ek-font);
	font-size: 14px;
	font-weight: 600;
	color: var(--ek-teal-text, #0A7A6F);
}
.ek-pf-connected[hidden] {
	display: none !important;
}
.ek-pf-connected svg {
	width: 16px;
	height: 16px;
}


/* Activity feed tabs, in priority order (Kevin, 12 Sep 2026).
   All · Groups · Contacts · Voices, "top priority to least".

   BuddyNext builds the strip as a plain array with no filter
   (templates/feed/home.php:194-206), so there is nothing to reorder server
   side. The strip is a flex row (.bn-tabs, bn-base.css:3362), so `order` moves
   the tabs with no flash of the vendor's sequence and no dependence on
   JavaScript. messaging.js then moves the elements themselves so keyboard and
   screen-reader order match what is on screen; these values are keyed to
   data-filter, not to position, so the two agree either way.

   The slugs are the vendor's and do not change: for-you = All,
   spaces = Groups, network = Contacts, following = Voices. */
.bn-feed-filter-tabs .bn-feed-filter-tab[data-filter="for-you"]   { order: 1; }
.bn-feed-filter-tabs .bn-feed-filter-tab[data-filter="spaces"]    { order: 2; }
.bn-feed-filter-tabs .bn-feed-filter-tab[data-filter="network"]   { order: 3; }
.bn-feed-filter-tabs .bn-feed-filter-tab[data-filter="following"] { order: 4; }


/* The bell's count, back on the bell (Kevin, 13 Sep 2026).

   Kevin: "we have a stray message count or notification count showing above
   the profile avatar". It is the notification bell's own badge, thrown clear
   of the bell by a collision between the two vendors — neither of which is
   wrong on its own:

     BuddyNext  .bn-block-notification-bell { position: relative }
                bn-header.css:55-58, so the badge it positions
                `absolute; top:1px; inset-inline-end:1px` sits on the icon.

     Reign      .reign-navbar-user > a,
                .reign-navbar-user > div  { position: static !important }
                in BOTH critical.min.css and main.min.css.

   Reign's carries !important, so the bell block is static whatever we say
   about specificity; the badge then finds no positioned ancestor inside the
   cluster and resolves against `nav#site-navigation`, landing at the whole
   navbar's top-right corner — which is where the avatar is. Measured on the
   sandbox: the bell sits at x=797..837 and its badge was drawn at x=865, y=1.

   The fix does not fight the !important. Reign's selector only matches DIRECT
   children of `.reign-navbar-user`, and the badge's own parent — the 40x40
   link — is a GRANDchild, so it is untouched by that rule and can simply be
   made the containing block. That is also where the badge belongs: on the icon
   button rather than on the wrapper around it. No !important, and nothing to
   unpick if Reign ever drops theirs.

   The messages icon rides the same rule: BuddyNext positions its badge
   identically, so if it is ever turned on it would land in the same wrong
   place for the same reason. */
.reign-navbar-user .bn-block-notification-bell > .bn-notification-bell-link,
.reign-navbar-user .bn-block-notification-bell > .bn-header-msg {
	position: relative;
}


/* Notifications, at half the height (Kevin, 13 Sep 2026: "this is ugly").

   Measured before touching anything, at 375px: a row with actions was **164px
   tall** to carry **39px** of sentence. The other 125px was chrome, and most of
   it was the same fact repeated:

     .bn-notif-row__text     39px  "Marcus O'Brien and 1 other posted in a group."
     .bn-notif-row__meta     44px  a chip reading "New post in group", the time,
                                   and the dismiss ×
     .bn-notif-row__actions  40px  "Open" and "Mark as read"
     padding                 24px

   Three of those earn their place. The rest is duplication:

   1. **The chip repeats the sentence.** The row says "posted in a group" and
      the chip says "New post in group" — and the little icon on the avatar
      (`__type`, which keeps its `aria-label`) says it a third time. One of the
      three is enough, and the sentence is the one a person actually reads.
   2. **The actions repeat the row.** The row itself carries
      `data-wp-on--click="actions.markRead"` and `data-notif-link`, so tapping
      anywhere already opens it AND marks it read. "Open" and "Mark as read"
      are a second copy of the row's own behaviour, given a whole 40px band.

   **"Open" is NOT hidden, and that is deliberate.** The row is a `div` with a
   click handler, not a link, so it takes no keyboard focus — which makes that
   anchor the only way to reach the notification without a mouse. Removing it
   would have tidied the screen by breaking it for anybody on a keyboard. It
   stays, shrunk to a quiet inline link beside the time, where it costs nothing.

   Everything here is CSS over the vendor's own markup (CLAUDE.md rule 3); no
   template is copied and no behaviour is replaced. */

/* One line for time and actions instead of two stacked bands.

   A GRID with both cells named, not a wrapping flex row. Wrapping was tried
   first and did not work: the two boxes measure 42px and 114px inside a 255px
   body, so they had room to share a line and still broke onto separate ones.
   Naming the cells makes the outcome a fact rather than a negotiation, and it
   also means a stray pseudo-element among the vendor's children cannot push
   anything onto a line of its own. */
.bn-notif-row__body {
	display: grid;
	grid-template-columns: auto 1fr;
	align-items: baseline;
	gap: 2px 10px;
	min-width: 0;
}

.bn-notif-row__text {
	grid-column: 1 / -1;
	min-width: 0;
	line-height: 1.4;
}

.bn-notif-row__meta {
	grid-column: 1;
	grid-row: 2;
	gap: 0 8px;
	min-height: 0;
	margin: 0;
}

.bn-notif-row__actions {
	grid-column: 2;
	grid-row: 2;
	justify-self: start;
	min-height: 0;
	margin: 0;
}

/* The chip. Its job is done by the sentence above it and by the type icon on
   the avatar, which keeps its own aria-label, so nothing is lost to a screen
   reader. */
.bn-notif-row__meta > .bn-badge { display: none; }

/* `--ek-dir-muted`, not `--bn-muted` (14 Sep 2026). BuddyNext declares no
   `--bn-muted` — its muted inks are `--bn-ink-2/3/4` — so all four uses in this
   file always fell back to #667085, a light-mode grey, in both themes. On a
   dark notifications page that measured 2.98:1 across every timestamp and
   every Open / Mark as read link: 22 failures on one screen. The same class of
   bug as the undeclared --ek-dir-line tokens found in Upcoming on 13 Sep —
   a var() whose fallback silently became the only value. --ek-dir-muted is
   #667085 in light, so nothing moves there, and #A0A7B2 in dark. */
.bn-notif-row__time {
	font-size: 12px;
	color: var( --ek-dir-muted, #667085 );
}

/* Quiet, inline, and no longer a band of their own. */
.bn-notif-row__actions .bn-btn {
	padding: 0;
	min-height: 0;
	height: auto;
	border: 0;
	background: none;
	font-size: 12px;
	font-weight: 500;
	color: var( --ek-dir-muted, #667085 );
	text-decoration: none;
}

.bn-notif-row__actions .bn-btn:hover,
.bn-notif-row__actions .bn-btn:focus-visible {
	color: var( --ek-teal-text, #0A7A6F );
	text-decoration: underline;
}

/* The × was a 44px control sitting inside the meta line, and it alone set that
   line's height. Lifted out to the row's own corner: the touch target stays 44px
   (it must), it just stops inflating the text column. */
.bn-notif-row {
	position: relative;
	padding: 11px 44px 11px 12px;
	gap: 10px;
}

.bn-notif-row__dismiss {
	position: absolute;
	top: 4px;
	right: 4px;
	width: 40px;
	height: 40px;
	display: inline-flex;
	align-items: center;
	justify-content: center;
}

/* The tab strip overflows its container (700px of tabs in 351px at phone
   width), so "Comments" was clipped mid-word with nothing to say it continued.
   Let it scroll, and take the scrollbar off since the cut-off tab is now the
   affordance. */
.bn-notif-tabs {
	overflow-x: auto;
	flex-wrap: nowrap;
	scrollbar-width: none;
	-webkit-overflow-scrolling: touch;
}

.bn-notif-tabs::-webkit-scrollbar { display: none; }
.bn-notif-tabs > * { flex: 0 0 auto; }


/* Accept / Decline on a connection request (Kevin, 13 Sep 2026).

   The controls are rendered by the companion on the vendor's own
   `buddynext_part_notification_row_after`, which fires OUTSIDE the row's
   closing tag — so they arrive as a sibling, not a child. This tucks them back
   against the row they belong to and matches the unread tint from BuddyNext's
   own `--bn-accent-50`, so the join reads as one object rather than a strip
   bolted underneath.

   The left padding lines the buttons up under the sentence, clear of the
   avatar column, rather than under the avatar. */
.ek-connreq {
	display: flex;
	gap: 8px;
	margin: -11px 0 0;
	padding: 0 12px 12px 50px;
	border-bottom: 1px solid var( --bn-line-faint, #EFF1F4 );
}

.ek-connreq--unread { background: var( --bn-accent-50, rgba( 11, 132, 120, 0.06 ) ); }

.ek-connreq form { margin: 0; }

.ek-connreq__btn {
	padding: 6px 14px;
	border: 1px solid transparent;
	border-radius: 999px;
	font-family: var( --ek-dir-body, Inter, system-ui, sans-serif );
	font-size: 12.5px;
	font-weight: 600;
	line-height: 1.3;
	cursor: pointer;
}

/* `--ek-teal-fill`, not `--ek-teal-text` (14 Sep 2026) — a regression of mine.
   On 13 Sep --ek-teal-text was lifted to #6FDCCB in dark because it is an ink,
   and its uses were checked for fills first. That check matched
   `var(--ek-teal-text)` with no spaces and no fallback, so this rule — written
   `var( --ek-teal-text, #0A7A6F )` — was never seen, and Accept would have
   gone mint with white type in dark. No pending request was on screen to
   show it. --ek-teal-fill is the token that never follows the theme. */
.ek-connreq__btn--yes {
	background: var( --ek-teal-fill, #0A7A6F );
	color: #fff;
}

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

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

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

/* The unread dot, off the dismiss button.

   Moving the × into the row's top-right corner (above) put it exactly where
   BuddyNext already pins `.bn-notif-row__pulse` — measured overlapping, dot
   806..832 inside button 804..844, so the dot was drawn underneath it. The dot
   moves to the leading edge, which is where an unread marker reads best anyway:
   a rail down the left of the list, scannable in one pass, instead of a mark
   competing with a control. */
.bn-notif-row__pulse {
	inset-block-start: 50%;
	inset-inline-end: auto;
	inset-inline-start: 3px;
	transform: translateY( -50% );
}


/* ══════════════════════════════════════════════════════════════════════════
 * Dark mode for the site tokens (Kevin, 13 Sep 2026).
 *
 * The tokens above were authored light-only, and `--ek-ink` is the one that
 * showed: `#1B1F24` body text kept its light value on a dark messenger, which
 * is why the conversation previews measured **1.01:1** — black on near-black.
 *
 * Only the two inks flip, and only because each was checked to BE an ink: nine
 * uses of `--ek-ink` and five of `--ek-teal-text` across this sheet and the
 * messaging skin, every one of them a `color` declaration and not one a fill.
 * That check is here because the same token-doing-two-jobs trap cost two
 * regressions earlier today; a colour that paints a filled control must not
 * follow the theme, or its white label stops being readable.
 *
 * `--ek-button`, `--ek-white`, `--ek-periwinkle`, `--ek-peach` and `--ek-navy`
 * are fills or brand marks and deliberately do not move.
 * ══════════════════════════════════════════════════════════════════════════ */
[data-bn-theme="dark"],
[data-theme="dark"],
[data-bx-mode="dark"] {
	--ek-ink:       #E6E8EB;
	--ek-teal-text: #6FDCCB;
}

/* ══════════════════════════════════════════════════════════════════════════
 * Article cards: tap the cover to play the video (Kevin, 15 Sep 2026).
 *
 * The companion draws the card (Chrome/ArticleCards.php::render_video_card())
 * with BuddyNext's own article-card classes, so the vendor's border, 16:9 cover
 * cap and body type all still apply; this only styles what it adds — the cover
 * as a button with a play mark, and the player that replaces it
 * (assets/js/article-video.js). The play mark is a FILL (`--ek-button` with a
 * white glyph), so it deliberately does not flip in dark mode.
 * ══════════════════════════════════════════════════════════════════════════ */
.ek-article-video__play {
	position: relative;
	width: 100%;
	margin: 0;
	padding: 0;
	border: 0;
	font: inherit;
	color: inherit;
	cursor: pointer;
}

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

.ek-article-video__icon {
	position: absolute;
	top: 50%;
	left: 50%;
	display: grid;
	place-items: center;
	width: 64px;
	height: 64px;
	border-radius: 50%;
	background: var(--ek-button, #0B7A6F);
	color: var(--ek-white, #FFFFFF);
	box-shadow: 0 4px 16px rgb(0 0 0 / 0.35);
	transform: translate(-50%, -50%);
	transition: transform 0.15s ease;
}

.ek-article-video__icon svg {
	margin-left: 3px; /* The triangle's optical centre sits right of its box. */
}

.ek-article-video__play:hover .ek-article-video__icon {
	transform: translate(-50%, -50%) scale(1.08);
}

.ek-article-video__play:focus-visible {
	outline: 3px solid var(--ek-teal-text, #0F766E);
	outline-offset: -3px;
}

.bn-post-card__article.ek-article-video:focus-within {
	border-color: var(--bn-accent);
}

.ek-article-video__body {
	color: inherit;
	text-decoration: none;
}

.ek-article-video__stage {
	position: relative;
}

.ek-article-video__frame {
	display: block;
	width: 100%;
	height: 100%;
	border: 0;
}

@media (prefers-reduced-motion: reduce) {
	.ek-article-video__icon {
		transition: none;
	}
}

/* ══════════════════════════════════════════════════════════════════════════
 * Header search pop-up, in dark (Kevin, 15 Sep 2026: "in dark mode it is hard
 * to read").
 *
 * Reign's pop-up (`.search-wrap .rg-search-form-wrap`, Reign 8.0.7
 * `assets/css/main.css:3189-3274`) paints the field with its generic
 * `input[type="search"]` rule on `--reign-form-*` tokens. In dark that put a
 * #181d24 field on a #1a2028 panel, measured on /activity/:
 *   field vs panel 1.03:1, field edge vs panel 1.19:1 (UI edges need 3:1),
 *   a 4%-black panel shadow that vanishes on the dark page (playbook 3.8),
 *   and Reign's blue (#97c0ee) as the focus edge plus a second white outline
 *   (`input[type="search"]:focus-visible`), the blue trap in playbook 3.7.
 *
 * Here the field takes the blue-grey of BuddyNext's left rail (`.bn-app` /
 * `.bn-rail__item`, #23262F in dark; Kevin, 15 Sep 2026, pinned rather than
 * `var(--bn-bg)`, playbook 3.1) with a visible edge, the placeholder takes the
 * house muted ink, focus is the house teal ring, and the close icon matches the
 * muted ink with the house danger on hover. Measured with the values below:
 * text 12.31, placeholder 6.23, search icon 7.19, field edge 3.42 on the field
 * and 3.70 on the panel, close 6.76, focus teal 9.19. Light mode is untouched.
 *
 * `!important` on the close glyph only: Reign sets that colour with
 * `!important` (`main.css:3236-3243`), which nothing else can beat.
 * ══════════════════════════════════════════════════════════════════════════ */
:is([data-bn-theme="dark"], [data-theme="dark"], [data-bx-mode="dark"]) .search-wrap .rg-search-form-wrap {
	border-color: #3A4452;
	box-shadow: 0 1px 2px rgba(0, 0, 0, .40), 0 2px 6px rgba(0, 0, 0, .32);
}

:is([data-bn-theme="dark"], [data-theme="dark"], [data-bx-mode="dark"]) .search-wrap .rg-search-form-wrap form.search-form input.search-field {
	background-color: #23262F;
	border-color: #6D7989;
	color: var(--ek-ink, #E6E8EB);
}

:is([data-bn-theme="dark"], [data-theme="dark"], [data-bx-mode="dark"]) .search-wrap .rg-search-form-wrap form.search-form input.search-field::placeholder {
	color: #A0A7B2;
	opacity: 1;
}

:is([data-bn-theme="dark"], [data-theme="dark"], [data-bx-mode="dark"]) .search-wrap .rg-search-form-wrap form.search-form input.search-field:focus {
	border-color: var(--ek-teal-text, #6FDCCB);
	box-shadow: 0 0 0 3px rgba(111, 220, 203, .30);
	outline: none;
}

:is([data-bn-theme="dark"], [data-theme="dark"], [data-bx-mode="dark"]) .search-wrap .rg-search-close::before {
	color: #A0A7B2 !important;
}

@media (hover: hover) and (pointer: fine) {
	:is([data-bn-theme="dark"], [data-theme="dark"], [data-bx-mode="dark"]) .search-wrap .rg-search-close:hover::before {
		color: #FF9A8F !important;
	}
}
