/*
Theme Name: Baringo Mpya
Theme URI: https://baringompya.org
Author: Trace & Ledger
Description: Native WordPress block theme for the Baringo Mpya civic listening and public-engagement platform. Built on theme.json design tokens and core Gutenberg blocks — no page-builder dependency, no external font CDN. See Clients/Baringo_Mpya_Yatich/website/README.md in the source repository for build notes.
Requires at least: 6.5
Tested up to: 6.9
Requires PHP: 8.0
Version: 0.1.0
License: GPL v2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html
Text Domain: baringo-mpya
*/

/* Intentionally minimal: this is a block theme — visual design lives in
   theme.json (design tokens) and in block markup, not in this file.
   Only true fallbacks/utility rules that theme.json cannot express live
   here. See functions.php for font loading and theme supports. */

.screen-reader-text {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.skip-link {
  position: absolute;
  top: -3rem;
  left: 1rem;
  z-index: 10000;
  padding: 0.75rem 1.25rem;
  background: var(--wp--preset--color--warm-ink);
  color: var(--wp--preset--color--white);
  border-radius: 0.5rem;
  transition: top 0.15s ease;
}

.skip-link:focus {
  top: 1rem;
}

/* Sticky header (2026-09-01). WordPress auto-wraps the header template
   part in an outer <header class="wp-block-template-part">, form-fitted
   tightly around the real header markup (header.html's own <header
   class="wp-block-group ...">) with no extra height of its own. A CSS
   sticky element only "sticks" for as long as its OWN PARENT still has
   height left to scroll through — sticking the INNER header first
   (tried, then measured and reverted) gave it zero room, since its
   immediate parent is exactly its own height: it unstuck again after
   about one pixel of scroll. Sticking the OUTER wrapper instead works
   correctly, because ITS parent is .wp-site-blocks, which spans the
   full page. Confirmed via a real scroll test on staging, not assumed.

   Kept deliberately simple otherwise: no scroll-triggered JS toggling
   a "scrolled" class (which risks the very "jump when sticky state
   begins" the brief warns against) — instead a single, always-present
   hairline border in the same #E3D6CD used for other hairline dividers
   across the theme, subtle enough to be barely noticeable at the very
   top of the page and to provide real separation once content scrolls
   underneath. The inner header already has an opaque warm-ivory
   background (has-warm-ivory-background-color, in header.html), so
   nothing scrolling beneath the sticky outer wrapper can show through. */
header.wp-block-template-part {
  position: sticky;
  top: 0;
  z-index: 100;
  border-bottom: 1px solid #E3D6CD;
}

/* Header logo. Rendered as a real <img> in patterns/site-navigation.php
   (a PHP pattern, not this static stylesheet) using get_theme_file_uri(),
   so this is just sizing — width set, height left to auto so the
   source file's own aspect ratio (~1:1 — bull mark on top, "BaringoMpya"
   wordmark beneath, both within one combined graphic) is never distorted.
   The supplied asset is a single combined mark with no separate
   icon-only crop, so a small square would crush the wordmark to
   illegibility.

   Enlarged 2026-09-01 from 72px to 216px (3x) so the mark reads as the
   site's principal brand identity rather than a small nav icon, per
   direct client instruction. 216px was checked against the header's
   own available width at 375px (the narrowest realistic viewport,
   where core's Navigation block collapses to a hamburger below 600px
   regardless): logo (216px) + hamburger button (~44px) + the theme's
   global 1.25rem side padding (40px) totals ~300px, comfortably inside
   375px with no overflow — so the "may scale slightly below 216px on
   very narrow screens if absolutely necessary" allowance wasn't needed
   for any real device width; a modest reduction below 340px is kept
   only as a defensive margin, not because 216px was found to overflow.

   Reduced 2026-09-02 from 216px to 150px (~30%), per direct client
   instruction that the header/navigation bar read as far too tall.
   The source artwork is a near-square PNG (4001x4000px, confirmed by
   reading its own IHDR chunk rather than assumed) — at 216px width
   the logo therefore rendered ~216px tall, which combined with the
   header's own top/bottom padding to produce the excessive vertical
   whitespace the client flagged. 150px keeps the same aspect ratio
   (height:auto) and still reads clearly as the header's principal
   mark, just at a compact-navigation-bar scale rather than a masthead
   scale. */
.site-logo-link {
  display: block;
}

.site-logo-image {
  display: block;
  width: 150px;
  height: auto;
}

@media (max-width: 340px) {
  .site-logo-image {
    width: 135px;
  }
}

/* Homepage image-led hero (patterns/hero.php). Real client-supplied
   photograph (see hero.php's own description for provenance/source
   path) — a wide landscape (1920x1080) looking down over the Baringo
   valley from a hillside dirt road: sky fills the top half, cattle
   stand on the road at roughly 30% across the frame, dense bush
   crowds the right edge. The hero's own copy sits near the TOP of the
   canvas (align-items: flex-start, not center) so it lands within a
   normal first viewport; the photograph continues below as the user
   scrolls.

   Height, reduced 2026-09-01 by ~30% from the previous 900/950/1050px
   pass (which itself corrected an earlier, much taller pass that
   over-cropped the image) — the earlier pass, while correctly cropped,
   still read as a near-full-page hero; this keeps the same strong
   photographic opening while bringing the next section into view much
   sooner. The crop math from that pass still holds at these heights
   (still comfortably height-bound at the three tested viewports, see
   the background-position-y comment below), so no focal-point change
   was needed alongside the height reduction.

   background-position-x is tuned per breakpoint (see media queries
   below), biased toward the cattle/dirt-road group (~30% across the
   source frame) and away from the bush on the right edge — chosen by
   opening the actual source file and reading pixel positions directly,
   not assumed. background-position-y is set slightly below center
   (55-60%) rather than a top anchor: at these heights, sufficiently
   wide desktop monitors (roughly >=1870px viewport width) flip the
   cover-fit from height-bound to width-bound, which crops vertically
   instead of horizontally — a top anchor would crop the ground/subject
   away entirely on those screens and leave only sky. A slightly-below-
   center anchor keeps the cattle and valley in frame either way, and
   is visually inert at the three test viewports (375/820/1440) where
   the fit stays height-bound and no vertical cropping happens at all.

   The overlay is deliberately gentle — an editorial photograph with
   restrained text protection, not a dark campaign-poster wash. Two
   custom properties make it easy to retune without touching markup.

   Parallax (2026-09-01): the background photograph now lives in its
   own absolutely-positioned inner layer, .hero-photo-bg, separate from
   the outer .hero-photo section — this is what lets a tiny scroll
   script (baringo_mpya_parallax_script() in functions.php) move just
   the photograph via transform:translateY() while the overlay and text
   content stay put. background-attachment:fixed was deliberately not
   used: it's well-documented to perform poorly and behave
   inconsistently on mobile Safari/Chrome (repaint jank, or simply not
   fixing at all on some mobile browsers), exactly what "no jank" here
   rules out. .hero-photo-bg is inset -80px top/bottom beyond its
   container — more than the script's own capped max offset (60px) —
   so translating it never reveals empty space at either edge. */
.hero-photo {
  --hero-overlay-color: 33, 28, 25; /* warm-ink, as r,g,b for rgba() */
  --hero-overlay-top: 0.42;
  --hero-overlay-bottom: 0.08;
  position: relative;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding-top: clamp(5rem, 16vh, 8rem);
  min-height: 630px;
  overflow: hidden;
}

.hero-photo-bg {
  position: absolute;
  top: -80px;
  bottom: -80px;
  left: 0;
  right: 0;
  background-image: var(--hero-bg-jpg);
  background-size: cover;
  background-position: 25% 55%;
  background-repeat: no-repeat;
  will-change: transform;
  z-index: 0;
}

/* WebP, only where the browser actually supports the image-set()
   syntax needed to offer it as an alternative — everywhere else the
   plain background-image above (universally-supported JPEG) stands,
   so there's no broken/blank state on older browsers. */
@supports (background-image: image-set(url("a.jpg") 1x)) {
  .hero-photo-bg {
    background-image: image-set(
      var(--hero-bg-webp) type("image/webp"),
      var(--hero-bg-jpg) type("image/jpeg")
    );
  }
}

@media (min-width: 600px) {
  .hero-photo {
    min-height: 665px;
  }

  .hero-photo-bg {
    background-position: 30% 55%;
  }
}

@media (min-width: 1200px) {
  .hero-photo {
    min-height: 735px;
  }

  .hero-photo-bg {
    background-position: 35% 60%;
  }
}

.hero-photo::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  background: linear-gradient(
    180deg,
    rgba(var(--hero-overlay-color), var(--hero-overlay-top)) 0%,
    rgba(var(--hero-overlay-color), calc(var(--hero-overlay-top) * 0.55)) 22%,
    rgba(var(--hero-overlay-color), var(--hero-overlay-bottom)) 45%
  );
}

