/* ============================================================
   rawcloser.com — Features page (Phase 7.A.20; corrected 7.A.21 across
   nine passes)
   Page-specific rules ONLY for /features (features/index.html).

   7.A.20 shipped the hero and a foundation feature-row component with no
   content consumer yet. 7.A.21's first pass CORRECTED that foundation (the
   half row was built at the wrong aspect ratio, the full-row variant and
   the 'coming'-status motif treatment were missing entirely) and shipped
   the first real consumer, the "before the call" arc group. A second
   correction pass, same phase, fixed two more issues found once that arc
   group was live: the hero H1 was capped to a prose measure and broke into
   three lines, with a too-large gap to the first section below it (§1);
   and the row component's TWO variants (full/half) are collapsed into ONE
   — every row is now the same alternating layout, with the image column
   given more width than the text column instead of a separate full-width
   component (§2). A THIRD pass cut the call-setup row entirely (no real
   screen in the app). A FOURTH pass landed once Daniel's actual warmup/
   sales-assistant captures existed to check against: the hero-to-first-
   section gap was still too large even after the second pass (the first
   content section's own top padding wasn't cut, only the hero's bottom —
   §1), the real images didn't match the assumed 16:10 ratio so the row
   now adapts to each image's own shape instead of cropping it (§2), and
   the image's outer-side bleed to the viewport edge is reverted so both
   sides of a row match the landing hero's side spacing exactly (§2). A
   FIFTH pass tried bottom-aligning the hero content inside its
   fold-filling box (centering was splitting the leftover viewport space
   evenly above AND below the text, swamping the padding cuts) — that
   only relocated the same leftover space to ABOVE the hero instead. A
   SIXTH pass dropped fold-filling entirely — this hero has no CTA/form to
   justify filling the screen, so its height is now just its own padding +
   content, leaving no leftover space to redistribute in either direction
   (§1). The sixth pass also matched this page's side gutters to the
   landing hero's OWN width cap (92.25rem, wider than the standard site
   .container's 75rem) rather than just its padding token, since Daniel
   found the two didn't actually match in devtools despite sharing
   --container-pad-x (§2/§3). A SEVENTH pass added more breathing room
   above and below the hero once the sixth pass's fix removed the
   confusing fold-filling leftover-space: the top padding swapped a flat
   --space-9 offset for the fluid --space-section-y (§1), and the hero's
   bottom + the arc section's top (§1/§2) each went from a quarter-step to
   a half-step, so together they total one full --space-section-y instead
   of half of one. An EIGHTH pass went further still, on request: TOP
   raised to 1.5x --space-section-y, and the hero-bottom/arc-top pair (§1/
   §2) each raised again to a three-quarter-step, so together they now
   total 1.5x --space-section-y — deliberately MORE than the site's
   ordinary section-to-section rhythm. A NINTH pass reacted to the real
   captures reading too large once seen alongside their copy: INVERTED
   the row's column split (§2) — the image is now the NARROW ~45% column
   and text the WIDE ~55% one, the opposite of the second pass's original
   reasoning (which was sized for whole-app screenshots, before any real
   capture existed to check it against). This file holds:
     §1 the page hero (kicker + H1 + subhead, no visual, no form — the one
        place this page's hero rhythm DIVERGES from /tester and /waitlist,
        which both carry a two-column grid + media/form column)
     §2 the reusable feature-row component — ONE variant, alternating,
        text column wider than image (~55/45), each row's own image ratio,
        no bleed — the shared placeholder-box shell a real <picture> or a
        'coming' motif both use, and the tier/status badge cluster —
        consumed by 7.A.21's two "before" rows and every arc group after
        it.

   HERO RHYTHM — mostly reused, not rebuilt, with two deliberate
   divergences (flagged at their use site in §1 below): the bottom padding
   is a quarter of the shared fluid token instead of the full amount (this
   page's hero is immediately followed by real content, not a CTA the
   visitor pauses on), and the H1 no longer sits in its own narrower
   wrapper, so it can run to the container's width instead of a ~65ch prose
   measure. Everything else — the --space-9 top padding, the --text-6xl H1
   step, the subhead treatment (size, secondary tone, prose measure,
   --space-5 gap), and the on-load `hero-rise` stagger (same keyframe, same
   900ms, same easing, same reduced-motion kill switch) — are the exact
   values landing.css already defines for .hero / .wl-intro / .ts-intro.
   This page does NOT join that shared selector list — unlike the waitlist
   and tester heroes, this hero has no media/form column, so the two-column
   .hero-grid/.wl-grid/.ts-grid system does not apply here and joining it
   would drag in grid rules this page never uses. Instead §1 below restates
   the shared numbers (where it doesn't diverge) as a plain single column.
   The `hero-rise` KEYFRAME ITSELF is not redefined — keyframes are global
   once declared, and landing.css (linked ahead of this file) already
   declares it, so §1 only points at it by name.

   The KICKER reuses the shared .ts-kicker rule directly (landing.css,
   grouped with .privacy-kicker) rather than restating its five
   declarations a third time — landing.css's own comment on that rule
   anticipated a third consumer. TIER BADGES reuse .metal-text /
   .metal-text--pro / .metal-text--max VERBATIM (landing.css, the one
   7.A.7-fix gradient definition) — §2 below defines only the pill SHELL
   around them (.feat-tier / .feat-tier__text), mirroring the landing
   features strip's .feature-tier / .feature-tier__text shell rather than
   reusing those classes directly (this page's rows are a different
   component from that accordion strip, even though the badge inside
   looks identical).

   Consumes tokens.css only — never hardcode a color, spacing, radius,
   type, shadow, or motion value. The raw numbers below are structural
   layout dims (rem caps, the row's motif/visual min-height, the 16:10
   image box) in the same category as the hero's 28rem copy cap and the
   how-it-works motif caps — each commented at its use site.
   ============================================================ */

