.page_page___svW2 {
  max-width: var(--max-width-dashboard);
  margin: 0 auto;
  padding: calc(var(--nav-height) + 32px) var(--page-gutter) 64px;
}

/* Shared coach avatar: tinted-initials circle, or the coach photo clipped to
   the same circle. Sizing is driven by the --avatar-size CSS var so one
   component serves every surface (44 / 64 / 72 / 84 px today). Tokens and the
   serif-500 initials match the prior per-surface avatar styling. */
.coach-avatar_avatar__iUC7f {
  width: var(--avatar-size, 64px);
  height: var(--avatar-size, 64px);
  border-radius: var(--radius-pill);
  display: grid;
  place-items: center;
  overflow: hidden;
  flex-shrink: 0;
  color: var(--cream-light);
  font-family: var(--font-serif);
  /* Initials scale with the avatar (64px wrapper renders ~24px, matching the
     previous fixed sizing). */
  font-size: calc(var(--avatar-size, 64px) * 0.375);
  font-weight: 500;
  letter-spacing: -0.02em;
  line-height: 1;
  -webkit-user-select: none;
          user-select: none;
}

.coach-avatar_img__clnty {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
  display: block;
  /* Gentle fade-in once the photo paints. Disabled under reduced motion. */
  animation: coach-avatar_coachAvatarFade__cnwE2 200ms ease both;
}

