/* ============================================================================
   Features — page components (feat-)

   Page-specific layout for the Features showcase. Builds on css/wm-dark.css
   (tokens, bands, wm- primitives), loaded first by wm_header() via
   wm_theme('dark'). A feat- component that turns out useful elsewhere should
   be promoted to css/wm-dark.css and renamed wm-.

   Covers: the top highlight card grid, the alternating image/text feature
   rows, media framing (video + figure shots), the inline customer pull
   quotes, the mid-page CTA, and the editions strip.

   Loaded with a cache-busting query (controllers/features.php passes
   css/features-dark.css?v=N) — bump N when editing this file.
   ============================================================================ */

/* ---- Title band ----
   Full-bleed still with the page title over it. The band's
   height is DEFINITE (clamp, not aspect-driven), which is what keeps the image
   from shifting anything when it loads — it is object-fit:cover inside a box
   the browser already knows the size of.

   A soft vignette anchored to the LEFT EDGE, not a plain left-to-right ramp and
   not an ellipse floating over the middle of the frame.

   The plain ramp darkens the whole left column top to bottom, including the
   bands above and below the copy where nothing needs protecting — measured, it
   could only ever recover ~1.5% before the spec line failed contrast. A centred
   ellipse recovered far more but read as a visible oval. Anchoring the radial at
   0% 50% keeps the left-to-right feel while still falling off vertically, so the
   top and bottom corners lighten.

   Contrast is measured, not eyeballed (scratch scrim.py — and note that harness
   must read the RENDERED text colour; hardcoding it silently scored everything
   against the wrong value).

   This is as light as it goes. The only thing left to protect is the h1, which
   is LARGE text and so needs 3.0:1 rather than 4.5:1 — worst single pixel behind
   it currently measures 3.8:1. Going one step lighter drops it to 3.5, and the
   step after that fails outright at 2.8.

   It was much darker while a spec line sat under the headline: that line was
   small, dim and ran furthest right into the sunlit third of the frame, and it
   set the floor for every earlier version. If any body-size text is ever put
   back over this image, the scrim has to come back up with it — re-measure,
   don't guess. */
.feat-hero {
  position: relative;
  isolation: isolate;
  display: flex;
  align-items: center;
  /* Track the image's own aspect (2880x727) rather than a fixed height, so the
     crop Stephen composed is the crop that shows — cover then discards nothing
     at normal widths. Bounded: min so the title block always fits, max so an
     ultrawide monitor doesn't turn the band into a letterbox. aspect-ratio is
     resolvable from the width alone, so this stays CLS-safe. */
  aspect-ratio: 2880 / 727;
  min-height: 300px;
  max-height: 440px;
  overflow: hidden;
  background: var(--wm-earth-900);
}
/* Two rows: the title block takes the space, the nav strip sits on the floor.
   The title block is centred via align-self on the GRID row — making it a flex
   container instead turned the h1 and the spec line into flex items and sat
   them side by side. */
.feat-hero { display: grid; grid-template-rows: 1fr auto; align-items: stretch; }
/* No vertical padding: .wm-wrap carries 88px top AND bottom at desktop, which
   inside an aspect-ratio'd band pushed the nav row past the band's bottom edge
   where overflow:hidden silently clipped it. The band's height comes from the
   image aspect; the title block just centres inside what's left. */
.feat-hero__inner { align-self: center; padding-top: 0; padding-bottom: 0; }

/* Nav row at the foot of the band. Its own wash on top of the scrim — 13px
   uppercase labels over a photograph need more than the band gradient gives.

   It starts at 0.3 rather than 0, so the row reads as a panel of tinted glass
   laid over the image rather than as the image fading out beneath it: the top
   edge is a definite start to the row, and the terrain stays visible through
   the whole height of it. No rule above it — the density step does that work,
   and a hairline drawn across a photograph reads as a seam. */