/* ---------- 1. Hero ---------- */
/* Carries id="hero" in the markup so the shared nav.js keys its per-page
   behaviour off it (full-size + always-visible while in view, compact +
   direction-driven past it) — same convention as every other standalone
   page. NOT fold-filling (see SIXTH PASS below) — this is the one place
   this page's hero rhythm DIVERGES from /tester and /waitlist's
   min-height:100svh box (landing.css .hero, .wl-intro, .ts-intro), on top
   of having no media/form column (see the file banner above).

   BOTTOM PADDING — CORRECTED 7.A.21 (second pass, cut further in the
   fourth): this page's first content section (.feat-arc, .section) opens
   with its own --space-section-y top padding by default (components.css
   .section). Reusing the shared box's full --space-section-y bottom here
   too stacked BOTH into a ~2x gap — the hero read as a title card with
   nothing attached below it. Unlike hero/waitlist/tester (which each end on
   a CTA the visitor pauses to read before scrolling on), this page's very
   next thing is the first real content section, so it can sit close under
   it. Cut to a quarter of the same fluid token (not a new value, not a
   swap to a fixed --space-N step) so the gap still scales with viewport
   the way every other section boundary on the site does.

   FOURTH PASS: cutting only this side wasn't enough — .feat-arc still
   carried its own UNCUT top padding (.section's default), so the visible
   gap was actually a quarter PLUS a full step, more than a normal
   section-to-section gap despite this cut. §2 below gives .feat-arc the
   same quarter-step top override, so the two cuts together are meant to
   close the gap "a lot."

   FIFTH PASS (SUPERSEDED by the sixth, keeping the note as it's the
   correct diagnosis of why the fourth pass alone didn't work): hero/
   waitlist/tester all use justify-content:CENTER inside a min-height:
   100svh box; centering this page's short, three-line hero (no CTA, no
   form, no visual) in a full fold splits the LEFTOVER viewport space
   evenly above AND below the text, dwarfing the padding cuts above.
   Tried justify-content:FLEX-END to push that leftover space above the
   kicker instead — that fixed the gap to section 2, but pushed a large,
   equally wrong gap above the hero instead (still fold-filling, so the
   same leftover space still exists, just relocated).

   SIXTH PASS — the actual fix: this hero doesn't need to fill the fold at
   all. Unlike hero/waitlist/tester, it has no CTA or form to give a
   visitor a reason to pause on a full screen — its only job is to lead
   straight into the row content, so DROPPED min-height entirely. The
   section's height is now exactly its own padding + content, so there is
   no leftover space to redistribute in any direction — the two paddings
   below are the WHOLE gap on both sides, on every viewport height.

   SEVENTH PASS: once there was no leftover fold-space left to confuse the
   read, both paddings turned out tighter than intended. TOP swapped the
   fixed --space-9 (a nav-clearance offset borrowed from the fold-filling
   heroes, not actually meaningful now that this box isn't fold-filling)
   for the fluid --space-section-y — the same top rhythm a plain .section
   opens with anywhere else on the site, so this hero's top space now
   scales with viewport instead of sitting at a flat 96px. BOTTOM went
   from a quarter step to a half step; .feat-arc's own top (§2) matches it
   pass-for-pass, so the two together total one full --space-section-y —
   the site's ordinary single-section rhythm — instead of half of one.

   EIGHTH PASS: still more requested. TOP raised 1x --space-section-y to
   1.5x; BOTTOM raised half-step to three-quarter-step, .feat-arc's top
   (§2) again matching it, so the two together now total 1.5x
   --space-section-y — MORE than the site's ordinary single-section gap,
   a deliberate exception for this page rather than the ordinary rhythm
   the seventh pass landed on. Still a calc() of the one fluid token, not
   a new value. */