@keyframes coach-avatar_coachAvatarFade__cnwE2 {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

@media (prefers-reduced-motion: reduce) {
  .coach-avatar_img__clnty {
    animation: none;
  }
}

/* Deterministic tones (mirror coach-list): a coach keeps one colour everywhere.
   The soft drop shadow also reads as a subtle lift under a photo. */
.coach-avatar_toneForest__mPMUB {
  background: var(--green-dark);
  box-shadow: 0 10px 24px -12px color-mix(in srgb, var(--green-dark) 70%, transparent);
}

.coach-avatar_toneAmber__HIey3 {
  background: var(--golden-sand);
  box-shadow: 0 10px 24px -12px color-mix(in srgb, var(--golden-sand) 65%, transparent);
}

.coach-avatar_toneOak__Hf84v {
  background: var(--wood-oak);
  box-shadow: 0 10px 24px -12px color-mix(in srgb, var(--wood-oak) 65%, transparent);
}

.coach-avatar_toneSage__PNWj4 {
  background: var(--warm-amber);
  box-shadow: 0 10px 24px -12px color-mix(in srgb, var(--warm-amber) 65%, transparent);
}

.book-session-dialog_content__UxuxQ {
  padding: var(--space-7) var(--space-7) var(--space-6);
}

.book-session-dialog_title__7OMkK {
  font-family: var(--font-serif);
  font-size: var(--fs-xl);
  font-weight: 500;
  color: var(--light-head);
  letter-spacing: -0.02em;
  line-height: var(--lh-tight);
  margin: 0;
}

.book-session-dialog_subtitle__x85Wa {
  font-family: var(--font-sans);
  font-size: var(--fs-base);
  color: var(--light-mute);
  line-height: var(--lh-snug);
  margin: var(--space-2) 0 var(--space-5);
}

.book-session-dialog_list___WSCo {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.book-session-dialog_row__sgbl_ {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-2) 0;
}

.book-session-dialog_meta__sk83w {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
  flex: 1 1;
}

.book-session-dialog_name__xyGFp {
  font-family: var(--font-serif);
  font-size: var(--fs-md);
  font-weight: 500;
  color: var(--light-head);
  margin: 0;
}

.book-session-dialog_role__buOjw {
  font-family: var(--font-sans);
  font-size: var(--fs-xs);
  color: var(--light-mute);
  margin: 0;
}

/* Loading / empty state */
.book-session-dialog_state__DvmJI {
  font-family: var(--font-sans);
  font-size: var(--fs-base);
  color: var(--light-mute);
  text-align: center;
  padding: var(--space-5) 0;
  margin: 0;
}

.book-session-dialog_note__7RgQw {
  font-family: var(--font-sans);
  font-size: var(--fs-xs);
  color: var(--light-mute);
  margin: var(--space-4) 0 0;
}

.book-session-dialog_foot__7qjP1 {
  margin-top: var(--space-6);
  padding-top: var(--space-5);
  border-top: 1px solid var(--border);
}

.coach-card_root__ISSLH {
  background: var(--cream-light);
  border: 1px solid var(--border);
  border-radius: 16px;
  padding: 22px 24px;
  box-shadow: var(--shadow);
}

.coach-card_head__mSGof {
  display: grid;
  grid-template-columns: 84px 1fr;
  gap: 18px;
  align-items: center;
}

.coach-card_info__SmBQx {
  min-width: 0;
}

.coach-card_nameRow__4XuXO {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 2px;
  flex-wrap: wrap;
}

.coach-card_name__7nbw_ {
  font-family: var(--font-serif);
  font-size: 17px;
  font-weight: 500;
  color: var(--light-head);
  margin: 0;
}

.coach-card_pick__L0wmQ {
  display: inline-flex;
  align-items: center;
  padding: 3px 9px;
  border-radius: 999px;
  background: var(--cream-dark);
  color: var(--light-body);
  font-size: 10.5px;
  font-weight: 500;
}

.coach-card_role__z142L {
  font-size: 12.5px;
  color: var(--light-mute);
  margin-bottom: 8px;
}

.coach-card_footer__Yl46S {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
  margin-top: 16px;
  padding-top: 14px;
  border-top: 1px solid var(--border);
}

/* Member-facing coach card (Services tab + coach profile preview).
   Spacing follows the DS SpacingSpec usage map:
   large card padding -> --space-5 · card inner gap -> --space-3 ·
   tight pairs -> --space-1 · pill gap -> --space-2 */

/* Card primitive owns border / radius-lg / shadow / hover lift. */
.coach-public-card_card__11nrK {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  width: 100%;
  height: 100%;
  padding: var(--space-5);
}

/* ── Heading (serif name + sans subtitle, tight pair) ────────────────────── */
.coach-public-card_heading__nsYkM {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}

.coach-public-card_name__m_101 {
  font-family: var(--font-serif);
  font-size: var(--fs-xl);
  font-weight: 500;
  color: var(--light-head);
  letter-spacing: -0.02em;
  line-height: var(--lh-tight);
  margin: 0;
}

.coach-public-card_role__E7win {
  font-family: var(--font-sans);
  font-size: var(--fs-base);
  color: var(--light-mute);
  margin: 0;
}

/* ── Body copy (DM Sans) ─────────────────────────────────────────────────── */
.coach-public-card_quote__uaGS6 {
  font-family: var(--font-sans);
  font-size: var(--fs-md);
  font-weight: 400;
  color: var(--light-body);
  line-height: var(--lh-snug);
  margin: 0;
  text-wrap: pretty;
}

/* ── Focus pills ─────────────────────────────────────────────────────────── */
.coach-public-card_tags__9eg55 {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

/* Divider spacing comes from the card's --space-3 gap, not its own margin. */
.coach-public-card_divider__qwo_c {
  margin: 0;
}

/* ── Outside of coaching (tight label + body pair) ───────────────────────── */
.coach-public-card_outside__b3ama {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}

.coach-public-card_outsideLabel__qnbzj {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: var(--tracking-eyebrow);
  color: var(--wood-oak);
  margin: 0;
}

.coach-public-card_outsideText__sKtic {
  font-family: var(--font-sans);
  font-size: var(--fs-base);
  color: var(--light-body);
  line-height: var(--lh-normal);
  margin: 0;
}

/* Bio-pending coaches: a gentle placeholder instead of the full body. */
.coach-public-card_pending___LcrE {
  font-family: var(--font-sans);
  font-size: var(--fs-md);
  color: var(--light-mute);
  line-height: var(--lh-snug);
  font-style: italic;
  margin: 0;
  text-wrap: pretty;
}

/* ── Footer actions (pinned to the card bottom so buttons align in a row) ── */
.coach-public-card_foot__efEtQ {
  margin-top: auto;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

/* Not-bookable coach: a clear, readable status chip (replaces the old 10px
   ghost note). AA: --light-body on --cream. */
.coach-public-card_availNote__QDZ07 {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  margin: 0;
  padding: var(--space-2) var(--space-3);
  background: var(--cream);
  border-radius: var(--radius-sm);
  font-family: var(--font-sans);
  font-size: var(--fs-base);
  font-weight: 500;
  color: var(--light-body);
}

.coach-public-card_availIcon__l6vRI {
  flex-shrink: 0;
  color: var(--light-mute);
  display: inline-flex;
}

/* List-level layout only; the card itself lives in coach-public-card.module.css.
   Spacing follows the DS SpacingSpec usage map: grid gutter -> --space-4. */
.coach-list_grid__YDe3V {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  /* Two balanced columns (4 coaches → tidy 2×2, not a stranded 3 + 1). */
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-4);
  /* Equal-height cards per row (default grid stretch) so the "View profile"
     buttons line up across the row regardless of differing copy length. */
}

.coach-list_item__tCmjy {
  display: flex;
}

.coach-list_loading__d0TZT {
  font-family: var(--font-sans);
  font-size: var(--fs-base);
  color: var(--light-mute);
  margin: 0;
}

@media (max-width: 560px) {
  .coach-list_grid__YDe3V {
    grid-template-columns: 1fr;
  }
}

/* Dark sky: the loading line sits directly on the page background. */
html[data-time="evening"] .coach-list_loading__d0TZT,
html[data-time="night"] .coach-list_loading__d0TZT {
  color: var(--sky-body);
}

/* Challenger session card. Token mapping and literal-color rules live in
 * hero-section.module.css.
 *
 * TWO BLOCKS, and you can tell which is which without reading. What separates
 * them, in order of how much work each does:
 *   1. the upcoming session sits on a TINTED PANEL, not under a hairline. A
 *      rule reads as "more of the same card"; a different ground reads as a
 *      different thing, which is what it is.
 *   2. the recording's badge lives ON the poster, so it labels the image it
 *      belongs to instead of taking a line of its own above it.
 *   3. the panel's CTA is a filled forest button, so the action sits with the
 *      thing it acts on and is unmistakably the card's primary move.
 *
 * Contrast, all AA at their sizes:
 *   on the #fffdf8 card ground
 *     light-head  14.5:1  heading, deck link
 *     #3c3a35      9.3:1  takeaways
 *     #55524c      7.7:1  sub, deck terms
 *   on the --cream-dark panel (#ede9e0)
 *     light-head  14.9:1  session title
 *     green-dark   8.1:1  badge
 *     #55524c      7.0:1  date, fine print
 *   on the --green-dark button (#2d4a32)
 *     cream        9.1:1  CTA label
 *   on the poster scrim
 *     #f5f0ea and --gold, both over a near-opaque dark gradient; the scrim is
 *     what makes them legible over an arbitrary still, so it is not optional.
 */

.session-card_card__05dIe {
  background: #fffdf8;
  border: 1px solid rgba(45, 74, 50, 0.15);
  border-radius: 16px;
  padding: 16px;
  box-shadow: 0 12px 32px rgba(27, 15, 51, 0.08);
}

.session-card_block__KI2hU {
  min-width: 0;
}

/* The poster carries the play affordance and now its own label. Taller than it
   was, because it is the first thing in the card since the badge moved onto
   it. object-fit: cover means the still is recropped, never squashed. */
.session-card_poster__dTq9_ {
  position: relative;
  display: block;
  width: 100%;
  height: 168px;
  background: var(--cream-dark);
  border: 1px solid rgba(45, 74, 50, 0.12);
  border-radius: 12px;
  overflow: hidden;
  cursor: pointer;
  padding: 0;
}

.session-card_poster__dTq9_:focus-visible {
  outline: 2px solid var(--light-head);
  outline-offset: 3px;
}

.session-card_posterImage__M_Rs8 {
  object-fit: cover;
}

.session-card_posterBadge__Ynlt_ {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}

/* Restyle the shared PlayBadge through its className hook: dark round ground,
 * warm icon, gold icon on hover. The descendant selector outweighs both the
 * badge's own single-class rule and its zero-specificity hover. */
.session-card_poster__dTq9_ .session-card_posterBadge__Ynlt_ {
  background: rgba(27, 15, 51, 0.88);
  color: #f5f0ea;
  box-shadow: none;
}

.session-card_poster__dTq9_:hover .session-card_posterBadge__Ynlt_ {
  color: #b98a1f;
}

/* The recording's label, above the poster on the card's own ground. See the
   component for why it is not on the image. */
.session-card_badge__1a1se {
  font-family: var(--font-mono);
  font-size: 9.5px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  line-height: 1.6;
  color: var(--green-dark);
  margin: 0 0 10px;
}

.session-card_badgeSep__Vfkdb {
  color: rgba(45, 74, 50, 0.45);
}

/* Gold is 1.9:1 on this ground, so it is EMPHASIS on a word that is also
   spelled out, never the only thing carrying it: the label reads "Recorded
   session, free" whether or not the colour lands. Weight stays at the mono
   default; bolding it as well was part of what read as heavy. */
.session-card_badgeFree__28Lyn {
  color: var(--wood-oak);
}

/* An h3, not a styled paragraph: it names the thing the poster above it opens,
   and the card sits inside the hero's outline under the h1. */
/* 400, not 500. Lora loads 400 and 500 only, and at this size on a small card
   500 was reading as the heaviest thing on the page. */
.session-card_heading__fOo1i {
  font-family: var(--font-heading);
  font-weight: 400;
  font-size: 17px;
  line-height: 1.3;
  color: var(--light-head);
  text-wrap: pretty;
  margin: 14px 0 0;
}

.session-card_sub__5m_is {
  font-size: 13px;
  line-height: 1.6;
  color: #55524c;
  margin: 6px 0 0;
}

/* A checked list, not pills. Three pills wrapped 2 + 1 and read as tags; ticks
   read as things you walk away with, which is what they are. */
.session-card_takeaways__Z3HBx {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 7px;
  margin: 12px 0 0;
  padding: 0;
}

.session-card_takeaway__KLK3B {
  display: flex;
  align-items: flex-start;
  gap: 9px;
  font-size: 13px;
  line-height: 1.5;
  color: #3c3a35;
}

/* Decoration: every item's text stands on its own, so the glyph never carries
   meaning alone. Nudged down to sit on the text's first line. */
.session-card_pencil__c5e6u {
  flex: none;
  margin-top: 3px;
  color: var(--green-dark);
}

/* The deck for the recording above.

   Its OWN ROW, opened by a hairline. Sharing a run with the takeaways is what
   made this look like clutter: the card already stacks a poster, a heading, a
   sentence and three items, and a bare underlined sentence dropped after them
   read as a loose fifth line rather than as a thing you can take away. The
   rule turns it into the recording block's footer, and the icon says "file"
   before the words do. */
/* ONE line: link, separator, terms. The icon is gone and the label sits beside
   its terms rather than above them. The download glyph was doing work the word
   "Download" already does, and it forced a second line on a narrow card. */
.session-card_deckLine__P92FL {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 6px;
  margin: 14px 0 0;
  padding-top: 12px;
  border-top: 1px solid rgba(27, 15, 51, 0.1);
}

/* Underlined rather than a button. The panel below already has the card's
   primary button and the poster opens the lightbox; a third pill would make
   three competing targets out of one small column.

   Forest green, not near-black: it is the one link in this half of the card
   and the colour is what says so. 8.8:1 on the card ground. */
.session-card_deckCta__Pe54g {
  font-size: 13px;
  color: var(--green-dark);
  text-decoration: underline;
  text-underline-offset: 3px;
  padding: 2px 0;
}

.session-card_deckSep__Niyb_ {
  color: rgba(27, 15, 51, 0.35);
}

.session-card_deckCta__Pe54g:hover {
  color: var(--light-head);
}

.session-card_deckCta__Pe54g:focus-visible {
  outline: 2px solid var(--light-head);
  outline-offset: 3px;
  border-radius: 3px;
}

.session-card_deckMeta__EL4nH {
  font-family: var(--font-mono);
  font-size: 10px;
  line-height: 1.6;
  color: #55524c;
}

/* ── The upcoming session ─────────────────────────────────────────────────
   A tinted panel rather than a hairline-divided run of text. It is a different
   KIND of thing from the recording above it (something that has not happened
   yet, versus something you can open now), and a change of ground says that
   before any of the words do. */
.session-card_next__EDdef {
  position: relative;
  overflow: hidden;
  isolation: isolate;
  margin-top: 16px;
  padding: 14px 14px 12px;
  /* Owner-picked. Opaque, not a tint over the card: the previous
     rgba(100,130,44,0.14) resolved to (233,236,219) against #fffdf8, which
     made the panel's colour a function of whatever it sat on. A flat value
     cannot drift if the card ground is ever retuned.
     Every text pair on this panel gained contrast on the change, measured
     both flat and at the corner glow's centre. */
  background: #f1f1e7;
  border: 1px solid rgba(100, 130, 44, 0.22);
  border-radius: 12px;
}

/* The light in the top-right corner. Warm against the green so the panel has a
   direction to it rather than reading as a flat swatch. Behind the content on
   its own layer: a pseudo-element paints ABOVE its parent's background but in
   normal order with the children, so without the z-index pair it would wash
   over the title. */
.session-card_next__EDdef::before {
  content: "";
  position: absolute;
  top: -56px;
  right: -44px;
  z-index: 0;
  width: 168px;
  height: 168px;
  border-radius: 50%;
  /* 0.24, not stronger. The date sits top-right, which is exactly where this
     lands, and the glow lightens the ground under it. Measured at the glow's
     CENTRE (the harshest point the text can sit on) against the #f1f1e7
     ground: wood-oak reads 4.77:1 at 0.24, so the floor still holds with a
     little more room than the old tint gave it (4.60:1). The ceiling on this
     effect is an accessibility number, not a taste call: re-measure here
     before raising the alpha or relighting the panel. */
  background: radial-gradient(
    circle,
    rgba(221, 184, 74, 0.24),
    rgba(221, 184, 74, 0) 68%
  );
  pointer-events: none;
}

.session-card_next__EDdef > * {
  position: relative;
  z-index: 1;
}

/* Badge left, date right. They are a pair: what this block is, and when. */
.session-card_nextHead__mHpzf {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 4px 12px;
  margin: 0;
}

.session-card_nextBadge__vuJcX {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-family: var(--font-mono);
  font-size: 9.5px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  line-height: 1.6;
  color: var(--green-dark);
}

/* A green dot that breathes. It is the one thing on the card still to happen,
   and a slow dim is the quietest way to say "live, soon" without a countdown.

   DECORATION, always: the badge beside it says "next live session" in words,
   so the animation carries nothing on its own.

   No per-component reduced-motion query. globals.css sweeps every descendant
   under html[data-motion="static"] (duration and iteration count) and caps
   iterations under html[data-motion-heavy="static"], so a plain infinite
   animation inherits both kill switches. A local media query here would be a
   third source of truth for the same rule. */
.session-card_dotNext__kEHOA {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--green);
  flex-shrink: 0;
  animation: session-card_nariSessionDotPulse__7IEm7 2.6s ease-in-out infinite;
}

@keyframes session-card_nariSessionDotPulse__7IEm7 {
  0%,
  100% {
    opacity: 1;
    box-shadow: 0 0 0 3px rgba(100, 130, 44, 0.22);
  }
  50% {
    opacity: 0.5;
    box-shadow: 0 0 0 8px rgba(100, 130, 44, 0.04);
  }
}

/* Warm against the green, picking up the corner light. */
.session-card_nextDate__i454y {
  font-family: var(--font-mono);
  font-size: 11px;
  line-height: 1.6;
  color: var(--wood-oak);
  white-space: nowrap;
}

/* The session's own name, in the heading face so it reads as a title rather
   than as another line of meta. 400 for the same reason as .heading. */
.session-card_nextTitle__I5Yx7 {
  font-family: var(--font-heading);
  font-weight: 400;
  font-size: 15.5px;
  line-height: 1.3;
  color: var(--light-head);
  text-wrap: pretty;
  margin: 8px 0 0;
}

/* Full width and filled: this is the card's primary action, and as a bordered
   pill it was competing with the deck link for the same attention. */
.session-card_detailsCta__3zNxK {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  min-height: 44px;
  margin-top: 12px;
  padding: 12px 20px;
  border-radius: 999px;
  background: var(--green-dark);
  color: var(--cream);
  font-size: 13.5px;
  font-weight: 500;
  text-decoration: none;
  transition: background-color 160ms ease;
}

.session-card_detailsCta__3zNxK:hover {
  background: var(--light-head);
}

.session-card_detailsCta__3zNxK:focus-visible {
  outline: 2px solid var(--light-head);
  outline-offset: 3px;
}

.session-card_ctaArrow__kDQ1I {
  white-space: pre;
}

/* No session: the CTA alone, no tint. The panel frames a specific upcoming
   session, so with nothing to frame it would just be a coloured box implying
   one exists. */
.session-card_nextBare__FaVfl {
  margin-top: 14px;
}

.session-card_nextFine__8apMT {
  font-family: var(--font-mono);
  font-size: 10px;
  line-height: 1.6;
  color: #55524c;
  text-align: center;
  margin: 10px 0 0;
}

/*
 * Challenger hero ("01 The door").
 *
 * THIS IS THE CONTROL'S HERO LAYOUT, COPIED, with the challenger's cream
 * palette, its own artwork and its own copy on top. Same decision, and the
 * same reason, as close/close-section.module.css: the artifact's own hero
 * structure (a fixed art band along the base, fully reserved out of the copy
 * column's padding) was retuned repeatedly and never stopped reading as
 * top-heavy, because the reservation IS the defect. A band that the copy may
 * never enter is dead space by construction, so the copy can only ever sit
 * above it, and no amount of retuning centres content inside a box whose
 * lower third is off limits.
 *
 * components/marketing/landing/hero/ had already solved this: art at inset 0,
 * scrims for legibility, and one grid with `align-items: center`. Nothing is
 * reserved, so nothing is stranded. Keep the four declarations marked below in
 * step with that file; hero-section.test.tsx reads it and compares.
 *
 * What stays the challenger's own, deliberately: the cream ground and the
 * sunrise panorama in place of the night forest, the type scale, the gold
 * membership rail, and the two CTA pills.
 *
 * The rgba(245, 242, 235, x) stops are alpha composites of the cream token,
 * kept literal exactly as the control keeps its navy composites.
 *
 * Motion: this file declares no animation. The two hover transitions
 * (background-color / border-color, 160ms) are killed by the global
 * html[data-motion="static"] descendant sweep in app/globals.css. The entrance
 * cascade is the global .nari-fu classes, killed by the same sweep. Per the
 * repo's motion system, no per-component prefers-reduced-motion block exists
 * here: the html attribute is the single source of truth.
 */

.hero-section_hero__HoI7O {
  position: relative;
  overflow: hidden;
  isolation: isolate;
  background: var(--cream);
}

/* ── Scene + scrims (the control's structure, cream instead of navy) ─────── */

.hero-section_scene___DAfL {
  position: absolute;
  inset: 0;
  z-index: 0;
}

/* The panorama is 2400x736, an aspect of 3.26 against the control art's 1.67,
   so `cover` scales it by HEIGHT at every viewport that matters and crops the
   sides rather than the sky. The whole landscape survives at full height; what
   narrows is how much of its width you see. `center` keeps the crop symmetric
   about the middle of the artwork, and the scrims below carry legibility, so
   the art never has to be dimmed to make the copy readable. */
.hero-section_sceneImage__JsypK {
  object-fit: cover;
  object-position: center center;
}

/* Horizontal scrim: keeps the copy column legible over the landscape. Heavy at
   the left where the copy sits, thinning to the right where the session card
   brings its own opaque ground.
   LIGHTER THAN THE CONTROL'S, on purpose. The control sets cream text on a
   night forest and has to hold the ground down; this arm sets near-black text
   (#1B0F33) on a dawn sky, so the ground only has to stay LIGHT, which it
   already is. The first pass carried the control's weights unexamined, the two
   scrims compounded, and the panorama rendered as a faint tint on flat cream:
   the art paid for legibility it was not costing. Alphas below are the lowest
   that still measured over 4.5:1 on the rendered page at 1440, 900 and 390. */
.hero-section_scrimCopy__Wq3ml {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background: linear-gradient(
    100deg,
    rgba(245, 242, 235, 0.66) 0%,
    rgba(245, 242, 235, 0.48) 34%,
    rgba(245, 242, 235, 0.18) 62%,
    rgba(245, 242, 235, 0) 100%
  );
}

/* Vertical scrim: reaches solid cream at the floor so the section below seams
   with no edge, and lifts the top band a little where the art runs up behind
   the fixed nav. The nav paints its own solid chrome on this arm, so the top
   stop is a seam, not a legibility measure. */
.hero-section_scrimVertical__iGAxA {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background: linear-gradient(
    180deg,
    rgba(245, 242, 235, 0.8) 0%,
    rgba(245, 242, 235, 0.3) 12%,
    transparent 30%,
    transparent 58%,
    rgba(245, 242, 235, 0.22) 76%,
    rgba(245, 242, 235, 0.72) 92%,
    var(--cream) 100%
  );
}

/* ── Layout grid ─────────────────────────────────────────────────────────── */

/* THE CENTRING FIX, and the four declarations to keep in step with the
   control's .grid: the auto-fit template, the 48/56 gaps, `align-items:
   center`, and the nav-clearing top padding against a flat 64px bottom. The
   control's own values, not retuned: this arm had already proved it could not
   pick them by eye. The max-width and gutters are its .innerWide primitive,
   written out rather than composed, because the challenger modules stay
   independent of the control's shared sheet. */
.hero-section_grid__2Sh_T {
  position: relative;
  z-index: 2;
  max-width: 1180px;
  margin: 0 auto;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(340px, 100%), 1fr));
  gap: 48px 56px;
  align-items: center;
  padding: calc(var(--nav-height) + 44px) 32px 64px;
}