/* Hover overlay (2026-09-01): a restrained additional black wash, only
   for pointer devices that can genuinely hover (hover:hover and
   pointer:fine) — gated so touch devices, which either can't hover at
   all or can only simulate a "stuck" hover after a tap, never show
   this. Sits above the gradient overlay (z-index 2) and below the text
   content (z-index 3). 20% black, roughly the middle of the requested
   15-25% range; the existing gentle readability gradient stays exactly
   as it is underneath. */
.hero-photo::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 2;
  background: rgba(0, 0, 0, 0.2);
  opacity: 0;
  transition: opacity 300ms ease-out;
  pointer-events: none;
}

@media (hover: hover) and (pointer: fine) {
  .hero-photo:hover::after {
    opacity: 1;
  }
}

.hero-photo-content {
  position: relative;
  z-index: 3;
  max-width: 640px;
}

/* WPForms Lite ships its own default submit-button styling (blue,
   square corners) which otherwise overrides the theme's button
   design entirely. Restyled to match the rest of the site's buttons
   (theme.json's elements.button) — same accessible-orange fill, pill
   radius, hover to warm-ink — since WPForms markup isn't a core block
   theme.json can style automatically. */
.wpforms-container .wpforms-submit {
  background-color: var(--wp--preset--color--accessible-orange) !important;
  color: var(--wp--preset--color--white) !important;
  border: none !important;
  border-radius: 999px !important;
  padding: 0.9rem 1.75rem !important;
  font-family: var(--wp--preset--font-family--mukta) !important;
  font-weight: 600 !important;
  font-size: 1rem !important;
}