.feat-intro{
  display:flex;
  flex-direction:column;
  padding-block-start:calc(var(--space-section-y) * 1.5);
  padding-block-end:calc(var(--space-section-y) * 0.75);
}

/* Kicker → heading gap: the same --space-3 step the landing privacy section
   and the tester hero put between their kicker and title, so this third
   consumer reads identically. The kicker's own type/tone/caps come from the
   shared .ts-kicker rule in landing.css — not restated here.

   WIDTH — CORRECTED 7.A.21: the kicker/H1/subhead used to sit inside a
   `.feat-intro-inner` wrapper capped at max-width:34rem, which constrained
   the H1 to a ~65ch prose measure and forced it to three lines at display
   size. That wrapper is removed — the H1 now runs the same width as the
   container (like the .container it sits in directly), so at desktop sizes
   it breaks into two lines, not three. The SUBHEAD keeps its own narrower
   --measure-prose cap below, so only the heading widened. */
.feat-title{
  margin-top:var(--space-3);
  font-size:var(--text-6xl);
  text-wrap:balance;
}

.feat-subhead{
  font-size:var(--text-lg);
  color:var(--color-text-secondary);
  max-width:var(--measure-prose);
  margin-top:var(--space-5);
}

/* On-load fade-and-rise — the SAME `hero-rise` keyframe the hero/waitlist/
   tester sections use (landing.css §1), pointed at by name rather than
   redeclared. Being the page's first section, this is a one-time on-LOAD
   stagger, not a scroll reveal — none of the three are .reveal/.r-rise
   targets and reveal.js never touches them. Scoped by the .feat-intro
   ancestor rather than a dedicated class on the kicker: the kicker's
   markup carries only .ts-kicker (reused directly, see the file banner) and
   needs no second class purely to hang this animation off. */
.feat-intro .ts-kicker,
.feat-intro .feat-title,
.feat-intro .feat-subhead{
  animation:hero-rise 900ms var(--ease-standard) both;
}
.feat-intro .feat-title{   animation-delay:var(--stagger); }
.feat-intro .feat-subhead{ animation-delay:calc(var(--stagger) * 2); }

/* Mandatory: a reduced-motion visitor sees the hero instantly and
   completely — no fade, no transform, final position. Same belt-and-
   suspenders kill switch the hero/waitlist/tester heroes carry. */
@media (prefers-reduced-motion: reduce){
  .feat-intro .ts-kicker,
  .feat-intro .feat-title,
  .feat-intro .feat-subhead{
    animation:none;
  }
}

/* ---------- 2. Feature row component ---------- */
/* Built on the how-it-works ROW pattern (index.html §3 / landing.css §3
   "How it works") — alternating visual/text columns, NOT the section-4
   features accordion (that strip is hover/tap-expand and collapses five of
   six cards; this component is never collapsed, nothing here is hover-
   gated, everything is open and visible at once, per the brief). Structure
   and rhythm below are the how-it-works row's, restated for this page's own
   class names rather than joined into .hiw-row — this component carries a
   badge cluster and a locked <picture> contract .hiw-row has no equivalent
   of, so folding it into that selector would drag how-it-works-only
   assumptions in here.

   ONE ROW TYPE ONLY — CORRECTED 7.A.21 (second pass). The 7.A.20 foundation
   shipped TWO variants (.feat-row-full, text-above-image-below at 16:10, for
   whole-app dashboard shots; .feat-row, alternating two-column at 4:3, for
   single-panel shots). That second variant is gone. Every feature — including
   the dense whole-app screenshots that motivated the full-row variant
   (warmup, and later selling-dashboard / kpi-dashboard) — now
   renders as the SAME alternating .feat-row: image one side, text the other,
   flipping per row, stacking on mobile. What made the full-width variant feel
   necessary was originally handled here by widening the image column past
   text and letting it bleed to the page edge — BOTH of those are since
   reverted (see the breakpoint block at the bottom of this section for the
   current column split and NO IMAGE BLEED note); the image now takes the
   NARROWER column and stays inside the ordinary container padding like
   everything else.

   FIRST INSTANCES SHIP IN 7.A.21 (features/index.html's "before the call"
   section: warmup, sales-assistant, both as .feat-row, alternating
   sides). 7.A.22–24 add the remaining arc-group <section>s the same way, one
   .feat-row per feature from features-data.js — this file defines the shape
   those rows use so each remaining commit only writes markup + copy, not a
   new pattern. The arc heading itself reuses .hiw-eyebrow directly
   (landing.css §3) rather than a new class — same small-caps
   eyebrow-doubles-as-h2 treatment, including its self-reveal — so no new
   heading rule was needed here.

   IMAGE CONTRACT — reproduce verbatim in every arc group (one <picture>
   per built feature, not two — the known double-download debt the hero and
   waitlist MacBook shots carry with their two-<picture>-per-theme approach
   must not be repeated here):

       <picture style="--img-ratio:<real-width>/<real-height>">
         <source media="(prefers-color-scheme: dark)"
                 srcset="/assets/img/features/<slug>-dark.webp" type="image/webp">
         <img src="/assets/img/features/<slug>-light.webp" alt="…" loading="lazy"
              decoding="async" width="<real-width>" height="<real-height>"
              onerror="this.style.display='none'">
       </picture>

   RATIO — REVISED AGAIN, 7.A.22 (see the RATIO comment on `.feat-visual
   picture` below for the full reasoning): per-image again, via inline
   --img-ratio, each row set to that file's OWN real captured dimensions.
   Two earlier attempts within this arc group were tried and rejected:
   hardcoding every row to a hoped-for 2000x1250 capture target that no
   file actually hit, then a single fixed 16:10 card tuned to fit
   selling-dashboard and certainty at the cost of visibly cropping
   already-shipped rows (warmup, sales-assistant) that had never been
   cropped before. Neither survived review. --img-ratio and the <img>
   width/height attributes
   below should always be the SAME two numbers for a given row — the
   custom property drives the reserved-space box, the attributes are the
   browser's pre-load layout hint, and letting them diverge is how the
   2000x1250 mistake happened in the first place. onerror hides just the
   broken <img> on a 404, leaving the surrounding placeholder-box
   background visible instead of the browser's broken-image icon —
   needed because these rows ship ahead of Daniel's captures for later
   arc groups, same as before.

   A 'coming' STATUS row does not necessarily skip <picture> — see the
   IMAGE DEMOTION comment further down (§2, near .feat-row--coming) for how
   7.A.22's three 'coming' rows ship real, demoted screenshots instead of
   the .feat-motif box below, once a feature has a real capture to show.

   WebP only, no PNG fallback (unlike the hero/waitlist shots, which carry a
   PNG <img> fallback behind a <source> — this page does not). alt is real,
   descriptive text per image once a row's copy is written — never left ''
   on a shipped row. loading="lazy" and decoding="async" are mandatory on
   every built row's <img>. */