.hero-section_promise__CC56c {
  min-width: 0;
}

/* ── Left column: the promise ────────────────────────────────────────────── */

/* Near the artifact's own scale (it used 52). An earlier pass cut the ceiling
   to 46px purely to buy hero height, and at 1200px the h1 rendered 43px
   against a 16px lead, a ratio too slack to read as a headline. Height is no
   longer bought here: there is no art band left to trade against. */
/* Leading and wrapping, both retuned after the owner read it as hard to read.
   Measured first: at 1440 this is 50px in a 530px column over THREE lines, so
   the problem was never the size, it was that 1.08 leading on a 50px Lora line
   leaves about 4px between one line's descenders and the next line's
   ascenders. A single-line heading can carry 1.08; a three-line one cannot.
   1.15 is still tight for a display face and now has air between the lines.

   text-wrap: pretty, not balance. Balance equalises line LENGTHS, which on a
   narrow column means it will happily make an extra short line to keep them
   even, and every extra line costs a full leading step. Pretty only pulls
   orphans back, so lines run as full as the column allows. */
/* DOUBLED CLASS, and it is load-bearing. app/(public)/page.module.css carries
   `.page h1, .page h2, .page h3 { text-wrap: balance }`, which is a class plus
   an element (0,1,1) and therefore outranks a lone module class (0,1,0). A
   plain `.heading { text-wrap: pretty }` here computed as `balance` on the
   rendered page: the declaration was live in the stylesheet and simply lost
   the cascade. Verified by asking the browser which rules matched, not by
   reading either file. `.heading.heading` is (0,2,0) and wins, and it is the
   pattern this repo already uses to outrank design-system single-class rules.

   Every OTHER heading on this page asks for balance anyway, so this rule is
   the only one that was ever in conflict. */
.hero-section_heading__oY70U.hero-section_heading__oY70U {
  font-family: var(--font-heading);
  font-weight: 500;
  /* 48, not 50. Measured on the deployed page with the real Lora: at 50px the
     first sentence needed three lines in the 530px column and stranded its
     last word; at 48 it takes two. 46 also works, but 48 keeps the headline
     scale. Below about 1140px the vw term governs and the binding above is
     what protects the wrap, not this ceiling. */
  font-size: clamp(31px, 4.2vw, 48px);
  line-height: 1.15;
  letter-spacing: -0.02em;
  color: var(--light-head);
  margin: 0;
  text-wrap: pretty;
}

/* The turn, held together. See hero-section.tsx for why: free to wrap, it
   broke as "Not the / opposite." and left one word on the last line, which
   text-wrap: pretty does not prevent because the orphan was not the block's
   own last line problem, it was a break inside the second sentence.
   Unbreakable, the turn moves whole. At the mobile floor it is about 250px
   against a 350px column, so nowrap cannot cause an overflow. */
.hero-section_headingTurn__TJIcD {
  white-space: nowrap;
}

/* The owner read this line as barely visible, and it was: 13px mid-grey
   directly under a 50px heading is a 4x size drop, which reads as fine print
   rather than as the credential the sentence actually is. It cleared AA at
   6.41:1, so this is a PROMINENCE fix, not a contrast one, and the two are
   easy to confuse. 15px and the page's own body colour bring it back up to
   supporting-text weight; the contrast improves as a side effect.

   Not --light-mute (#6b6560): the scrim thins the cream ground under this
   column to a composite rather than the flat token, and that token measured
   under 4.5:1 against it. */
/* The intro pair. Opened by the short gold rule the coach lane cards already
   use, so the group is marked with an existing Nari motif rather than a new
   one, and horizontally, which keeps it out of the way of the vertical rail on
   the steps below. The rule is DECORATION: it separates, it never carries
   meaning, so its 1.7:1 against the cream is not an AA question. */
.hero-section_intro__6J6kX {
  margin: 26px 0 0;
}

.hero-section_intro__6J6kX::before {
  content: "";
  display: block;
  width: 28px;
  height: 2px;
  margin-bottom: 16px;
  border-radius: 1px;
  background: var(--gold);
}

/* The credential. A tier DOWN from the promise under it, and the tier comes
   from SIZE ONLY: 14 against 17.

   The colour deliberately does NOT move. This line was already reported as
   barely visible once, and the fix then was to bring it UP to the body colour;
   that was a prominence problem, not a contrast one. Taking it back down to a
   quieter literal to manufacture hierarchy would re-create the exact complaint
   from the other direction, so the hierarchy is bought with size and with the
   weight of the promise below, never by dimming this. The test pins the
   colour. */
.hero-section_credibility__11OUS {
  font-size: 14px;
  line-height: 1.6;
  color: #3c3a35;
  margin: 0;
}

/* The lead names three things, and each is set bold so they read as a list
   inside the sentence rather than as one long emphasised run. A literal rather
   than the mute token, for the same reason .credibility uses one: the mute
   token does not survive the scrim over the panorama. */
/* The promise, and the tier the eye should land on after the h1. Larger and
   darker than the credential above it; 10px of space between them, against 26
   either side of the pair, so the two read as one block. */
.hero-section_journey__c8IL5 {
  font-size: 17px;
  line-height: 1.6;
  color: #3c3a35;
  max-width: 560px;
  margin: 10px 0 0;
}

.hero-section_journeyStrong__3mLcy {
  /* 500, not bold: DM Sans loads 300/500 here, and 700 would synthesise a faux
     bold rather than pick a real weight. */
  font-weight: 500;
  color: var(--light-head);
}

/* The journey as a rail. The ORDER is the meaning, these are the stages of a
   search in the sequence they happen, so the dots read as progress and the
   hairline makes the six one path rather than six tags. */
.hero-section_steps__2WxRo {
  position: relative;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 12px;
  max-width: 560px;
  /* 26, matching the space above the intro pair: the steps are their own tier,
     and the pair must not look closer to the list than to itself. */
  margin: 26px 0 0;
  padding: 0;
}

.hero-section_step__CNmcK {
  position: relative;
  padding-left: 24px;
  font-size: 15px;
  line-height: 1.5;
  color: var(--light-head);
}

/* The connector, anchored top AND bottom rather than given a fixed height.
   A height is correct only while every step is one line: the moment one wraps,
   and the long ones do on a narrow column, a fixed rail stops short and the
   path visibly breaks. Anchored, it always spans dot to dot. */
.hero-section_step__CNmcK:not(:last-child)::after {
  content: "";
  position: absolute;
  left: 4px;
  top: 15px;
  bottom: -17px;
  width: 1px;
  background: rgba(221, 184, 74, 0.5);
}

/* The dot. Gold on cream is 2.1:1, which is why it is DECORATION and never the
   only carrier of meaning: each step's text stands on its own. */
.hero-section_step__CNmcK::before {
  content: "";
  position: absolute;
  box-sizing: border-box;
  left: 0;
  top: 5px;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--gold);
}

/* The last step ends "and beyond", so its marker is OPEN: a ring, with no rail
   continuing past it. The one place the structure repeats what the words
   already say, which is the only reason it earns the exception. */
.hero-section_stepOpen__HGFzW::before {
  background: transparent;
  border: 2px solid var(--gold);
}

.hero-section_ctaRow__Gzdu_ {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 14px;
  margin-top: 20px;
}

/* Buttons are DM Sans 500: family inherited, weight declared. */
.hero-section_primaryCta__LPa3E {
  display: inline-block;
  font-size: 15.5px;
  font-weight: 500;
  color: var(--cream);
  background: var(--light-head);
  border-radius: 999px;
  padding: 14px 28px;
  text-decoration: none;
  transition: background-color 160ms ease;
}

.hero-section_primaryCta__LPa3E:hover {
  background: var(--green-dark);
}

.hero-section_primaryCta__LPa3E:focus-visible {
  outline: 2px solid var(--light-head);
  outline-offset: 3px;
}

/* The secondary CTA is a LINK now, not the lightbox trigger, so it carries
   inline-flex and the anchor reset rather than a button reset. */
.hero-section_watchCta__oVp7z {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 15.5px;
  font-weight: 500;
  color: var(--light-head);
  background: rgba(255, 253, 248, 0.5);
  border: 1.5px solid rgba(27, 15, 51, 0.35);
  border-radius: 999px;
  padding: 13px 26px;
  text-decoration: none;
  cursor: pointer;
  transition: border-color 160ms ease, background-color 160ms ease;
}

.hero-section_watchCta__oVp7z:hover {
  border-color: var(--light-head);
  background: rgba(255, 253, 248, 0.85);
}

.hero-section_watchCta__oVp7z:focus-visible {
  outline: 2px solid var(--light-head);
  outline-offset: 3px;
}

/* Last line of the promise column since the mission line was dropped. */
.hero-section_priceRow__r6Gcx {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.06em;
  /* Same reason as .credibility: the mute token does not survive the scrim. */
  color: #55524c;
  margin: 10px 0 0;
}

.hero-section_cardColumn__zB9xz {
  min-width: 0;
  width: 100%;
  justify-self: end;
  max-width: 460px;
}