.wpforms-container .wpforms-submit:hover,
.wpforms-container .wpforms-submit:focus {
  background-color: var(--wp--preset--color--warm-ink) !important;
}

/* "Stardust" — a small, restrained motion/icon/colour layer for the
   interior pages, added on top of the already-approved design system.
   Deliberately minimal: no animation library, no JS framework — a
   ~20-line vanilla IntersectionObserver script (see wp_footer output
   in functions.php) plus these CSS classes. Every rule here is inert
   until JS adds a class, or is itself neutralised under
   prefers-reduced-motion below — the site is fully usable with no
   motion at all. */

/* Icon wrapper: a small tinted circle behind each line icon, using the
   new *-soft palette tokens. Icons are inline SVG (currentColor
   stroke), never an external icon font/CDN. */
.bm-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 3rem;
  height: 3rem;
  border-radius: 999px;
  flex-shrink: 0;
}

.bm-icon svg {
  width: 1.5rem;
  height: 1.5rem;
}

.bm-icon--orange {
  background: var(--wp--preset--color--orange-soft);
  color: var(--wp--preset--color--accessible-orange);
}

.bm-icon--bronze {
  background: var(--wp--preset--color--bronze-soft);
  color: var(--wp--preset--color--accessible-bronze);
}

.bm-icon--green {
  background: var(--wp--preset--color--green-soft);
  color: #2f6b27; /* darkened baringo-green — the raw brand green is too light for an icon stroke at this size */
}