/* Every arc-group <section> (.section .feat-arc) — first one is
   "before-the-call". CORRECTED 7.A.21 (fourth pass): .section's default
   padding-block:var(--space-section-y) gave this, the section right after
   the hero, a full top step on top of the hero's own (already-cut, see
   §1) bottom step — the combined gap was BIGGER than an ordinary
   section-to-section boundary, not smaller. Cut to a quarter-step so the
   two together read as one tight, deliberate gap instead of two
   independent cuts fighting each other.

   SEVENTH PASS: bumped to a half-step to match §1's hero bottom-padding
   raise — the two together now total one full --space-section-y (the
   site's ordinary single-section rhythm), not half of one.

   EIGHTH PASS: bumped again to a three-quarter-step to match §1's hero
   bottom-padding raise — the two together now total 1.5x
   --space-section-y, MORE than the site's ordinary section-to-section
   gap, a deliberate exception for this page. Only the TOP is touched —
   the bottom (gap to the next arc group) keeps the full, ordinary
   --space-section-y rhythm, same as every other section boundary on the
   site. */
.feat-arc{
  padding-block-start:calc(var(--space-section-y) * 0.75);
}

/* Wraps one arc group's rows. Same generous inter-row rhythm as .hiw-rows;
   margin-top lifts the first row off the arc heading with the same step
   .hiw-rows uses off the how-it-works eyebrow. */
.feat-rows{
  display:flex;
  flex-direction:column;
  gap:var(--space-9);
  margin-top:var(--space-8);
}

/* Alternating two-column row — the ONLY row type (7.A.21, second pass).
   Mobile-first single column, visual first in source order so it stacks
   ABOVE the text on narrow widths — same as .hiw-row. The two-column
   desktop layout, the ~55/45 column split, and side alternation all live
   in the breakpoint at the bottom of this section — none of it applies
   below it, so mobile stays a plain single column. */
.feat-row{
  display:grid;
  grid-template-columns:1fr;
  gap:var(--space-7);
  align-items:center;
}

.feat-visual{
  display:flex;
  align-items:center;
  justify-content:center;
  /* min-width:0 lets this grid item shrink below its content's natural
     size — without it, a wide intrinsic image can force the 11fr/9fr
     track wider than the split intends. */
  min-width:0;
}