.feat-hero__nav {
  background: linear-gradient(180deg, rgba(10,12,16,0.3) 0%, rgba(10,12,16,0.5) 42%, rgba(10,12,16,0.9) 100%);
}
.feat-hero__nav .wm-wrap { padding-top: 16px; padding-bottom: 16px; }
.feat-hero__img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Pinned to the TOP, not centred. On wide screens cover crops ~200px off the
     height; the sky holds the sun, the haze and the far range, while the
     foreground is plain sand — so keep the top and let the bottom go. Horizontal
     is irrelevant at most widths (the width fills exactly) but matters below
     ~1250px, where the band gets taller than the frame. */
  object-position: 50% 0%;
  z-index: -2;
}
.feat-hero__scrim {
  position: absolute;
  inset: 0;
  z-index: -1;
  background:
    radial-gradient(ellipse 84% 112% at 0% 50%,
      rgba(10,12,16,0.66) 0%, rgba(10,12,16,0.38) 42%,
      rgba(10,12,16,0.06) 74%, rgba(10,12,16,0) 100%);
}
.feat-hero__inner { width: 100%; }
.feat-hero__title {
  font-family: var(--wm-font-display);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.01em;
  line-height: 1.02;
  font-size: clamp(32px, 4.2vw, 52px);
  color: var(--wm-earth-50);
  margin: 0;
  /* 18ch, not 15. At 15 it broke as "FROM RAW NOISE / TO A WORLD YOU / CAN
     SHIP" — three lines with "YOU" left dangling at a line end. 18ch gives two
     balanced lines, and text-wrap:balance keeps them even at other widths. */
  max-width: 18ch;
  text-wrap: balance;
  text-shadow: 0 2px 18px rgba(0,0,0,0.55);
}
/* Spec line, where a lede used to be. Mono and quiet: it is metadata about the
   page's scope, not a pitch — and it carries facts the home hero doesn't, which
   is what keeps the two openings distinct. */
.feat-hero__spec {
  margin: 18px 0 0;
  font-family: var(--wm-font-mono);
  font-size: 13px;
  letter-spacing: 0.04em;
  line-height: 1.7;
  /* earth-100, not 200: brighter type carries its own contrast, which is what
     paid for the lighter scrim above. See the note on .feat-hero__scrim. */
  color: var(--wm-earth-100);
  text-shadow: 0 1px 10px rgba(0,0,0,0.8);
  max-width: 70ch;
}
.feat-hero__spec span { color: var(--wm-sand-gold); margin: 0 8px; }

@media (max-width: 860px) {
  /* Narrow: the left-weighted scrim can't protect text across a portrait frame,
     so darken evenly and let the image sit behind the whole block. */
  /* Drop the aspect ratio, not just the min-height: 3.96:1 at 390px wide is a
     98px band, which clipped the title, the spec line and the whole nav row
     behind overflow:hidden. Below this breakpoint the band is content-sized and
     the image simply sits behind it. */
  .feat-hero { aspect-ratio: auto; min-height: 0; max-height: none; padding: 30px 0 0; }
  .feat-hero__inner { padding-bottom: 26px; }
  .feat-hero__nav .wm-wrap { padding-top: 14px; padding-bottom: 14px; }
  .feat-hero__scrim {
    background: linear-gradient(180deg, rgba(10,12,16,0.72) 0%, rgba(10,12,16,0.86) 100%);
  }
  .feat-hero__title { max-width: none; }
}

/* ---- Section strip ----
   One row of short jump labels, directly under the page header. Replaced a
   six-card grid; deliberately reads as furniture, not content — no tiles, no
   icons, no radius. The bottom hairline ties it to the header block above
   rather than letting it float as its own band. */
.feat-strip {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0 4px;
}
.wm-page a.feat-strip__item {
  position: relative;
  padding: 4px 14px 4px 0;
  margin-right: 10px;
  font-family: var(--wm-font-display);
  font-weight: 600;
  font-size: 13px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--wm-earth-200);
  white-space: nowrap;
  transition: color 120ms;
}
.wm-page a.feat-strip__item:hover { color: var(--wm-sand-gold); text-decoration: none; }
/* Hairline separator between items — drawn on the element rather than as a gap
   so it disappears cleanly at the end of a wrapped row. */