/* Editorial feature panel (replaces the 2026-08-31 "stardust" pass's
   solid soft-tint panel treatment, corrected the same day after client
   feedback that filled colour blocks sitting close together read as
   "coloured windows" — a dashboard-tile look, not editorial). No
   background fill, no border, no card boundary at all: just a thin
   coloured rule above the icon (matching the icon's own tint) as a
   quiet accent mark, open onto the page's own warm-ivory/white
   background either side. The generous grid gap that separates these
   (set on the wrapping grid in functions.php) is what keeps items from
   ever visually touching — not a border or a fill. */
.bm-feature-panel {
  position: relative;
  padding-top: 1.5rem;
}

.bm-feature-panel::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  width: 2.25rem;
  height: 2px;
  border-radius: 1px;
}

.bm-feature-panel--orange::before {
  background: var(--wp--preset--color--accessible-orange);
}

.bm-feature-panel--bronze::before {
  background: var(--wp--preset--color--accessible-bronze);
}

.bm-feature-panel--green::before {
  background: #2f6b27;
}

/* Lift-only hover for the open editorial panels above — deliberately
   no shadow (a shadow would reintroduce the "boxed card" reading this
   pass removed). Distinct from .bm-card-hover below, which is kept for
   genuinely card-shaped elements (the Stories archive's image-backed
   cards) where a card silhouette is correct. */
.bm-lift-hover {
  transition: transform 220ms ease-out;
}

.bm-lift-hover:hover,
.bm-lift-hover:focus-within {
  transform: translateY(-4px);
}

.bm-lift-hover:hover .bm-icon,
.bm-lift-hover:focus-within .bm-icon {
  transform: translateY(-2px);
}

/* Scroll reveal: starts hidden/offset, JS adds .bm-revealed on
   intersection. The reduced-motion block below forces full visibility
   unconditionally, independent of whether JS ever runs. */
.bm-reveal {
  opacity: 0;
  transform: translateY(18px);
  transition: opacity 0.5s ease-out, transform 0.5s ease-out;
}

.bm-reveal.bm-revealed {
  opacity: 1;
  transform: translateY(0);
}

/* Staggered children within a revealed group (theme grids, story
   cards) — small, deliberately subtle per-item delay. */
.bm-reveal-stagger > * {
  transition-delay: calc(var(--bm-stagger-index, 0) * 60ms);
}

/* Card/panel hover lift — used on theme-grid items, story cards, and
   the "listening lens" / "three ideas" feature panels. Kept gentle per
   instruction: a few px of lift, a soft shadow, no scale/rotate/tilt. */
.bm-card-hover {
  transition: transform 220ms ease-out, box-shadow 220ms ease-out, border-color 220ms ease-out;
}

.bm-card-hover:hover,
.bm-card-hover:focus-within {
  transform: translateY(-4px);
  box-shadow: 0 12px 24px -16px rgba(33, 28, 25, 0.35);
}

.bm-card-hover:hover .bm-icon,
.bm-card-hover:focus-within .bm-icon {
  transform: translateY(-2px);
}

.bm-icon {
  transition: transform 220ms ease-out;
}

/* Button micro-interaction — a small lift added on top of the
   existing theme.json colour-swap hover, applied broadly to block
   buttons and the WPForms submit button. */
.wp-block-button__link,
.wpforms-container .wpforms-submit {
  transition: transform 180ms ease-out, background-color 180ms ease-out, box-shadow 180ms ease-out;
}

.wp-block-button__link:hover,
.wp-block-button__link:focus-visible,
.wpforms-container .wpforms-submit:hover,
.wpforms-container .wpforms-submit:focus-visible {
  transform: translateY(-2px);
}

/* Text-link underline reveal — used for inline links in page body
   copy. Nav links intentionally get their own, separate treatment
   below rather than this one (a full underline reads too heavy for a
   compact nav bar). */
.bm-link-underline {
  position: relative;
  text-decoration: none;
  background-image: linear-gradient(currentColor, currentColor);
  background-position: 0 100%;
  background-repeat: no-repeat;
  background-size: 0% 1px;
  transition: background-size 220ms ease-out;
}