/* Shared placeholder-box shell for BOTH a real <picture> and the 'coming'
   .feat-motif box below: neutral token background + hairline border, so a
   missing image (or an intentionally imageless 'coming' row) reads as a
   deliberate empty slot rather than a broken-image icon sitting on bare
   page background.

   RATIO — REVISED AGAIN, 7.A.22, REVERSES THE ATTEMPT ABOVE: back to a
   per-image ratio, not one fixed card shape. That single-ratio attempt's
   16:10 forced real crop on every row except the two it was tuned for
   (selling-dashboard, certainty) — including cropping the two rows that
   were already shipped uncropped (warmup, sales-assistant). Daniel
   rejected that outcome outright: the card adapts to each image, not the
   other way round. `.feat-visual picture` takes its ratio from a
   `--img-ratio` custom property set inline per row to that image's own
   real captured dimensions (e.g. style="--img-ratio:1200/1020"), so
   object-fit:cover below is a no-op in the normal case — it only crops if
   a future capture's real dimensions and its --img-ratio inline value
   ever drift apart, which they should not: keep the two in sync when
   adding a row. Falls back to 16:10 only for a row that hasn't set one
   yet (an arc group not captured, matching the original placeholder
   behaviour). `.feat-motif` — never a real image — keeps the flat 16:10
   default, since there's nothing to size it against. Row heights are NOT
   uniform down the page as a result — accepted, on the record, in
   exchange for never cropping real UI out of a screenshot. */
.feat-visual picture{
  display:flex;
  align-items:center;
  justify-content:center;
  width:100%;
  aspect-ratio:var(--img-ratio, 16/10);
  overflow:hidden;
  border-radius:var(--radius-lg);
  background:var(--color-surface-3);
  border:1px solid var(--color-border);
}

.feat-visual .feat-motif{
  display:flex;
  align-items:center;
  justify-content:center;
  width:100%;
  aspect-ratio:16/10;
  overflow:hidden;
  border-radius:var(--radius-lg);
  background:var(--color-surface-3);
  border:1px solid var(--color-border);
}

.feat-visual picture img{
  display:block;
  width:100%;
  height:100%;
  object-fit:cover;
}

/* ----- 'coming' status: no image slot, a quiet motif instead -----
   A status:'coming' row (features-data.js) never carries a <picture> — there
   is no screenshot of a feature that does not exist yet. .feat-motif fills
   the same placeholder-box shell above with three small static dots instead
   — a restrained "not yet" mark in the site's existing abstract/greyscale
   motif language (how-it-works' wave/meters/notes, the tester dot field),
   not an icon or illustration. No motion: unlike those other motifs this one
   has nothing to usefully animate (no fill level, no loop that reads as
   "loading"), so it is static by construction rather than needing a
   reduced-motion override. aria-hidden — decorative, the LABELS.comingSoon
   text in .feat-badges (below) carries the actual meaning. */
.feat-motif-dots{
  display:flex;
  gap:var(--space-2);
}

.feat-motif-dots span{
  width:var(--space-2);
  height:var(--space-2);
  border-radius:var(--radius-pill);
  background:var(--color-text-tertiary);
}

/* SUPERSEDED 7.A.22, TWICE OVER (both unused, kept for the record):
   .feat-motif-dots (above) was never wired into any row. A first draft of
   the "coming to Max" rows then reused the landing features strip's own
   greyscale .feature-motif SVGs (landing.css, 7.A.5) instead — but that too
   is superseded now that Daniel's actual live-feedback / active-listening /
   weekly-statistics captures exist: those three rows render real, demoted
   <picture> previews (see the IMAGE DEMOTION block below), the same
   locked-contract markup the built rows use. Neither .feat-motif-dots nor
   the .feature-motif reuse below is wired into any row's markup as of
   7.A.22; both are left in place rather than deleted since removing them
   wasn't part of this task.

   .feature-motif is consumed VERBATIM (markup + landing.css rules) where it
   WAS used — width, greyscale currentColor strokes/fills, and the static
   resting SVG state all come from there unmodified. The one override that
   was needed: landing scopes it inside a card with text above it
   (margin-top:var(--space-5) pushes it below that text); here it would be
   the ONLY thing in a centred flex box (.feat-visual .feat-motif above), so
   that margin-top was reset to 0 or it would sit visibly off-centre. */
.feat-motif .feature-motif{
  margin-top:0;
}

/* ----- 'coming' rows that DO ship a screenshot (7.A.22) -----
   live-feedback / active-listening / weekly-statistics render the same
   locked <picture> contract as any built row (§2 above) — real screenshots
   now exist for them, reversing the motif-only decision above. Each row's
   markup also carries .feat-row--coming, which demotes the shot two ways so
   it never reads as an equal peer to the built rows above it, without
   needing a second component:

     1. NARROWER IMAGE COLUMN — the breakpoint below shrinks the image
        track from the built rows' 9fr/11fr (~45%) to 7fr/13fr (~35%), text
        taking the rest. Alternation (.feat-row--text-left) still flips
        which side is narrow, exactly like the built rows.
     2. LIGHTER, MORE-RECESSIVE BOX — background swaps from the built rows'
        --color-surface-3 to --color-surface-2. Tokens only, and it reads as
        "receding toward the page" in BOTH themes even though the two
        tokens move in opposite absolute directions: in light mode
        surface-2 (#fafafa) sits closer to --color-bg (#ffffff) than
        surface-3 (#f0f0f0) does; in dark mode surface-2 (#1b1b1b) sits
        closer to --color-bg (#1d1d1d) than surface-3 (#292929) does. Same
        token swap, same "blends toward background" effect, both themes —
        no separate dark-mode override needed.

   No object-fit change — still the shared cover crop (§2), same as the
   built rows, so this stays one visual contract for every <picture> on the
   page; the column/background changes above are what carries the
   demotion. */