@media (max-width: 900px) {
  .hero-section_grid__2Sh_T {
    padding: calc(var(--nav-height) + 28px) 20px 48px;
    gap: 28px;
  }

  /* Stacked, the two CTAs wrap onto two rows, so this gap is vertical too and
     is paid twice over. Button padding is untouched: the primary is 50px tall
     and the secondary 52px, both clear of the 44px touch-target minimum. */
  .hero-section_ctaRow__Gzdu_ {
    gap: 10px;
    margin-top: 18px;
  }

  .hero-section_cardColumn__zB9xz {
    justify-self: stretch;
    max-width: none;
  }
}

/*
 * Challenger mirror ("Doing it alone"), rebuilt to the extracted design
 * spec: one centered column on the deep cream ground. Stack order is
 * eyebrow, heading, lead, chip row, closer, with the spec's own margins
 * carrying the rhythm (no flex gap).
 *
 * Color mapping: the artifact's #ede9e0 ground is exactly --cream-dark, so
 * the token wins. The #3c3a35 text ink and the rgba(27,15,51,.22) chip
 * border have no token equivalent and stay artifact literals per the
 * challenger mapping rules. Px sizes come from the spec literally, matching
 * the control's convention.
 *
 * Body text (lead, closer) inherits DM Sans 300 from the page, so those
 * rules set only size, rhythm, and ink, never font-family.
 *
 * Fully static section: no interactive elements, so no focus styles live
 * here. No decorative art either.
 */

.mirror-section_mirror__ZV9Vn {
  /* spec #ede9e0, exact token match */
  background: var(--cream-dark);
  padding: 88px 0;
  /* Anchor target for the nav's /#why. Without it a hash jump lands the
     eyebrow under the fixed nav, and under the webinar banner too when one
     is live (review measured 28px of the eyebrow obscured). Same allowance
     as landing-shared's .anchor, which every control anchor composes. */
  scroll-margin-top: calc(var(--nav-height) + var(--space-6));
}

/* Gutters are the page-wide standard, var(--space-7) stepping to
 * var(--space-5) under 900px, so every challenger section shares one left
 * edge. The 820px cap is the artifact's own for this narrow column, so it
 * stays instead of the shared 1120px. */
.mirror-section_inner__6d2KK {
  max-width: 820px;
  margin: 0 auto;
  padding: 0 var(--space-7);
  /* The centered column IS the redesign; the old left-aligned layout was
   * the rejected bug. */
  text-align: center;
}

/* Wood-oak is the declared AA substitute for the artifact's #b98a1f, which
 * fails the 4.5:1 floor on light grounds. */
.mirror-section_eyebrow__dYR4v {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--wood-oak);
  /* The artifact's global body line-height; nari-web declares none, so a
   * rule that omits it falls to normal (about 1.25) and the label loses
   * height against the eyebrows in the other sections. */
  line-height: 1.6;
  margin: 0 0 16px;
}

.mirror-section_heading__39eqC {
  font-family: var(--font-heading);
  /* Lora loads 400 and 500 only; 600 would synthesize. */
  font-weight: 500;
  font-size: clamp(26px, 3.6vw, 38px);
  line-height: 1.2;
  color: var(--light-head);
  margin: 0;
  text-wrap: balance;
}

.mirror-section_lead__1UKMh {
  font-size: 15.5px;
  line-height: 1.65;
  color: #3c3a35;
  margin: 14px 0 0;
}

/* The five within-reach fragments flow as one centered wrapping row; list
 * semantics live in the markup so the count is announced. */
.mirror-section_chips__v7E3v {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 8px;
  margin: 24px 0 0;
  padding: 0;
}

.mirror-section_chip__7INHV {
  font-family: var(--font-mono);
  font-size: 11.5px;
  /* Same reason as the eyebrow: without this the chip renders about 4px
   * shorter than the identical chip in the engine loop row. */
  line-height: 1.6;
  color: #3c3a35;
  border: 1px solid rgba(27, 15, 51, 0.22);
  border-radius: 999px;
  padding: 6px 12px;
  white-space: nowrap;
}

.mirror-section_closer__SB3hc {
  font-size: 15px;
  line-height: 1.7;
  color: #3c3a35;
  max-width: 620px;
  margin: 26px auto 0;
}

@media (max-width: 900px) {
  /* The shared mobile gutter. Section padding deliberately does NOT step
   * here: no challenger section steps its vertical padding, so the page
   * keeps one rhythm down the scroll. */
  .mirror-section_inner__6d2KK {
    padding: 0 var(--space-5);
  }

  /* The longest chip outgrows the narrowest viewports (roughly 345px and
   * down at 11.5px mono plus padding), and nothing may overflow the
   * viewport horizontally. Letting chip text wrap under the mobile
   * breakpoint keeps that guarantee; on wider screens the rule is inert,
   * because a chip only wraps once it exceeds the row width. */
  .mirror-section_chip__7INHV {
    white-space: normal;
  }
}

/*
 * Moments ("03 The moments"): the dark section, rebuilt to the artifact in
 * the design-fidelity pass.
 *
 * Ground: var(--light-head). The artifact's #1B0F33 is exactly the
 * --light-head token value, and the fidelity spec's rule is that an exact
 * token match wins, so the ground is the token (declared choice; the old
 * port's --midnight ground is retired). Gold carries the mono labels and the
 * selected state, cream carries headings and body copy.
 *
 * The rail: one scrolling canvas whose CSS aspect-ratio equals the SVG
 * viewBox ratio (both derive from moments-geometry.ts RAIL_VB, which reaches
 * this sheet as the --rail-aspect-ratio custom property). The SVG is
 * decoration; the tab capsules are HTML buttons absolutely positioned by
 * percentage of the same box, out of the --tab-x/--tab-y/--tab-w/--tab-h
 * properties the same module emits. The canvas is a size container so pill
 * type tracks the rail width via cqw.
 *
 * Below 900px that whole arrangement is dropped and the SAME seven buttons
 * become a vertical journey; see THE MOBILE JOURNEY at the end of this file.
 * Custom properties are what lets one tablist serve both layouts: a direct
 * inline left/top/width cannot be media-queried away, an unread custom
 * property costs nothing.
 *
 * The detail card is the artifact's BRIGHT CREAM object sitting on the
 * midnight ground: it is the focal element of the section, not a translucent
 * inset panel. Every ink inside it is therefore chosen against #fffdf8 (or
 * against the moss sub-panel's #f3f4e9), not against the dark ground.
 *
 * Declared AA substitutions, each computed against its own ground:
 *   - card when-label: the artifact's #b98a1f is 2.51:1 on #fffdf8 and fails.
 *     var(--wood-oak) (#7a5c3a) is 6.04:1. Same warm-oak read, AA clear.
 *   - fit label: the artifact's #64822C is 3.97:1 on the moss #f3f4e9 and
 *     fails. var(--green-dark) (#2d4a32) is 8.86:1.
 *   - stepper hover/focus ink: var(--gold) is 1.87:1 on the card, below the
 *     3:1 that WCAG 2.1 asks of a focus indicator, so the card's steppers use
 *     var(--light-head) (17.8:1) where the dark-ground controls use gold.
 * The quote keeps the artifact's #2d4a32 exactly (var(--green-dark), 9.67:1
 * on the card); the old cream-leaning substitution existed only because the
 * card used to be dark.
 */

.moments-section_section__sojo7 {
  background: var(--light-head);
  padding: 88px 0 96px;
}

.moments-section_inner__dqJxC {
  max-width: 1120px;
  margin: 0 auto;
  padding: 0 var(--space-7);
  display: flex;
  flex-direction: column;
  gap: var(--space-8);
}

/* Top: copy left, illustration right; collapses below ~900px with the
 * illustration under the copy (source order). */
.moments-section_topGrid__kaFNr {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 540px);
  gap: var(--space-8);
  align-items: center;
}

.moments-section_copyColumn__pixkz {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}

.moments-section_eyebrow___izHL {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--gold);
  margin: 0;
}

.moments-section_heading__buTuO {
  font-family: var(--font-heading);
  font-weight: 500;
  font-size: clamp(26px, 3.6vw, 38px);
  line-height: 1.2;
  color: var(--cream);
  margin: 0;
  text-wrap: balance;
}

.moments-section_lead__YUHYT {
  font-size: 15.5px;
  line-height: 1.7;
  color: var(--cream);
  max-width: 560px;
  margin: 0;
}

/* The panda illustration in its dashed gold frame (intentional design).
 *
 * The frame is always here and always keeps the artifact's 540x310 box; only
 * the PICTURE is conditional, and it arrives as a background-image declared
 * in the min-width block at the end of this file. It used to be a next/image
 * whose frame the mobile block hid with display:none, which hid the picture
 * but not the download: a browser fetches an img inside a display:none
 * subtree all the same, and the sizes attribute made a phone choose the
 * widest candidate, so the device the rule existed to help paid the most
 * bytes for a picture it never saw. A background-image behind min-width is
 * never even requested there, and it is how the hero and close sections
 * already carry their art. */
.moments-section_illustrationFrame__BWY_k {
  width: 100%;
  max-width: 540px;
  aspect-ratio: 540 / 310;
  border-radius: 14px;
  border: 1.5px dashed rgba(221, 184, 74, 0.7);
  background-color: rgba(245, 240, 234, 0.92);
  overflow: hidden;
}

.moments-section_timeline__Z2UmT {
  min-width: 0;
}

.moments-section_timelineRoot__vkXEm {
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
}

/* The rail scroller: the artifact's sideways scroll on narrow screens. */
.moments-section_scroller__DndFR {
  overflow-x: auto;
}

/* One coordinate space for the SVG and the HTML capsules. The aspect-ratio
 * value is --rail-aspect-ratio, emitted from moments-geometry.ts, so it
 * cannot drift from the viewBox and the mobile block can drop it. */
.moments-section_canvas__e4JQv {
  position: relative;
  min-width: 780px;
  width: 100%;
  aspect-ratio: var(--rail-aspect-ratio);
  container-type: inline-size;
}

.moments-section_rail__inbWa {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}

/* ── Functional motion on the rail ─────────────────────────────────────────
 * Four movements, all of them carrying meaning the static drawing cannot:
 * the lap closing, the journey being drawn, which way you just moved along
 * it, and the fact that the card under it is now a different moment.
 *
 * KILL SWITCH, for all four. globals.css sweeps
 * `html[data-motion="static"] *` (plus ::before/::after) with
 * animation-duration: 0.01ms, animation-iteration-count: 1,
 * transition-duration: 0.01ms, and animation-timeline: auto, every one
 * !important. Everything below is a plain CSS animation or transition on an
 * element inside <html>, so that descendant sweep reaches all of it. Nothing
 * here uses SMIL (<animate>), which the sweep could NOT reach, and nothing
 * here uses a component-level prefers-reduced-motion query, which is the
 * documented anti-pattern in this repo (it would override an explicit
 * "Animated" choice). moments-section.test.tsx pins both facts.
 */

/* A. THE RETURN EDGE MARCHES, from the stall back to Day zero.
 *
 * Direction, worked out from the path's coordinate order: RETURN_D is
 * "M1090,92 ... 86,108", so it STARTS at the stall node and ENDS at the
 * arrowhead beside Day zero; path distance s therefore grows toward the
 * arrow. With dasharray "6 6" a dash is painted where (s + offset) mod 12
 * lands in [0, 6), so a RISING offset slides the dashes toward s = 0, which
 * is backwards, toward the stall. The offset therefore FALLS, 0 to -12,
 * which carries every dash forward along the path in the arrowhead's
 * direction. 12 is one whole dash + gap period, so the loop is seamless.
 *
 * Slow and calm: 1.6s linear, in the 1.2s to 2s band. Infinite, and stopped
 * dead in Static mode by the sweep's animation-iteration-count: 1 (the
 * duration override alone would only have made it spin faster).
 *
 * WCAG 2.2.2 (Pause, Stop, Hide) applies, because this is automatic motion
 * that runs past five seconds beside other content. The mechanism it asks
 * for already exists and is on this page: the Motion control in the public
 * nav (components/public-nav/motion-toggle.tsx), whose "Static" setting is
 * what stamps html[data-motion="static"] and stops this. Every mobile
 * visitor is force-resolved to static and never sees it move at all.
 */