.bm-link-underline:hover,
.bm-link-underline:focus-visible {
  background-size: 100% 1px;
}

/* Navigation: a quiet underline reveal + current-page indicator,
   without touching the header's structure or the approved logo/layout.

   Current-page detection (2026-09-01): the .current-menu-item class
   and aria-current="page" below are NOT added automatically by
   WordPress core here — core's own current-page detection for the
   navigation-link block only fires for "post-type" kind links (a
   direct post/page ID reference); every link in site-navigation.php is
   a "custom" kind link built from home_url() paths, precisely so the
   pattern stays staging/production-portable, and custom-kind links get
   no automatic detection at all. baringo_mpya_mark_current_nav_link()
   in functions.php compares each link's own path against the actual
   current request path (never a hardcoded production URL) and injects
   both the class and the ARIA attribute onto the rendered HTML. */
.wp-block-navigation-item > .wp-block-navigation-item__content {
  position: relative;
  color: inherit;
  transition: color 180ms ease-out;
}

.wp-block-navigation-item > .wp-block-navigation-item__content::after {
  content: "";
  position: absolute;
  left: 0;
  right: 100%;
  bottom: -4px;
  height: 2px;
  background: var(--wp--preset--color--accessible-orange);
  transition: right 200ms ease-out;
}

.wp-block-navigation-item:hover > .wp-block-navigation-item__content::after,
.wp-block-navigation-item.current-menu-item > .wp-block-navigation-item__content::after {
  right: 0;
}

/* Current page: a persistent brand-colour text treatment, not just the
   underline — distinct from plain :hover (underline only, no colour
   change) and from :focus-visible (browser's own focus ring, untouched
   here). accessible-orange is the same token already used elsewhere
   for interactive/accent colour, checked for contrast against
   warm-ivory/white in the existing Accessibility section of this
   theme's own README. */
.wp-block-navigation-item.current-menu-item > .wp-block-navigation-item__content {
  color: var(--wp--preset--color--accessible-orange);
  font-weight: 700;
}

/* Stories pagination (2026-09-01, baringo_mpya_stories_pagination() in
   functions.php). Plain <a> elements — naturally keyboard-operable and
   focusable, no custom JS/ARIA widget needed for something this
   simple. The current page reads as a filled accessible-orange pill;
   others are quiet outlined links matching the button-outline language
   already used elsewhere (the hero's secondary button). */
.bm-pagination {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
}

.bm-pagination a,
.bm-pagination span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 2.75rem;
  height: 2.75rem;
  padding: 0 1rem;
  border-radius: 999px;
  border: 1.5px solid #E3D6CD;
  color: var(--wp--preset--color--warm-ink);
  text-decoration: none;
  font-weight: 600;
  transition: border-color 180ms ease-out, color 180ms ease-out, background-color 180ms ease-out;
}

.bm-pagination a:hover,
.bm-pagination a:focus-visible {
  border-color: var(--wp--preset--color--accessible-orange);
  color: var(--wp--preset--color--accessible-orange);
}

.bm-pagination .bm-pagination-current {
  background: var(--wp--preset--color--accessible-orange);
  border-color: var(--wp--preset--color--accessible-orange);
  color: var(--wp--preset--color--white);
}

@media (prefers-reduced-motion: reduce) {
  * {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }

  .bm-reveal {
    opacity: 1 !important;
    transform: none !important;
  }

  .bm-card-hover:hover,
  .bm-card-hover:focus-within,
  .bm-lift-hover:hover,
  .bm-lift-hover:focus-within,
  .wp-block-button__link:hover,
  .wp-block-button__link:focus-visible,
  .wpforms-container .wpforms-submit:hover,
  .wpforms-container .wpforms-submit:focus-visible {
    transform: none !important;
  }

  /* Parallax (see .hero-photo-bg above): baringo_mpya_parallax_script()
     already checks prefers-reduced-motion itself and never attaches a
     scroll listener when it matches, so this transform:none is a
     second, independent guarantee — the photograph stays static even
     if the script somehow ran anyway. */
  .hero-photo-bg {
    transform: none !important;
  }
}