@media (min-width: 60rem){
  .feat-row--coming{
    grid-template-columns:7fr 13fr;
  }
  .feat-row--coming.feat-row--text-left{
    grid-template-columns:13fr 7fr;
  }
}

.feat-row--coming .feat-visual picture{
  background:var(--color-surface-2);
}

/* active-listening ONLY, on request: even inside the already-narrowed
   7fr/13fr 'coming' column above, its 800x915 portrait still read too
   wide. .feat-visual is a centred flex box, so capping the picture's own
   max-width shrinks and centres it within that column without touching
   live-feedback or weekly-statistics, which share .feat-row--coming but
   were not asked for.

   SCOPED TO >=60rem, Phase 7.A.26: this rule used to be unscoped, so it
   also capped active-listening's picture on phones — at a DIFFERENT
   percentage (70%) than the uniform mobile cap the seven other rows now
   get (§2 below, the mobile visual-sizing block). Wrapping it in the same
   60rem breakpoint as the coming column it was written for keeps this
   fix desktop-only, exactly as it already reads above, and lets the
   mobile block be the one rule governing all eight rows' phone width. */
@media (min-width: 60rem){
  [data-slug="active-listening"] .feat-visual picture{
    max-width:70%;
  }
}

.feat-text{
  display:flex;
  flex-direction:column;
}

/* Badge cluster above the heading — tier pill + a "coming soon" note, only
   present on rows whose features-data.js entry is not {tier:'all',
   status:'built'}. Empty on an all-tier/built row (no badge shown), so this
   wrapper collapses to nothing rather than reserving dead space. */
.feat-badges{
  display:flex;
  align-items:center;
  gap:var(--space-2);
}

/* Tier pill shell — mirrors the landing features strip's .feature-tier
   shell (transparent, thin theme-adaptive outline, no fill of its own; the
   tier is conveyed entirely by the gradient text inside via .metal-text).
   Restated here rather than reused directly: this page's rows are a
   different component from that accordion strip. The gradient itself is
   NOT redefined — .metal-text / .metal-text--pro / .metal-text--max are
   consumed verbatim from landing.css. */
.feat-tier{
  display:inline-flex;
  align-items:center;
  line-height:1;
  padding:var(--space-1) var(--space-2);
  border-radius:var(--radius-pill);
  background:transparent;
  border:1px solid var(--color-border);
}

.feat-tier__text{
  font-size:var(--text-xs);
  font-weight:var(--weight-semibold);
  letter-spacing:var(--tracking-normal);
  text-transform:uppercase;
}

/* "Coming soon" note — plain muted text, no pill, no gradient: it is a
   build-status note, not a tier, so it must not read as a fourth tier
   badge. Matches the app/pricing "Coming Soon" framing in tone only. The
   TEXT this class wraps must be features-data.js's LABELS.comingSoon
   verbatim, tagged data-feature-label="comingSoon" in the markup — the
   same canonical-string-plus-tag convention waitlist-offer.js established
   for the early-access offer copy, so a hand-typed synonym would be
   visibly inconsistent with the module rather than silently drifting. */
.feat-status--coming{
  font-size:var(--text-xs);
  font-weight:var(--weight-semibold);
  letter-spacing:var(--tracking-normal);
  text-transform:uppercase;
  color:var(--color-text-tertiary);
}

.feat-heading{
  /* Same step as the how-it-works row heading — bigger, calmer type than a
     card title, clearly subordinate to the hero (--text-6xl). */
  font-size:var(--text-3xl);
  margin-top:var(--space-2);
}

.feat-body{
  /* Mirrors the how-it-works row body / hero subhead (size, secondary tone,
     prose measure) so every row on this page reads as one system. */
  font-size:var(--text-lg);
  color:var(--color-text-secondary);
  max-width:var(--measure-prose);
  margin-top:var(--space-4);
}