.moments-section_returnEdge__IMHCP {
  animation: moments-section_momentsReturnMarch__VmPD3 1.6s linear infinite;
}

@keyframes moments-section_momentsReturnMarch__VmPD3 {
  from {
    stroke-dashoffset: 0;
  }
  to {
    stroke-dashoffset: -12;
  }
}

/* B. THE CURVE DRAWS ITSELF, once, on first sight.
 *
 * The armed state (stroke-dasharray and stroke-dashoffset both set to the
 * path's OWN length, measured at runtime with getTotalLength so editing
 * CURVE_D cannot silently break it) deliberately carries NO transition:
 * arming must not animate the line away. The transition arrives together
 * with data-draw="in", in the same style change as the offset dropping to 0,
 * which is exactly when a transition starts.
 */
.moments-section_curve__n9qiA[data-draw="in"] {
  transition: stroke-dashoffset 1600ms cubic-bezier(0.2, 0.65, 0.25, 1);
}

/* C. THE SELECTION RING SLIDES between nodes.
 *
 * The ring is a circle at 0,0 inside this group, and the group is moved by a
 * CSS transform. cx/cy are SVG geometry properties whose CSS transitions are
 * uneven across engines; a transform on a wrapping <g> is solid everywhere,
 * and it composites rather than reflowing. The element persists across
 * selections (React keeps the same <g>), which is what lets it travel
 * instead of teleport, so the reader SEES which way along the journey they
 * just moved.
 */
.moments-section_ringGroup__A_YFH {
  transition: transform 260ms cubic-bezier(0.2, 0.65, 0.25, 1);
}

.moments-section_tabs__wjCI4 {
  position: absolute;
  inset: 0;
}

/* The capsule tabs, placed by the four percentage custom properties the
 * geometry module puts on each button. */
.moments-section_tab__Qtil_ {
  position: absolute;
  left: var(--tab-x);
  top: var(--tab-y);
  width: var(--tab-w);
  height: var(--tab-h);
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 999px;
  background: rgba(245, 242, 235, 0.07);
  border: 1px solid rgba(245, 242, 235, 0.3);
  color: #f5f0ea;
  font-family: inherit;
  font-weight: 400;
  font-size: clamp(9px, 1.125cqw, 13.5px);
  line-height: 1;
  white-space: nowrap;
  padding: 0;
  cursor: pointer;
  transition: border-color 160ms ease, background-color 160ms ease;
  /* The public layout puts a blanket min-height:44px on every button under
     768px. These pills are positioned by PERCENTAGE of the rail canvas, so a
     px floor detaches them from the geometry: measured, they became 44px
     blobs swallowing the nodes and pushed every below-node when-label off the
     canvas. The 44px target is still met, by the ::before hit expansion
     below, which grows the touch area without moving the box. */
  min-height: 0;
}

/* Hit expansion: keeps the small capsules in the 44px class at min-width. */
.moments-section_tab__Qtil_::before {
  content: "";
  position: absolute;
  inset: -14px -8px;
}

.moments-section_tab__Qtil_:hover {
  border-color: var(--gold);
  background: rgba(221, 184, 74, 0.16);
}

.moments-section_tab__Qtil_[aria-selected="true"] {
  border-color: var(--gold);
}

.moments-section_tab__Qtil_:focus-visible {
  outline: 2px solid var(--gold);
  outline-offset: 2px;
}

/* The when label rides with its pill (mod 55): above for dayzero and stall,
 * below for the rest. The verdict when clears the return edge by ~5px,
 * accepted by the owner; the path stays put. */
/* The HALO is the fix for the owner's "lines are overlapped". The tab pills
   carry a background, so the curve behind them is occluded cleanly; these
   when-labels do not, so the rail's stroke ran straight through the glyphs at
   several nodes. A halo in the section's own ground colour cuts the line out
   from behind the text without drawing a chip around it, and it holds wherever
   the curve happens to pass, which a hand-placed offset would not: the rail is
   a bezier and the labels are positioned per node.

   Four shadows, not one, because a single offset shadow only masks one side
   and the stroke crosses these at every angle. */
.moments-section_tabWhen__3MiGT {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  white-space: nowrap;
  font-family: var(--font-mono);
  text-transform: uppercase;
  letter-spacing: 0.12em;
  font-size: clamp(9px, 0.833cqw, 10px);
  color: var(--gold);
  text-shadow: 0 0 4px var(--light-head), 0 0 4px var(--light-head),
    0 0 3px var(--light-head), 0 0 2px var(--light-head);
}

.moments-section_whenAbove__bFm4L .moments-section_tabWhen__3MiGT {
  bottom: calc(100% + 4px);
}

.moments-section_whenBelow__wyn5w .moments-section_tabWhen__3MiGT {
  top: calc(100% + 4px);
}

.moments-section_caption__61sL1 {
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.1em;
  color: var(--gold);
  text-align: center;
  margin: 0;
}

/* The swipe hint is gone, with its copy constant: below 900px the moments are
 * a vertical column now, so "Swipe to see the whole line" described an
 * interface that no longer exists, and it only ever rendered on mobile. */

/* The tabpanel is a plain column; each card carries its own surface so the
 * Day zero return card (mod 56) reads as a second card, not a longer one. */
/* The artifact centers the card stack under the rail at max-width 820px.
   The panel is a flex ITEM of .timelineRoot (a column flex container at the
   default align-items:stretch), so a bare max-width left it flush left under
   the 1056px rail. align-self:center takes it out of stretch and centers it;
   width:100% keeps it filling the rail up to the 820px cap. Its top offset
   comes from the .timelineRoot gap, so no margin-top is restated here. */
.moments-section_panel__JyNxP {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  align-self: center;
  width: 100%;
  max-width: 820px;
}

.moments-section_panel__JyNxP:focus-visible {
  outline: 2px solid var(--gold);
  outline-offset: 2px;
  border-radius: 12px;
}

/* The artifact's card: bright cream on the midnight ground. Block flow, not
   a flex column, so the artifact's per-element margins (14px above the moss
   panel, 9px above the tag) land exactly instead of stacking onto a gap. */
.moments-section_card__jiyLs {
  background: #fffdf8;
  border: 1px solid rgba(45, 74, 50, 0.15);
  border-radius: 16px;
  padding: 22px 26px;
}

/* D. THE CARD FADES IN on a moment change, so a stepper click or a tab click
 * reads as a change of moment rather than a repaint of the same box.
 *
 * It rides on the two regions that actually change (the when label and the
 * body block), NOT on the whole card, so the prev/next steppers in the
 * header are never torn down: focus stays exactly where the pinned
 * stepper-focus behaviour puts it. Nothing is delayed either, the new copy
 * is in the DOM and readable from frame one; only its opacity settles, from
 * 0.4 to 1 over 180ms. That floor is deliberate: the page's own scroll
 * reveals start at 0, and starting from 0.4 keeps the swapped text legible
 * through the whole 180ms instead of blinking out.
 *
 * Contrast, computed for the transient state: the card's darkest ink,
 * var(--light-head) #1B0F33, sits at 17.8:1 on the #fffdf8 card. Composited
 * at 40% over that same card it is #A39EA9-ish (163.8, 157.8, 169.2), which
 * is 2.57:1 for at most 180ms before it settles back to 17.8:1. WCAG 1.4.3
 * is about the text as presented at rest, and this repo's own .nari-reveal
 * entrance starts at opacity 0 (1:1); 0.4 is the more conservative floor of
 * the two, and it is why the fade does not start lower.
 *
 * Opacity and nothing else, so no layout is touched. Killed in Static mode
 * by the same sweep (0.01ms duration, one iteration, fill both leaves it at
 * opacity 1).
 */
.moments-section_swap___3lMR {
  animation: moments-section_momentsSwapIn__tVfsg 180ms cubic-bezier(0.2, 0.65, 0.25, 1) both;
}

@keyframes moments-section_momentsSwapIn__tVfsg {
  from {
    opacity: 0.4;
  }
  to {
    opacity: 1;
  }
}

.moments-section_cardHeader__SsNbg {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  margin-bottom: 10px;
}

/* AA substitution, see the file header: the artifact's #b98a1f is 2.51:1 on
   the #fffdf8 card. --wood-oak is 6.04:1. Gold was only ever right while the
   card was dark. */
.moments-section_cardWhen__TtBfw {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--wood-oak);
  margin: 0;
}

.moments-section_cardNav__yj_iE {
  display: flex;
  gap: var(--space-2);
}

.moments-section_navButton__8WfJJ {
  width: 44px;
  height: 44px;
  border-radius: 999px;
  border: 1px solid rgba(27, 15, 51, 0.3);
  background: transparent;
  color: var(--light-head);
  font-family: inherit;
  font-size: 18px;
  line-height: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: border-color 160ms ease;
}

/* Gold is 1.87:1 on the cream card, under the 3:1 WCAG 2.1 asks of a focus
   indicator, so these two states use the card's own dark ink instead. */
.moments-section_navButton__8WfJJ:hover {
  border-color: var(--light-head);
}

.moments-section_navButton__8WfJJ:focus-visible {
  outline: 2px solid var(--light-head);
  outline-offset: 2px;
}

.moments-section_cardTitle__8XWQ3 {
  font-family: var(--font-heading);
  font-weight: 500;
  font-size: 21px;
  color: var(--light-head);
  margin: 0 0 10px;
  text-wrap: balance;
}

/* No rule down the side: the artifact's quote is unruled, the port's
   border-left was an addition. */
.moments-section_quote__S9vyC {
  margin: 0;
}

.moments-section_quote__S9vyC p {
  font-family: var(--font-heading);
  font-style: italic;
  font-weight: 400;
  font-size: 18px;
  line-height: 1.45;
  color: var(--green-dark);
  margin: 0;
}

/* The artifact wraps the quote in curly quotation marks. They live here, not
   in challenger-copy.ts, so the constant stays the member's plain words. */
.moments-section_quote__S9vyC p::before {
  content: "\201C";
}

.moments-section_quote__S9vyC p::after {
  content: "\201D";
}

/* The moss sub-panel: the artifact's container around the fit block. */
.moments-section_fitPanel__gTLU9 {
  background: #f3f4e9;
  border: 1px solid rgba(100, 129, 44, 0.35);
  border-radius: 10px;
  padding: 12px 14px;
  margin-top: 14px;
}

/* AA substitution, see the file header: the artifact's #64822C label ink is
   3.97:1 on the moss ground and fails; --green-dark is 8.86:1. */
.moments-section_fitLabel__Pb3dh {
  font-family: var(--font-mono);
  font-size: 9px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--green-dark);
  margin: 0 0 8px;
}

.moments-section_fitList__eHP2p {
  list-style: none;
  margin: 0;
  padding: 0;
}

.moments-section_fitLine__CthVS {
  font-size: 13.5px;
  line-height: 1.6;
  color: #3c3a35;
  border-left: 2px solid var(--green);
  padding-left: 11px;
  margin-bottom: 7px;
}

.moments-section_fitLine__CthVS:last-child {
  margin-bottom: 0;
}

.moments-section_tag__EhnO8 {
  font-family: var(--font-mono);
  font-size: 9px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--wood-oak);
  margin: 9px 0 0;
}