.feat-strip__item + .feat-strip__item::before {
  content: "";
  position: absolute;
  left: -10px;
  top: 50%;
  transform: translateY(-50%);
  width: 1px;
  height: 12px;
  background: var(--wm-earth-600);
}
@media (max-width: 560px) {
  .feat-strip__item { font-size: 12px; padding-right: 10px; margin-right: 8px; }
  .feat-strip__item + .feat-strip__item::before { left: -8px; }
}

/* The band leads straight into the first section, so that section doesn't need
   a full 88px of air above it — the same job .wm-pagehead + .wm-band used to do
   for the old text header. */
.feat-hero + .wm-band > .wm-wrap { padding-top: 44px; }

/* ---- Alternating two-column feature rows ---- */
.feat-row {
  display: grid;
  grid-template-columns: 1fr 1.15fr;   /* copy : media — media a touch wider */
  gap: 48px;
  align-items: center;
  margin-top: 40px;
}
.feat-row:first-of-type { margin-top: 0; }
/* Flip sides: media on the left, copy on the right. Using order keeps the
   copy first in source (good for reading order / screen readers). */
.feat-row--reverse .feat-copy  { order: 2; }
.feat-row--reverse .feat-media { order: 1; }

.feat-copy h3.wm-h3 { font-size: 22px; margin: 24px 0 10px; }
.feat-copy h3.wm-h3:first-child { margin-top: 0; }
.feat-copy p { color: var(--wm-earth-200); font-size: 16px; }
.feat-copy b, .feat-copy strong { color: var(--wm-earth-50); }
.feat-copy .wm-list { margin: 4px 0 14px; }
.feat-copy a { color: var(--wm-sand-gold); }

/* Affordance line for an interactive figure (the image stacks) — quieter than
   body copy, since it's an instruction rather than a claim. */
.feat-hint {
  font-family: var(--wm-font-mono);
  font-size: 12px;
  line-height: 1.5;
  letter-spacing: 0.02em;
  color: var(--wm-earth-400);
  margin-top: 18px;
}

/* ---- Media framing ---- */
.feat-media { min-width: 0; }   /* allow the column to shrink for scroll strips */

.feat-video {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 12px;
  border: 1px solid var(--wm-earth-700);
  background: var(--wm-earth-900);
}

.feat-shot {
  margin: 0;
  /* 12px, matching .wm-tile and the home page's media surfaces. Features sat at
     6px while home used 12-16px — two radius languages in one design system. */
  border-radius: 12px;
  overflow: hidden;
  border: 1px solid var(--wm-earth-700);
  background: var(--wm-earth-900);
}
.feat-shot img { display: block; width: 100%; height: auto; }

/* Small-source variant. .feat-media fills its grid column (~700px at desktop),
   and .feat-shot img is width:100%, so a modest capture gets upscaled into mush
   — the history panel is only 348px wide.

   The cap is the capture's LOGICAL width, not its pixel width. UI screenshots
   are taken on a high-DPI display, so graph_history.jpg is 348 physical px for
   a panel that is ~232 logical px in the app. Browsers ignore a file's embedded
   DPI entirely and treat 1 image pixel as 1 CSS pixel, so showing it at 348
   renders the panel ~1.5x larger than the body text sitting beside it — it
   reads as magnified even though nothing is being scaled up.
   240px puts its UI text back in step with the page.

   (The declarative alternative is srcset="… 1.5x", which makes the browser do
   this division itself. Worth adopting if more HiDPI captures land.)

   Don't be tempted by width:fit-content on the figure plus width:auto on the
   img: the frame then sizes to the image while the image maxes to the frame,
   and that circularity stops the browser reserving the box before the lazy
   image loads. Measured: 247px of layout shift on this row alone. A definite
   width keeps the aspect-ratio reservation working. */
.feat-media--sm { display: flex; justify-content: center; }
.feat-shot--sm { width: 100%; max-width: 240px; }
.feat-shot a { border-bottom: none; display: block; }
.feat-shot figcaption {
  padding: 8px 12px;
  font-family: var(--wm-font-mono);
  font-size: 12px;
  letter-spacing: 0.02em;
  color: var(--wm-earth-400);
  background: rgba(255, 255, 255, 0.03);
  border-top: 1px solid var(--wm-earth-700);
}