/* ----- Mobile layout: two columns, alternating, image narrower
   (Phase 7.A.29 — REVERSES 7.A.26) -----
   7.A.26 stacked the visual above/below the text below 60rem — a single
   1fr column, order:2/1 flipping the visual after the text, capped to
   max-width:60%, left-flush. That read as a full-width banner sitting
   over unrelated copy rather than an image belonging to the row beneath
   it — wrong call, reversed here in full: the order pair, the 60% cap,
   and the justify-content:flex-start left-flush are all deleted
   outright, nothing here inherits from them. [data-slug=active-listening]
   .feat-visual picture's own max-width:70% (above, in §2) stays exactly
   as 7.A.26 scoped it — min-width:60rem only — untouched by this pass.

   Below 60rem .feat-row is now TWO columns side by side, same shape the
   >=60rem block below already uses, just its own narrower split and its
   own breakpoint — not stacked, not left-flush.

   SPLIT — image the SMALLER share, 35%/65% (roughly the >=60rem
   'coming' rows' own 7fr/13fr ratio, but applied here uniformly to all
   eight rows, built and coming alike — nothing on this page's mobile
   layout distinguishes the two the way the desktop coming-row narrowing
   does). Measured (real SF Pro Text glyph widths via CoreText, greedy
   word-wrap simulation, same method as 7.A.25) at 375/393/430px: the
   text column lands at 181/193/217px. 181px at 375px sits right on the
   ~180px floor Daniel flagged as the shift-the-split trigger — but every
   description on the page, including the longest (certainty, 253
   characters) wraps clean with zero word overflow at all three widths
   (certainty: 13 lines at 375px, 13 at 393px, 11 at 430px), so the split
   stands as specified rather than moving further toward text.

   ALTERNATION — reuses the exact order-based flip the >=60rem block
   below already uses on .feat-row--text-left, re-declared here since
   that block's own order rules are scoped to min-width:60rem and don't
   reach this breakpoint. Source order stays visual-then-text either
   way; only paint order and track width flip. Verified row by row
   against the markup: warmup (image left), sales-assistant (right),
   selling-dashboard (left), certainty (right), objection-handling
   (left), live-feedback (right), active-listening (left),
   weekly-statistics (right) — L/R/L/R/L/R/L/R down the page, unbroken,
   same as >=60rem.

   HEIGHT — .feat-row's own align-items:center (declared above, no media
   query) is untouched, so the two columns still sit centred on the
   cross axis here, not top-aligned or stretched, same as >=60rem. At
   393px this split makes TEXT the taller column on every row, including
   the two 800/915 portrait rows (live-feedback, active-listening) that
   were the risk case: the image column is narrow enough (~104px) that
   even a tall portrait crop stays shorter than its row's own multi-line
   prose, so both rows' images now sit centred in extra vertical space
   beside the text, not the other way round. Reversed from the 7.A.26
   stacked layout, where live-feedback's image (237px) ran taller than
   its text (~178px) and active-listening's were close to level (237px
   vs ~234px). Row totals at 393px, before (7.A.26 stacked) to after
   (this pass, side by side): warmup 507 to 516, sales-assistant 548 to
   488, selling-dashboard 433 to 442, certainty 593 to 688,
   objection-handling 520 to 576, live-feedback 463 to 280,
   active-listening 519 to 392, weekly-statistics 328 to 224. Box-model
   arithmetic plus real glyph metrics, no browser render — worth an eye
   in Safari responsive mode before this is relied on, same caveat
   7.A.25 shipped with. */
@media (max-width: 59.999rem){
  .feat-row{
    grid-template-columns:35fr 65fr;
  }

  .feat-row--text-left{
    grid-template-columns:65fr 35fr;
  }

  .feat-row--text-left .feat-visual{
    order:2;
  }

  .feat-row--text-left .feat-text{
    order:1;
  }
}

/* Two-column desktop layout + side alternation — same 60rem breakpoint and
   the same `order`-based flip as .hiw-row--text-left. Source order is
   visual-then-text, so the default row is visual-left; .feat-row--text-left
   flips the two with `order`, exactly mirroring how-it-works, so 7.A.21–24
   alternate rows by adding this one class rather than reordering markup
   (source order stays visual-then-text either way, matching a screen
   reader/tab sequence regardless of which side paints where).

   COLUMN SPLIT — CORRECTED 7.A.21 (second pass, INVERTED in a ninth): the
   second pass replaced an even 1fr/1fr split with the image column WIDER
   than text (~55/45), reasoning from the dense whole-app screenshots the
   (now-removed) full-width row variant existed for. Once the real warmup/
   sales-assistant captures were in place at their own natural ratios
   (§2 above), that wide image column read as too large / too dominant
   against the text — so the ninth pass INVERTED the ratio: TEXT is now
   the wide column (~55%) and the image the narrow one (~45%), 11fr/9fr ⇒
   9fr/11fr (and vice versa) from what shipped before. The ratio still
   FLIPS along with the `order` swap below: .feat-row's default column 1
   holds the image (9fr, narrow) and column 2 the text (11fr, wide);
   .feat-row--text-left reverses the track sizes too (11fr/9fr) so
   column 1 — now holding the text, via `order` — stays the wide one and
   column 2 — now the image — stays the narrow one. The narrow column
   always belongs to whichever side the image actually renders on, never
   to a fixed column position.

   NO IMAGE BLEED — CORRECTED 7.A.21 (fourth pass): the second pass had the
   image run past .container to the true viewport edge on its own outer
   side. Reverted — the outer edge now stops at the ordinary container
   padding, same as the TEXT side, so BOTH sides of every row use the same
   padding-inline:var(--container-pad-x) gutter .hero-media sits inside
   too, no bleed either. (This got the PADDING to match the hero — §3
   below is what makes the full side distance, padding AND the outer
   auto-centring margin, match it exactly.) */