@media (max-width: 900px) {
  .moments-section_inner__dqJxC {
    padding: 0 var(--space-5);
    gap: var(--space-7);
  }

  .moments-section_topGrid__kaFNr {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-6);
  }

  /* Narrow screens trim the card gutters only; the type sizes and the moss
     panel are unchanged, and nothing here carries a fixed width, so the card
     still fits inside a 320px viewport. */
  .moments-section_card__jiyLs {
    padding: 18px 16px;
  }

  /* THE ILLUSTRATION IS HIDDEN, mobile only.
   *
   * On desktop it sits in the right column of the two-column top grid and
   * costs no vertical space at all. Stacked under the copy on a phone it cost
   * about 330px of scroll, plus the grid gap under it, for decoration. It is
   * decorative (empty alt, aria-hidden), so display:none removes nothing a
   * reader or a screen reader ever had; the element, the asset and the whole
   * desktop rendering are untouched. A display:none grid item generates no
   * box, so the second grid row and its gap go with it. */
  .moments-section_illustrationFrame__BWY_k {
    display: none;
  }

  /* ── THE MOBILE JOURNEY ──────────────────────────────────────────────────
   * The winding rail does not survive a 390px screen: it is a 780px-minimum
   * canvas inside a sideways scroller, so four of the seven moments sat off
   * screen, the pills were sliced mid-word at the viewport edge, and the
   * when-labels landed on the dashed return edge. Below 900px the same seven
   * moments become a vertical journey instead: a spine down the left, one row
   * per moment, and the lap closed by a dashed return edge that leaves the
   * last node, runs back up the gutter and arrives in the first node. It is
   * drawn closed, not animated closed; see THE RETURN LOOP below.
   *
   * ONE TABLIST. Every rule below re-lays out the SAME seven buttons the
   * desktop rail uses. Nothing is duplicated into a second tablist, which
   * would put fourteen tabs in the accessibility tree and two of every
   * data-element-id in the analytics stream. That is possible because the
   * geometry arrives as custom properties (--tab-x and friends), which these
   * rules simply do not read.
   *
   * The gutter, in one place so the pieces cannot drift:
   *   x = 10px  the return's vertical run (2px wide, so it covers 9 to 11)
   *   x = 26px  the spine, the node dots, and the arrowhead's centre
   *   x = 44px  where the label starts
   * The rows are honest 44px+ touch targets: real height from real padding,
   * not the ::before hit expansion the desktop capsules need (those are sized
   * as a percentage of the rail canvas, so a px floor would detach them from
   * the geometry). The desktop ::before is repurposed here as the node dot.
   */

  /* Nothing scrolls sideways any more: no scroller, no min-width canvas, and
     no rail aspect-ratio, so the column is exactly as tall as its rows. */
  .moments-section_scroller__DndFR {
    overflow: visible;
  }

  .moments-section_canvas__e4JQv {
    min-width: 0;
    aspect-ratio: auto;
  }

  /* The winding SVG (curve, return edge, arrowhead, nodes, ring) is desktop
     only. It is decoration, so hiding it removes nothing from the reader. */
  .moments-section_rail__inbWa {
    display: none;
  }

  .moments-section_tabs__wjCI4 {
    position: relative;
    inset: auto;
    display: flex;
    flex-direction: column;
  }

  /* ── THE RETURN LOOP, A CLOSED FIGURE DRAWN FROM GEOMETRY ALONE ──────────
   *
   * WHY GEOMETRY AND NOT MOTION. The previous build drew the return as a
   * lone dashed column at x=7 while the spine and every node dot sat at
   * x=26: a second parallel line 19px away from the journey, touching no
   * node at either end, with an arrowhead aimed into the empty gutter. It
   * relied on the marching dashes to be read as a return, and that reading
   * is never available on the device this layout is FOR:
   * lib/motion-preference.tsx force-resolves "(hover: none) and (pointer:
   * coarse)" to "static", and globals.css then stops every animation dead
   * with animation-iteration-count: 1. On a phone these dashes DO NOT MOVE.
   * So the lap now closes as a drawn figure, and the march is a bonus for
   * the pointer devices narrow enough to see this layout at all.
   *
   * THE FIGURE. Four straight runs and an arrowhead, in the 44px gutter to
   * the left of the labels:
   *      spine        x=26, from the FIRST dot (y=22) down to the column's
   *                   bottom edge, passing through all seven dots
   *      bottom run   y=bottom, from the spine across to the return column
   *      vertical run x=10, from the bottom edge back up to y=8
   *      top run      y=8, from the return column across to x=26
   *      arrowhead    x=26, pointing DOWN, its tip inside the first dot
   * Every join is an OVERLAP, not a butt joint: each horizontal run spans
   * x=9 to x=27, which is the full 2px width of both columns it connects,
   * and its dash phase (6 on, 6 off over an 18px run) puts a painted dash at
   * both ends, so the two corners are always painted. The arrowhead's base
   * sits exactly where the top run ends and its tip reaches 2px into the
   * first dot, so the return does not stop beside the node, it arrives in it.
   *
   * WHERE THE BOTTOM TURN SITS, and why it is not on the last dot itself.
   * A row's height is its content's: a label that wraps to two lines makes a
   * taller row, so the distance from the LAST dot down to the column's bottom
   * edge is not a number this sheet can know. The turn is therefore placed on
   * the one bottom edge that is knowable, and the SPINE carries the reader
   * the short way from the last dot into it. That is a join, not a gap: the
   * spine is the journey line the seven dots sit on, so the eye leaves the
   * last node along the line it has been following all the way down, turns,
   * and comes back up. The alternative, anchoring the turn to the last dot,
   * would need the row's height measured in JS and written back as a custom
   * property, which is a resize-observer and a layout read for two pixels of
   * tidiness.
   *
   * WHY MULTIPLE BACKGROUND LAYERS RATHER THAN ONE STRETCHED SVG. Seven rows
   * have no fixed height (labels wrap), so the column's height is unknown at
   * authoring time. A background tile with an ABSOLUTE 12px period does not
   * scale with its box, so every dash is 6px on and 6px off whatever the
   * column ends up being. A stretched SVG would need preserveAspectRatio
   * "none", which squashes the dash pattern by the box-to-viewBox ratio
   * unless vector-effect: non-scaling-stroke rescues it, and it would stretch
   * the corner arcs as well. The one thing a background cannot do is turn a
   * corner, which is exactly why each run gets its own element box: the box
   * is what fixes a run's extent, so background-position can march the
   * pattern inside it without the run itself moving.
   *
   * FOUR DECORATION BOXES, none of which may swallow a tap (a hit on a
   * pseudo-element counts for its originating element, so an un-disabled
   * gutter decoration would put dead spots over the rows):
   *   .tabs::before    the spine and the vertical run
   *   .tabs::after     the bottom run  (same element as the spine, so the
   *                    bottom corner cannot drift)
   *   .canvas::before  the top run
   *   .canvas::after   the arrowhead   (last in tree order, so it paints
   *                    over the dot's ground-coloured halo)
   * .canvas has no padding, no border and one in-flow child, so its padding
   * box and the tablist's box are the same rectangle.
   *
   * Contrast, WCAG 1.4.11 (3:1 for meaningful graphics), both against the
   * section ground var(--light-head) #1B0F33:
   *   - every dash and the arrowhead, var(--gold) #ddb84a, 9.49:1
   *   - spine, cream at 40% (composites to #726979-ish), 3.47:1. Cream at the
   *     28% the desktop rail uses would have been 2.32:1 and failed here,
   *     where the spine is the structure of the whole layout.
   * No new colour pair: the loop is drawn in the two inks the column already
   * used. */

  /* The spine and the return's vertical run.
   *
   * The box runs from y=7 (the top of the top run) to the column's bottom
   * edge, so both of this element's layers are placed off known edges.
   *   layer 1, the spine: a flat 2px cream column at x=25 to 27, starting
   *     15px into the box, which is the FIRST dot's own centre at y=22, and
   *     ending at the box's bottom edge where the bottom run picks it up.
   *   layer 2, the vertical run: a 2px gold column at x=9 to 11 carrying a
   *     6px-on 6px-off tile that repeats down the whole box. Its period is
   *     12px ABSOLUTE, never a percentage, so the column's unknown height
   *     cannot stretch a single dash. */
  .moments-section_tabs__wjCI4::before {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    top: 7px;
    bottom: 0;
    background-image: linear-gradient(
        to bottom,
        rgba(245, 240, 234, 0.4) 0 100%
      ),
      linear-gradient(to bottom, var(--gold) 0 6px, transparent 6px 12px);
    background-size: 2px calc(100% - 15px), 2px 12px;
    background-repeat: no-repeat, repeat-y;
    background-position: 25px 15px, 9px 0;
    animation: moments-section_momentsMobileReturnMarch__WpNkX 1.6s linear infinite;
    pointer-events: none;
  }

  /* The bottom run: out of the spine, across to the return column. It shares
     .tabs with the spine above, so the corner the two make at the bottom of
     the column cannot drift apart. Its own box is 18px wide, which is the
     whole distance from the outer edge of one column to the outer edge of
     the other, so both corners are covered rather than approached. */
  .moments-section_tabs__wjCI4::after {
    content: "";
    position: absolute;
    left: 9px;
    bottom: 0;
    width: 18px;
    height: 2px;
    background-image: linear-gradient(
      to right,
      var(--gold) 0 6px,
      transparent 6px 12px
    );
    background-size: 12px 2px;
    background-repeat: repeat-x;
    animation: moments-section_momentsMobileReturnMarchLeft__K8D4T 1.6s linear infinite;
    pointer-events: none;
  }

  /* The top run: out of the return column, across to the first dot's own
     column, where the arrowhead below takes over. Same 18px span and same
     absolute 12px dash period as the bottom run. */
  .moments-section_canvas__e4JQv::before {
    content: "";
    position: absolute;
    left: 9px;
    top: 7px;
    width: 18px;
    height: 2px;
    background-image: linear-gradient(
      to right,
      var(--gold) 0 6px,
      transparent 6px 12px
    );
    background-size: 12px 2px;
    background-repeat: repeat-x;
    animation: moments-section_momentsMobileReturnMarchRight__Wi0cV 1.6s linear infinite;
    pointer-events: none;
  }

  /* The arrowhead: a CSS border triangle, so no stretching can distort it
     (this is why it is not a vertex of any of the runs). It is centred on
     x=26, the dot column, its base at y=9 is exactly where the top run ends,
     and its tip at y=19 is 2px INSIDE the first dot, which spans y=17 to 27.
     Tip and dot are both gold, so the arrow reads as arriving in the node
     rather than stopping beside it. Last in tree order, so it paints over
     the ground-coloured halo the dot casts. */
  .moments-section_canvas__e4JQv::after {
    content: "";
    position: absolute;
    left: 21px;
    top: 9px;
    width: 0;
    height: 0;
    border-left: 5px solid transparent;
    border-right: 5px solid transparent;
    border-top: 10px solid var(--gold);
    pointer-events: none;
  }

  /* THE MARCH, one direction per run, all of it a bonus.
   *
   * Every run travels the way the lap does: out of the last node (the bottom
   * run moves LEFT, its x position falling), up the gutter (the vertical run
   * moves UP, its y position falling), and into the first node (the top run
   * moves RIGHT, its x position rising). One whole 6 + 6 period per cycle in
   * each case, so every loop is seamless, and the same 1.6s linear the
   * desktop rail's return edge uses.
   *
   * Only background-position moves anywhere: it repaints a 2px strip and can
   * reflow nothing. Each run's EXTENT is its element box, not its
   * background-size, which is why a marching position slides the pattern
   * without dragging the run off its corners.
   *
   * These are ordinary infinite CSS animations on ordinary pseudo-elements,
   * so html[data-motion="static"] *::before and *::after stop all three dead
   * through animation-iteration-count: 1 (the duration override alone would
   * only have spun them faster). No component-level prefers-reduced-motion
   * query here either; that is this repo's documented anti-pattern. The
   * spine's layer keeps a fixed position in both keyframes, so the solid
   * column never moves with the dashes beside it. */
  @keyframes moments-section_momentsMobileReturnMarch__WpNkX {
    from {
      background-position: 25px 15px, 9px 0;
    }
    to {
      background-position: 25px 15px, 9px -12px;
    }
  }

  @keyframes moments-section_momentsMobileReturnMarchLeft__K8D4T {
    from {
      background-position: 0 0;
    }
    to {
      background-position: -12px 0;
    }
  }

  @keyframes moments-section_momentsMobileReturnMarchRight__Wi0cV {
    from {
      background-position: 0 0;
    }
    to {
      background-position: 12px 0;
    }
  }

  /* One row per moment: dot on the spine, label, when underneath. */
  .moments-section_tab__Qtil_ {
    position: relative;
    left: auto;
    top: auto;
    width: auto;
    height: auto;
    /* An honest touch target: 12px + 12px of padding around a 20px line is
       already past 44px, and the floor is stated anyway so a shorter label
       cannot drop the row under it. */
    min-height: 44px;
    padding: 12px 0 12px 44px;
    display: block;
    text-align: left;
    border: 0;
    border-radius: 0;
    background: transparent;
    white-space: normal;
    font-size: 15px;
    line-height: 1.35;
    /* Unselected: cream at 78%, which composites to 9.94:1 on the section
       ground. Selected below is the full cream, 15.94:1. */
    color: rgba(245, 240, 234, 0.78);
  }

  /* The node dot ON the spine (26px), replacing the desktop hit expansion:
     these rows meet 44px with real height, so no expansion is needed. The
     halo is the ground colour, so the spine passes behind the dot cleanly.
     Gold on the section ground is 9.49:1. */
  .moments-section_tab__Qtil_::before {
    inset: auto;
    left: 21px;
    top: 17px;
    width: 10px;
    height: 10px;
    border-radius: 999px;
    background: var(--gold);
    box-shadow: 0 0 0 2px var(--light-head);
  }

  /* No capsule to tint on a touch row, so hover brightens the label instead
     of painting a box that a touch device would then leave stuck on. */
  .moments-section_tab__Qtil_:hover {
    background: transparent;
    border-color: transparent;
    color: #f5f0ea;
  }

  /* Selected reads as selected twice over: a cream ring on the dot (the same
     ring the rail draws around the selected node) and a brighter, heavier
     label. Cream on the ground is 15.94:1. */
  .moments-section_tab__Qtil_[aria-selected="true"] {
    color: #f5f0ea;
    font-weight: 500;
  }

  .moments-section_tab__Qtil_[aria-selected="true"]::before {
    box-shadow: 0 0 0 2px var(--light-head), 0 0 0 4px var(--cream);
  }

  /* The when drops out of its absolute placement and simply sits under the
     label, in the same mono gold as the rail (9.49:1). The above/below
     placement rules go inert on their own: top and bottom do not apply to a
     statically positioned box. */
  .moments-section_tabWhen__3MiGT {
    position: static;
    display: block;
    transform: none;
    margin-top: 4px;
    font-size: 10px;
    white-space: normal;
  }
}