/* Multi-image galleries now use the shared .wm-carousel (js/wm-carousel.js);
   .feat-shot above remains for the single framed images. */

/* ---- Inter-block note (legacy <hr/> + intro line before the export options) ---- */
.feat-note {
  margin: 40px 0 0;
  padding-top: 28px;
  border-top: 1px solid var(--wm-divider);
  color: var(--wm-earth-200);
  font-size: 16px;
}

/* ---- Inline customer pull quote ----
   Sits at the end of a feature section, beside the material it speaks to
   (rather than in a collected testimonial band as on the home page). Offset
   to one side and rule-led so it reads as an aside, not as body copy.
   If a third page needs this treatment, promote it to wm-quote in
   css/wm-dark.css and share it with .home-quote. */
.feat-quote {
  margin: 48px 0 0;
  padding: 0 0 0 24px;
  border-left: 2px solid var(--wm-terra-red-soft);
  max-width: 66ch;
}
.feat-quote__mark { width: 22px; height: 22px; color: var(--wm-terra-red-soft); }
.feat-quote__text {
  font-family: var(--wm-font-display);
  font-weight: 500;
  font-size: 20px;
  line-height: 1.45;
  letter-spacing: 0.01em;
  color: var(--wm-earth-50);
  margin: 12px 0 16px;
}
.feat-quote__text b { color: var(--wm-sand-gold); font-weight: 500; }
.feat-quote__name { display: block; font-size: 14px; font-weight: 600; color: var(--wm-earth-50); }
.feat-quote__role {
  display: block;
  font-family: var(--wm-font-mono);
  font-size: 12px;
  color: var(--wm-earth-300);
  margin-top: 3px;
}

/* ---- Mid-page CTA ----
   A low-profile conversion point after the erosion + water sections, where
   interest peaks. Deliberately quieter than the closing .wm-cta: no artwork,
   one primary button. */
.feat-midcta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  padding: 26px 30px;
}
.feat-midcta__h {
  font-family: var(--wm-font-display);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  font-size: 20px;
  color: var(--wm-earth-50);
  margin: 0 0 6px;
}
.feat-midcta__body p { margin: 0; color: var(--wm-earth-200); font-size: 15px; max-width: 62ch; }
.feat-midcta__actions { display: flex; flex-wrap: wrap; gap: 14px; }

/* ---- Editions strip ----
   Facts mirror the comparison table in views/purchase_dark.php — update both
   together. */
.feat-editions { padding: 30px; }
.feat-editions__h {
  font-family: var(--wm-font-display);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  font-size: 20px;
  color: var(--wm-earth-50);
  margin: 0 0 8px;
}
.feat-editions__head p { color: var(--wm-earth-200); font-size: 15px; margin: 0; max-width: 68ch; }
.feat-editions__list {
  list-style: none;
  margin: 22px 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 16px 32px;
}
.feat-editions__list li {
  color: var(--wm-earth-200);
  font-size: 14px;
  line-height: 1.55;
  padding-left: 14px;
  border-left: 1px solid var(--wm-earth-700);
}
.feat-editions__list strong { color: var(--wm-sand-gold); font-weight: 600; }

/* ---- Closing CTA (layout is the shared .wm-cta; these are feat-specific bits) ---- */
.feat-cta__body p { color: var(--wm-earth-200); }
.feat-cta__body .wm-lede { margin: 14px 0 6px; }
.feat-free { color: var(--wm-sand-gold); font-style: normal; font-weight: 700; }
.feat-cta__meta {
  font-family: var(--wm-font-mono);
  font-size: 12px;
  letter-spacing: 0.04em;
  color: var(--wm-earth-400);
  margin: 18px 0 0;
}

/* ---- Responsive ---- */
@media (max-width: 860px) {
  .feat-row {
    grid-template-columns: 1fr;
    gap: 28px;
  }
  /* Stack with copy first regardless of the desktop flip. */
  .feat-row--reverse .feat-copy  { order: 1; }
  .feat-row--reverse .feat-media { order: 2; }

  .feat-midcta { flex-direction: column; align-items: flex-start; }
  .feat-editions { padding: 24px; }
}