@media (min-width: 60rem){
  .feat-row{
    grid-template-columns:9fr 11fr;
  }

  .feat-row--text-left{
    grid-template-columns:11fr 9fr;
  }

  .feat-row--text-left .feat-visual{
    order:2;
  }

  .feat-row--text-left .feat-text{
    order:1;
  }
}

/* ---------- 3. Page container width ---------- */
/* ADDED 7.A.21 (sixth pass). Every section on this page wraps its content
   in the standard .container (components.css: max-width:var(--container-
   max) = 75rem, margin-inline:auto, padding-inline:var(--container-pad-x)).
   The landing hero does NOT use .container — .hero-grid (landing.css §1)
   has its own wider max-width:92.25rem, plus the same margin-inline:auto
   and padding-inline:var(--container-pad-x). Both share the padding
   token, so they LOOK aligned at a glance, but the two different
   max-widths mean the auto-centring margin beyond each cap diverges as
   soon as the viewport exceeds ~75rem — Daniel measured this directly in
   devtools (48px padding, matching; 117px margin on the landing hero,
   NOT matching this page's rows at the same viewport width).

   Fix: this page's .container instances take the hero's own 92.25rem cap
   instead of the site-standard one, so the side distance — padding AND
   margin together — matches the landing hero exactly, not just the
   padding half of it. 92.25rem is not a design token here either (see
   landing.css's own comment on .hero-grid); restated verbatim rather than
   introducing a new one. Scoped to .feat-intro/.feat-arc's own .container
   so no other page's .container is affected. Applies to BOTH the hero and
   every arc-group section so the whole page keeps one consistent left/
   right edge, not just the rows. */
.feat-intro .container,
.feat-arc .container{
  max-width:92.25rem;
}

/* ---------- 4. Close (7.A.23) ---------- */
/* The page's last section: a centred heading + one line + two buttons, no
   form. Deliberately takes the STANDARD .container (75rem, no override) —
   unlike §3 above, which widens .feat-intro/.feat-arc specifically for
   their two-column rows. A centred single column has no reason to run that
   wide; this matches how the landing final-CTA also stays on the plain
   .container rather than tracking the hero's own wider cap. No padding
   override either: the shared .section rhythm (components.css,
   padding-block:var(--space-section-y) top AND bottom) is used as-is, on
   purpose — this section must not assume it is adjacent to whatever
   currently sits above it (today, coming-to-max; later, arc group 3 once
   7.A.24 lands), so it carries its own full rhythm on both sides rather
   than a half-step coupled to a specific neighbour. */
.feat-close{
  text-align:center;
}

/* Same section-heading step as the landing final-CTA (--text-5xl, one
   below the hero's --text-6xl) and every other section heading on the
   site (problem/privacy/pricing/faq). text-wrap:balance for the same
   reason final-cta uses it: short headings read better even where they
   don't strictly need the second line. */
.feat-close-title{
  font-size:var(--text-5xl);
  text-wrap:balance;
}

/* One supporting line under the heading — same size/tone as the hero
   subhead and every other section lead-in on this page. measure-prose cap
   + auto side margins keeps it centred and readable at any width. */
.feat-close-body{
  font-size:var(--text-lg);
  color:var(--color-text-secondary);
  max-width:var(--measure-prose);
  margin-inline:auto;
  margin-top:var(--space-4);
}

/* Two buttons, side by side with room, wrapping to a stacked pair on
   narrow widths rather than a dedicated breakpoint — flex-wrap does the
   job here since both items are their own natural (label+padding) width,
   unlike final-cta's form controls which need an explicit stacked/row
   swap to manage the input's flex-grow. */
.feat-close-actions{
  display:flex;
  flex-wrap:wrap;
  align-items:center;
  justify-content:center;
  gap:var(--space-4);
  margin-top:var(--space-7);
}

/* ----- Scroll reveal -----
   Handled by the generic reveal ruleset (landing.css §2, same contract as
   every .reveal group on the site). .feat-close is the group; its risers
   are the heading, the body line, and the action row — three risers,
   matching the landing final-CTA's title/form/tester-line beat count. */