/* ── THE ILLUSTRATION'S PICTURE, DECLARED ONLY WHERE IT IS SHOWN ────────────
 *
 * A phone must not download a picture the mobile block hides. That is not
 * true of an <img> inside a display:none subtree, which is fetched anyway,
 * so the asset moved out of the markup and into this block: below 901px the
 * declaration is never applied, so the request is never made. The frame, the
 * dashed gold border and the 540x310 box stay unconditional above.
 *
 * cover reproduces the object-fit: cover the next/image had, and the picture
 * is decoration on an aria-hidden frame, so it carries no text alternative
 * and none is owed. 901px is the exact complement of the 900px mobile block,
 * so the two can never both apply. */
@media (min-width: 901px) {
  .moments-section_illustrationFrame__BWY_k {
    background-image: url("/landing-challenger/long-middle-illustration.webp");
    background-size: cover;
    background-position: center;
    background-repeat: no-repeat;
  }
}

/*
 * Gold disc + SVG triangle. Gold sits on dark imagery at every call site
 * (night hero, session poster, sessions poster, demo poster), which is the
 * only surface gold is allowed on.
 */

.play-badge_badge__GPP9A {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: var(--c-gold);
  color: var(--c-green-deep);
  box-shadow: 0 12px 28px -8px rgba(0, 0, 0, 0.65);
  flex-shrink: 0;
  transition: transform 0.2s cubic-bezier(0.22, 1, 0.36, 1),
    background 0.2s ease;
}

.play-badge_triangle___uP9q {
  display: block;
}

/* Grow on hover of whichever button or link wraps the badge. :where() keeps
   the specificity at zero so a call site can still override. */
:where(button, a):hover > .play-badge_badge__GPP9A,
:where(button, a):hover .play-badge_badge__GPP9A {
  transform: scale(1.06);
  background: #e6c86b;
}

/*
 * Shared primitives for the landing sections. Section modules pull these in
 * with `composes: goldPill from "../landing-shared.module.css";` so the pills,
 * eyebrows, and ambient layers stay identical across sections.
 *
 * Palette: --c-* tokens only (marketing convention). Gold never sits on cream
 * or white surfaces (globals.css rule); the gold pill below is for the dark
 * hero/community surfaces only.
 *
 * Motion convention for the ambient layers (fireflies, glow, tilt): every
 * animated decorative element must look correct in its BASE styles, because
 * html[data-motion="static"] collapses the animation to one 0.01ms run and the
 * element then sits at its base state. Fireflies rest at half opacity, the
 * glow rests mid-intensity, the tilt rests level.
 */

/* ── Layout shells ─────────────────────────────────────────────────────────── */

.landing-shared_inner__4NwU2 {
  max-width: 1080px;
  margin: 0 auto;
  padding-left: 32px;
  padding-right: 32px;
}

.landing-shared_innerNarrow__jjlsu {
  max-width: 960px;
}

.landing-shared_innerWide__7etTT {
  max-width: 1180px;
}

/* Anchor targets land below the fixed nav (the old +44px subnav allowance is
   gone with the subnav itself). */
.landing-shared_anchor__aX2Uf {
  scroll-margin-top: calc(var(--nav-height) + 24px);
}

/* ── Type primitives ───────────────────────────────────────────────────────── */

.landing-shared_eyebrow__kZyHK {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
}

.landing-shared_eyebrowGold__OONAg {
  color: var(--c-gold);
}

.landing-shared_eyebrowOak__hXqlo {
  color: var(--c-wood-oak);
}

/* ── Pills (CTAs) ──────────────────────────────────────────────────────────── */

/* Gold pill: dark surfaces ONLY (7.31:1 on green-deep, 9.89:1 on navy). */
.landing-shared_goldPill__noTZy {
  font-family: var(--font-body);
  font-size: 15px;
  font-weight: 600;
  padding: 15px 30px;
  border-radius: 999px;
  border: 0;
  background: var(--c-gold);
  color: var(--c-green-deep);
  display: inline-flex;
  align-items: center;
  gap: 9px;
  white-space: nowrap;
  cursor: pointer;
  transition: background 0.18s ease, transform 0.18s ease, box-shadow 0.18s ease;
  box-shadow: 0 14px 30px -12px rgba(0, 0, 0, 0.55);
}

.landing-shared_goldPill__noTZy:hover {
  background: #e6c86b;
  transform: translateY(-1px);
}

.landing-shared_goldPill__noTZy:focus-visible {
  outline: 3px solid var(--c-cream);
  outline-offset: 3px;
}

/* Ghost pill on dark imagery. */
.landing-shared_ghostPillDark__532qP {
  font-family: var(--font-body);
  font-size: 14.5px;
  font-weight: 500;
  color: var(--c-text);
  border: 1px solid rgba(251, 248, 242, 0.45);
  background: rgba(11, 18, 25, 0.4);
  padding: 14px 24px;
  border-radius: 999px;
  display: inline-flex;
  align-items: center;
  gap: 9px;
  white-space: nowrap;
  cursor: pointer;
  transition: background 0.18s ease, border-color 0.18s ease;
}

.landing-shared_ghostPillDark__532qP:hover {
  background: rgba(251, 248, 242, 0.14);
  border-color: rgba(251, 248, 242, 0.7);
}

.landing-shared_ghostPillDark__532qP:focus-visible {
  outline: 3px solid var(--c-gold);
  outline-offset: 3px;
}

/* Green pill for light surfaces (gold is banned there). */
.landing-shared_forestPill__Tiv0N {
  font-family: var(--font-body);
  font-size: 16px;
  font-weight: 600;
  padding: 17px 34px;
  border-radius: 999px;
  border: 0;
  background: var(--c-green-dark);
  color: var(--c-cream);
  display: inline-flex;
  align-items: center;
  gap: 9px;
  white-space: nowrap;
  cursor: pointer;
  transition: background 0.18s ease, transform 0.18s ease;
  box-shadow: 0 18px 38px -18px rgba(45, 74, 50, 0.6);
}

.landing-shared_forestPill__Tiv0N:hover {
  background: var(--c-green-deep);
  transform: translateY(-1px);
}

.landing-shared_forestPill__Tiv0N:focus-visible {
  outline: 3px solid var(--c-green-dark);
  outline-offset: 3px;
}

/* ── Ambient layers ────────────────────────────────────────────────────────── */

@keyframes landing-shared_nariLandingDrift1__jWt0w {
  0%, 100% { transform: translate(0, 0); opacity: 0.2; }
  25% { opacity: 0.85; }
  50% { transform: translate(28px, -36px); opacity: 0.45; }
  75% { opacity: 0.9; }
}

@keyframes landing-shared_nariLandingDrift2__R79Cd {
  0%, 100% { transform: translate(0, 0); opacity: 0.3; }
  30% { opacity: 0.9; }
  50% { transform: translate(-32px, -22px); opacity: 0.4; }
  80% { opacity: 0.75; }
}

@keyframes landing-shared_nariLandingDrift3__3ccRK {
  0%, 100% { transform: translate(0, 0); opacity: 0.2; }
  40% { opacity: 0.8; }
  50% { transform: translate(16px, -48px); opacity: 0.5; }
}

@keyframes landing-shared_nariLandingGlow__KXbM3 {
  0%, 100% { opacity: 0.5; }
  50% { opacity: 0.9; }
}

@keyframes landing-shared_nariLandingTilt__pnMLM {
  0%, 100% { transform: rotate(0deg); }
  30% { transform: rotate(-2.2deg); }
  60% { transform: rotate(1.6deg); }
}

.landing-shared_firefly__9FET7 {
  position: absolute;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--c-gold);
  box-shadow: 0 0 10px 2px rgba(221, 184, 74, 0.5);
  pointer-events: none;
  opacity: 0.5; /* base state: visible but calm when animations are frozen */
}

.landing-shared_fireflyA___n0as {
  animation: landing-shared_nariLandingDrift1__jWt0w 11s ease-in-out infinite;
}

.landing-shared_fireflyB__5_c1l {
  width: 4px;
  height: 4px;
  animation: landing-shared_nariLandingDrift2__R79Cd 14s ease-in-out 2s infinite;
}

.landing-shared_fireflyC__rmv_l {
  width: 3px;
  height: 3px;
  animation: landing-shared_nariLandingDrift3__3ccRK 17s ease-in-out 5s infinite;
}

.landing-shared_fireflyD__bRm4_ {
  animation: landing-shared_nariLandingDrift1__jWt0w 13s ease-in-out 7s infinite;
}

.landing-shared_glow__J9BpH {
  position: absolute;
  pointer-events: none;
  background: radial-gradient(ellipse at center, rgba(221, 184, 74, 0.16), transparent 62%);
  opacity: 0.7; /* base state: mid-intensity when frozen */
  animation: landing-shared_nariLandingGlow__KXbM3 9s ease-in-out infinite;
}

.landing-shared_tilt__AQw9o {
  animation: landing-shared_nariLandingTilt__pnMLM 7s ease-in-out infinite;
  transform-origin: 50% 88%; /* base transform: level (resting pose) */
}

/*
 * ENGINE section: light gradient surface. Left, the "most resume builders"
 * treadmill (struck-through steps + the red loop line). Right, the demo
 * recording inside the shared BrowserMock frame, with the four-step process
 * bar and the pricing CTA underneath.
 *
 * Palette: --c-* tokens only; the rgba() hairlines and scrims are alpha
 * composites from the design and stay literal (landing convention). Gold
 * appears only on the play circle, which sits over the demo poster imagery,
 * never directly on the cream surface.
 */

.engine-section_section__B8xQo {
  position: relative;
  overflow: hidden;
  background: linear-gradient(
    180deg,
    #fff 0%,
    var(--c-cream-light) 46%,
    var(--c-cream) 100%
  );
  border-top: 1px solid rgba(85, 111, 36, 0.12);
  padding: 56px 0 60px;
}

/* Gold radial corner accent. The shared glow rests at mid-intensity when
   animations are frozen, so the static state stays presentable. */
.engine-section_cornerGlow__htF7_ {
  top: -120px;
  right: -80px;
  width: 520px;
  height: 420px;
}

/* Header */

.engine-section_header__5M_zW {
  max-width: 860px;
  margin-bottom: 42px;
  text-align: center;
}

.engine-section_eyebrow__eUeZo {
  margin-bottom: 20px;
}

.engine-section_heading__BOfmu {
  font-family: var(--font-heading);
  font-size: clamp(29px, 6vw, 36px);
  line-height: 1.18;
  font-weight: 500;
  letter-spacing: -0.02em;
  color: var(--c-light-head);
  margin-bottom: 14px;
}

.engine-section_headingItalic__AOlfg {
  font-style: italic;
}

.engine-section_subline__r7GnD {
  font-size: 15px;
  color: var(--c-light-mute);
  max-width: 540px;
  margin: 0 auto;
  text-wrap: pretty;
}

/* Two-column grid */

.engine-section_grid___0QJ7 {
  /* Keep 1060: job-search-card.module.css .wrap uses the same 1060/32, so the
     two halves of this section share one left and right edge. Moving one
     without the other visibly misaligns the dark card below. */
  max-width: 1060px;
  position: relative;
  display: grid;
  /* Deliberately NOT the repeat(auto-fit, minmax(...)) idiom the other landing
     sections use. These columns are not peers: the left one is six short
     struck lines, the right one is a 16:9 product recording whose legibility
     is the point of the section. Equal tracks capped the player at 470x264 on
     a 1440 desktop, SMALLER than the same player got on a 720px tablet. This
     split spends the band the before/after illustration used to occupy on the
     thing people actually watch.
     Explicit tracks mean the collapse is now this file's job: the media query
     below is load-bearing, not cosmetic. Without it a phone gets two ~130px
     columns. */
  grid-template-columns: minmax(0, 0.82fr) minmax(0, 1.18fr);
  gap: 48px;
  align-items: center;
}

/* Collapse to one column well above the old 756px fold.
   The demo column is (min(vw, 1060) - 64 - 48) * 0.59, so at 901px it is only
   ~465px and both columns are cramped: the treadmill list starts wrapping and
   the recording is no larger than it was before the reweight. A single
   full-width column hands the demo the whole 704px instead, which is the
   point of the change.
   Separately, and further down: .processCell is nowrap across four fixed
   tracks and needs about 332px, which the column stops providing around a
   677px viewport. That is below this breakpoint, so the collapse keeps the
   bar safe, but it is NOT the reason for choosing 900. Note the bar fails by
   overflowing, and .section is overflow:hidden, so it clips silently rather
   than showing a scrollbar. */
@media (max-width: 900px) {
  .engine-section_grid___0QJ7 {
    grid-template-columns: minmax(0, 1fr);
    gap: 40px;
  }
}

/* Left: the treadmill */

.engine-section_oldWayLabel__rQvfy {
  font-family: var(--font-mono);
  font-size: 9px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--c-light-mute);
  margin-bottom: 18px;
}

.engine-section_oldWayList__msjmI {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 7px;
  margin: 0 0 14px;
  padding: 0;
}

.engine-section_oldWayFirst__iqjmx {
  font-size: 13.5px;
  color: var(--c-light-body);
}

.engine-section_oldWayNote__WrDiv {
  font-family: var(--font-mono);
  font-size: 9px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--c-light-mute);
}

.engine-section_struck__aSHiJ {
  font-size: 13.5px;
  color: var(--c-light-mute);
  text-decoration: line-through;
  text-decoration-color: rgba(160, 40, 40, 0.45);
}

.engine-section_loopRow__1IOEw {
  display: flex;
  align-items: center;
  gap: 10px;
  padding-top: 16px;
  margin-bottom: 40px;
  border-top: 1px solid rgba(160, 40, 40, 0.18);
}

.engine-section_loopGlyph__ZJMlK {
  font-size: 15px;
  color: var(--c-red);
}

.engine-section_loopLine__z4w4X {
  font-family: var(--font-heading);
  font-style: italic;
  font-size: 14.5px;
  line-height: 1.4;
  color: var(--c-red);
  /* Short block: balance the line lengths. */
  text-wrap: balance;
}

.engine-section_payoff__TWe2y {
  font-family: var(--font-heading);
  font-size: 20px;
  line-height: 1.4;
  color: var(--c-light-head);
  /* Short block: balance the line lengths. */
  text-wrap: balance;
}

.engine-section_payoffItalic___Ttxf {
  font-style: italic;
}

/* Right: the demo */

.engine-section_demoCol__PElfP {
  position: relative;
}


/* max-width: none overrides BrowserMock's own 560px cap so the frame fills
   whatever the demo column gives it. Load-bearing since the grid was reweighted
   to 1.18fr: the column is ~559px at 1440, so removing this would re-cap the
   mock at almost exactly the right size and then silently stop working the
   moment anyone widens the section. */
.engine-section_browser__pdYp2 {
  max-width: none;
  border-radius: 20px;
  box-shadow: 0 30px 60px -34px rgba(27, 15, 51, 0.3);
}

/* BrowserMock's body pads its content (18px sides/top, 22px bottom); the
   recording should sit flush against the chrome like the design, so this
   wrapper bleeds back out. The bottom margin stays -22px because the caption
   strip below it re-bleeds itself. Keep in sync with
   browser-mock.module.css .body. */
.engine-section_playerBleed__sMoV_ {
  margin: -18px -18px -22px;
}


.engine-section_player__Lrcri,
.engine-section_posterOnly__hUTk6 {
  position: relative;
  aspect-ratio: 16 / 9;
  background: var(--c-cream);
  overflow: hidden;
}

.engine-section_posterImg__wYGDA {
  object-fit: cover;
}

/* Idle: one full-bleed play button over the poster. */

.engine-section_playOverlay__WsGUh {
  position: absolute;
  inset: 0;
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: center;
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
}

.engine-section_playOverlay__WsGUh:focus-visible {
  outline: 3px solid var(--c-green-dark);
  outline-offset: -3px;
}

/* PlayBadge owns the disc; this only adds the keyboard-focus grow, since the
   badge's own rule covers hover but not :focus-visible on the wrapper. */
.engine-section_playOverlay__WsGUh:focus-visible .engine-section_playCircle__Gyxmy {
  transform: scale(1.08);
}

/* Playing */

.engine-section_video__0cxCu {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  background: var(--c-green-deep);
}

.engine-section_backBtn__eQjzP {
  position: absolute;
  top: 10px;
  right: 10px;
  z-index: 3;
  font-family: var(--font-mono);
  font-size: 9.5px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--c-cream);
  background: rgba(27, 15, 51, 0.72);
  border: 1px solid rgba(245, 242, 235, 0.35);
  border-radius: 999px;
  padding: 6px 12px;
  transition: background 0.18s ease;
}

/* The pill is visually small per the design; the pseudo-element pads its hit
   target out to the 44px minimum without changing the rendering. */
.engine-section_backBtn__eQjzP::after {
  content: "";
  position: absolute;
  inset: -11px;
  border-radius: 999px;
}

.engine-section_backBtn__eQjzP:hover {
  background: rgba(27, 15, 51, 0.9);
}

.engine-section_backBtn__eQjzP:focus-visible {
  outline: 3px solid var(--c-gold);
  outline-offset: 3px;
}

/* Error */

.engine-section_errorPane__S04eC {
  position: absolute;
  inset: 0;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 16px;
  padding: 0 28px;
  background: var(--c-green-deep);
  text-align: center;
}

.engine-section_errorText__XXW2C {
  font-family: var(--font-mono);
  font-size: 11px;
  line-height: 1.7;
  letter-spacing: 0.06em;
  color: rgba(245, 242, 235, 0.86);
}

.engine-section_retryBtn___APUh {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--c-cream);
  background: rgba(245, 242, 235, 0.08);
  border: 1px solid rgba(245, 242, 235, 0.35);
  border-radius: 999px;
  min-height: 44px;
  padding: 0 26px;
  display: inline-flex;
  align-items: center;
  transition: background 0.18s ease, border-color 0.18s ease;
}

.engine-section_retryBtn___APUh:hover {
  background: rgba(245, 242, 235, 0.16);
  border-color: rgba(245, 242, 235, 0.6);
}

.engine-section_retryBtn___APUh:focus-visible {
  outline: 3px solid var(--c-gold);
  outline-offset: 3px;
}

/* Below the frame */

/* The frame's own footer strip (design: hairline above, faint tinted band),
   living INSIDE BrowserMock's padded body: bleed to the frame edges and pull
   up to meet the player, which bled the body's bottom padding away. */
.engine-section_caption__p2Iqh {
  font-family: var(--font-mono);
  font-size: 9.5px;
  letter-spacing: 0.08em;
  color: var(--c-light-mute);
  text-align: center;
  margin: 0 -18px -22px;
  padding: 9px 14px;
  border-top: 1px solid rgba(85, 111, 36, 0.14);
  background: #faf8f4;
  /* Short block: balance the line lengths. */
  text-wrap: balance;
}

.engine-section_processBar__30qvw {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  margin-top: 20px;
  border-top: 1px solid rgba(85, 111, 36, 0.16);
  border-bottom: 1px solid rgba(85, 111, 36, 0.16);
}

.engine-section_processCell__GIvWG {
  font-family: var(--font-mono);
  font-size: 9.5px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--c-light-body);
  text-align: center;
  white-space: nowrap;
  padding: 10px 4px;
}

.engine-section_processCell__GIvWG + .engine-section_processCell__GIvWG {
  border-left: 1px solid rgba(85, 111, 36, 0.16);
}

.engine-section_processCellOptional__2z_7Y {
  color: var(--c-light-mute);
}

.engine-section_footRow__UDwfk {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  margin-top: 16px;
}

.engine-section_footnote__uxRV8 {
  font-family: var(--font-heading);
  font-style: italic;
  font-size: 15px;
  line-height: 1.4;
  color: var(--c-green-dark);
  /* Short block: balance the line lengths. */
  text-wrap: balance;
}

.engine-section_cta__0NJ_W {
  font-size: 14px;
  font-weight: 500;
  color: var(--c-wood-oak);
  white-space: nowrap;
  /* Padding grows the tap target to the 44px minimum; the negative margin
     keeps the row's visual rhythm unchanged. */
  padding: 13px 2px;
  margin: -13px -2px;
}

.engine-section_cta__0NJ_W:hover {
  text-decoration: underline;
}

.engine-section_cta__0NJ_W:focus-visible {
  outline: 3px solid var(--c-green-dark);
  outline-offset: 2px;
  border-radius: 4px;
}

